高效替换VCF文件染色体名
方法一awk+sed(有点慢)
你可以使用Linux命令行工具来完成这个任务。假设你有一个VCF文件 input.vcf
,以及一个包含旧染色体名和新染色体名对应关系的文件 chromosome_mapping.txt
,文件内容如下:
old_chr1 new_chr1
old_chr2 new_chr2
...
你可以使用 awk
和 sed
工具来实现这个替换。以下是具体步骤:
-
准备映射文件:确保
chromosome_mapping.txt
文件中的每一行都是旧染色体名和新染色体名的对应关系,用空格或制表符分隔。 -
使用
awk
和sed
进行替换:
# 创建一个临时文件来存储替换后的内容
temp_file=$(mktemp)
# 使用 awk 读取映射文件并生成 sed 替换命令
sed_commands=$(awk '{print "s/^" $1 "\t/" $2 "\t/;"}' chromosome_mapping.txt)
# 使用 sed 执行替换并将结果保存到临时文件中
sed "$sed_commands" input.vcf > "$temp_file"
# 将临时文件移动回原始文件
mv "$temp_file" input.vcf
### 解释:
- `awk '{print "s/^" $1 "\t/" $2 "\t/;"}' chromosome_mapping.txt`:生成 `sed` 替换命令,将旧染色体名替换为新染色体名。`^` 确保只匹配行首的染色体名。
- `sed "$sed_commands" input.vcf`:执行生成的 `sed` 替换命令,将替换后的内容保存到临时文件中。
- `mv "$temp_file" input.vcf`:将临时文件移动回原始文件,完成替换。
### 注意事项:
- 如果VCF文件中有注释行或其他不以染色体名开头的行,这些行将不会被修改。
- 确保 `chromosome_mapping.txt` 文件中的旧染色体名和新染色体名之间用空格或制表符分隔。
### 示例:
假设 `chromosome_mapping.txt` 内容如下:
chr1 1
chr2 2
`input.vcf` 内容如下:
##fileformat=VCFv4.2
##reference=hg38
chr1 100 . A T . . .
chr2 200 . G C . . .
执行上述命令后,`input.vcf` 将变为:
##fileformat=VCFv4.2
##reference=hg38
1 100 . A T . . .
2 200 . G C . . .
方法二awk(快一点)(满足一二列要求即可替换)
## 1
awk 'BEGIN { while (getline < "map.txt") map[$1]=$2 }
/^##contig=<ID=/ {
if (match($0, /ID=[^,]+/)) {
id = substr($0, RSTART+3, RLENGTH-3);
if (id in map) sub(/ID=[^,]+/, "ID=" map[id])
} print; next
}
/^#/ { print; next }
$1 in map { $1 = map[$1] } 1' input.vcf > output.vcf
解释:
1. **读取映射文件**:`BEGIN`块将`map.txt`读入内存,构建哈希表`map`(旧名称为键,新名称为值)。
2. **处理头信息**:
- 对`##contig=<ID=...>`格式的行,提取旧ID并替换为新ID(如果存在映射)。
3. **跳过注释行**:其他以`#`开头的行(如`#CHROM`)直接打印。
4. **替换数据行**:对非注释行,若第1列(染色体名)在映射表中存在,则替换为新名称。
## 2 输入文件以空格分隔时,去掉下面FS字段
awk 'BEGIN {
# 设置输入和输出字段分隔符为制表符
FS = "\t"
OFS = "\t"
# 加载映射关系到数组
while (getline < "chromosome_mapping.txt") {
map[$1] = $2
}
}
{
# 处理 VCF 文件
if ($0 ~ /^#/) {
# 保留注释行(直接打印原内容)
print $0
} else {
# 替换染色体名称
if ($1 in map) {
$1 = map[$1]
}
# 使用OFS(制表符)输出各字段
print
}
}' input.vcf > output_renamed.vcf
awk 'BEGIN { FS="\t"; OFS="\t"; while (getline < "chromosome_mapping.txt") map[$1]=$2 } { if ($0 ~ /^#/) print $0; else { if ($1 in map) $1=map[$1]; print } }' input.vcf > output_renamed.vcf
**关键修改说明:**
1. **设置分隔符**:在`BEGIN`块中设置`FS`(输入字段分隔符)和`OFS`(输出字段分隔符)为制表符`\t`,确保输入正确解析且输出以制表符分隔。
2. **保留注释行原样**:注释行直接使用`print $0`输出原始内容,避免因字段操作导致格式变化。
3. **替换后自动制表符分隔**:非注释行替换染色体名称后,使用`print`(默认输出`$0`,各字段由`OFS`分隔)确保制表符分隔。
方法3 bcftools(推荐)(只适用于vcf文件)
# 1. 将映射文件转换为 bcftools 接受的格式(旧ID->新ID)
awk '{print $1 "\t" $2}' chromosome_mapping.txt > chrom_map.txt
# 2. 使用 bcftools 重命名染色体
bcftools annotate --rename-chrs chrom_map.txt input.vcf -o output_renamed.vcf