You need to enable JavaScript to run this app. 基于前两列合并多VCF文件并补./.:.缺失值的命令或Perl脚本
优惠活动
大模型
产品
解决方案
定价
更多

基于前两列合并多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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.05 22:27:03