基于前两列合并多VCF文件并补./.:.缺失值的命令或Perl脚本
多VCF按染色体-位置主键整合实现方案
问题根因
之前使用paste是按物理行拼接文件内容,未以染色体+位置作为唯一主键匹配,且无缺失值填充逻辑,因此会出现位点错位、错配的问题。
核心规则
- 唯一主键:每行前两列(染色体、物理位置)
- 对齐方式:收集所有输入文件的所有位点主键,按VCF标准(染色体升序+位置升序)排序后逐个匹配
- 缺失填充:某位点未出现在对应文件时,该文件对应的样本值位置填充
./.:.
方案1:Awk 快速处理(适配你的示例输入)
你的示例输入文件每行结构为:[染色体] [位置] [FORMAT列] [样本值列],以下awk代码直接复用该结构,无需修改即可处理:
# 保存为 merge_vcf.awk BEGIN { FS = OFS = " "; # 若文件为制表符分隔,改为 FS=OFS="\t" missing_val = "./.:."; file_count = ARGC - 1; # 统计输入的VCF样本文件数 } { # 生成唯一主键:前两列拼接 site_key = $1 "|" $2; # 当前处理的文件索引(从1开始,对应ARGV[1]为第一个样本文件) current_file_idx = ARGIND; # 存储当前文件的该位点的样本值(取每行最后一列) sample_val[current_file_idx, site_key] = $NF; # 【可选修改】若需保留除前两列外的所有内容,替换上面一行代码为: # sample_val[current_file_idx, site_key] = substr($0, index($0, $3)); # 存储FORMAT列(仅取第一个文件的FORMAT,假设所有文件FORMAT一致) if (current_file_idx == 1) format_str[site_key] = $3; # 记录所有出现过的位点主键 all_site_keys[site_key] = 1; } END { # 按染色体、位置排序主键 n = asorti(all_site_keys, sorted_keys, "@ind_str_asc"); # 遍历每个排序后的位点,输出主键+FORMAT+所有样本值 for (i = 1; i <= n; i++) { key = sorted_keys[i]; split(key, parts, "|"); printf "%s %s %s", parts[1], parts[2], format_str[key]; # 逐个样本文件匹配样本值,缺失则填充默认值 for (f = 1; f <= file_count; f++) { val = ( (f, key) in sample_val ) ? sample_val[f, key] : missing_val; printf " %s", val; } printf "\n"; } }
执行命令
awk -f merge_vcf.awk file1 file2 file3 > merged_output.vcf
针对你的示例的输出结果
1 152 GT:DP 1/1:5 0/1:5 ./.:. 1 155 GT:DP ./.:. 0/1:6 1/1:5 1 162 GT:DP 0/1:4 ./.:. 0/1:4
完全匹配需求:按位点排序,缺失值自动填充,无错位
方案2:Perl 脚本(适配大规模VCF处理)
若后续处理的VCF文件较大、列数较多(含完整VCF的ID/REF/ALT等列),使用以下Perl脚本更稳定,支持自定义主键列、缺失值:
#!/usr/bin/perl use strict; use warnings; # 配置参数 my $MISSING_VAL = "./.:."; my @INPUT_FILES = @ARGV; # 命令行传入的所有VCF文件 my $FILE_COUNT = scalar @INPUT_FILES; # 数据结构: # $site_data{主键}{文件索引} = 该行除主键外的所有列内容 # $all_sites{主键} = 1 (记录所有出现过的位点) my (%site_data, %all_sites, $format_col); # 遍历所有输入文件 for my $file_idx (0 .. $#INPUT_FILES) { open my $fh, "<", $INPUT_FILES[$file_idx] or die "无法打开文件 $INPUT_FILES[$file_idx]: $!"; while (<$fh>) { chomp; next if /^#/; # 跳过VCF头部行 my @cols = split /\s+/; # 生成主键:前两列拼接(可根据需求修改为更多列) my $key = join("|", @cols[0,1]); # 存储除前两列外的所有内容(若仅需样本值,可改为join("|", $cols[-1])) $site_data{$key}{$file_idx} = join(" ", @cols[2 .. $#cols]); # 记录FORMAT列(取第一个文件的FORMAT,假设所有文件一致) if ($file_idx == 0) { $format_col = $cols[2]; } $all_sites{$key} = 1; } close $fh; } # 按染色体、位置排序所有位点主键 my @sorted_sites = sort { my ($chr_a, $pos_a) = split /\|/, $a; my ($chr_b, $pos_b) = split /\|/, $b; $chr_a cmp $chr_b || $pos_a <=> $pos_b } keys %all_sites; # 输出整合后的文件 open my $out_fh, ">", "merged_output.vcf" or die "无法创建输出文件: $!"; # 输出表头(若需要) print $out_fh "#CHROM POS FORMAT SAMPLE1 SAMPLE2 SAMPLE3\n"; # 遍历每个排序后的位点 foreach my $key (@sorted_sites) { my ($chr, $pos) = split /\|/, $key; print $out_fh "$chr $pos $format_col"; # 逐个文件匹配值,缺失则填充 for my $f (0 .. $#INPUT_FILES) { my $val = exists $site_data{$key}{$f} ? $site_data{$key}{$f} : $MISSING_VAL; print $out_fh " $val"; } print $out_fh "\n"; } close $out_fh;
执行命令
# 赋予脚本执行权限 chmod +x merge_vcf.pl # 运行脚本 ./merge_vcf.pl file1 file2 file3
内容的提问来源于stack exchange,提问作者anitha
相关产品推荐
相关产品推荐

