使用bcftools合并多批次VCF:merge与concat的实战选择

做多批次VCF合并,bcftools merge和bcftools concat到底该用哪个?

这个问题,我当年刚接触生信时也晕过好一阵子。两个命令都能把多个VCF文件合并成一个,但结果却天差地别。选错了,轻则数据丢失,重则引入假阳性变异,后面所有分析白做。

说白了,merge是按位点合并,concat是按区域拼接。理解了这个本质区别,你就知道每个场景该用什么工具了。

merge与concat的核心区别

维度 bcftools merge bcftools concat
合并逻辑 按坐标位置对齐样本 按染色体/区域首尾拼接
输入要求 同一区间、不同样本的VCF 不同区间、相同样本的VCF
输出样本数 增加(合并所有样本) 不变(样本数=N)
位点数目 去重后合并 直接追加,不会去重
典型场景 多批次WES/WGS样本聚合 分染色体VCF拼接成全基因组
缺失数据 填充 ./. 不产生缺失

嗯,这里的核心就是:样本维度还是区域维度。你自己想想看,如果你的数据是同一批样本在不同时间点做的测序,那显然要用merge;如果你只是把不同染色体的结果拼在一起,那concat才是正解。

我个人的经验是:先用bcftools stats + bcftools isec摸清数据重叠情况,再决定用merge还是concat。这一步能省去很多debug时间。

实战对比:两种合并方式

场景一:同一区域的多个样本VCF,用merge

假设你有3个样本的gVCF,都在chr1:1-100000区间,想合并成一个多样本VCF:

# 先用bgzip压缩并建立索引
bgzip -c sample1.vcf > sample1.vcf.gz
bgzip -c sample2.vcf > sample2.vcf.gz
bgzip -c sample3.vcf > sample3.vcf.gz
tabix -p vcf sample1.vcf.gz
tabix -p vcf sample2.vcf.gz
tabix -p vcf sample3.vcf.gz

# 合并三个样本
bcftools merge -O z -o merged.vcf.gz sample1.vcf.gz sample2.vcf.gz sample3.vcf.gz

# 查看样本数变化
bcftools query -l merged.vcf.gz

输出结果:样本列表会包含sample1、sample2、sample3三个。如果某样本在某个位点没有检出,merge会填充./.来表示缺失。

注意:如果三个样本的VCF中位点坐标不完全一致,merge会做交集或并集处理。默认是做交集(所有样本都有记录的位点),加上--force-samples可以改为并集。这个细节我栽过跟头——本来以为所有样本都call到了某个关键突变,结果merge后发现是并集模式,差点漏掉一个重要变异。

场景二:不同染色体的VCF,用concat

假设你做完call变异后,得到了每个染色体的独立VCF:

# 按染色体顺序拼接
bcftools concat -O z -o whole_genome.vcf.gz chr1.vcf.gz chr2.vcf.gz chr3.vcf.gz

# 也可以用通配符
bcftools concat -O z -o whole_genome.vcf.gz chr{1..22,X,Y}.vcf.gz

这里的逻辑很简单:只是把VCF文件按坐标首尾连起来。合并后的总样本数不变,位点数是各染色体位点数的简单加和。concat不检查样本是否一致,它假定每个VCF文件的样本列表完全相同。

如何选择?我的实战决策流程

让我用一张流程图把决策逻辑说清楚:

bcftools merge vs concat 决策流程 多批次VCF输入 样本是否重叠? (相同区间?不同样本?) 是 否 推荐merge 按位点对齐样品 推荐concat 按区域首尾拼接 潜在风险 缺失填充 ./. 位点不一致问题 潜在风险 样本列表必须一致 染色体顺序重要 合并后VCF 多样本/全基因组

这个图其实已经把逻辑捋得很清楚了。我再补充几个实际项目中的经验:

参数详解与避坑指南

bcftools merge 关键参数

# 我最常用的合并命令
bcftools merge \
  --merge all \              # 合并策略:all/join/both/snps/indels
  --info-rules DP:sum,GQ:avg \  # INFO字段合并规则
  --format-rules GT:avg \       # FORMAT字段合并规则
  -O z \                        # 输出压缩VCF
  -o merged.vcf.gz \            # 输出文件
  sample1.vcf.gz sample2.vcf.gz sample3.vcf.gz
参数 说明 我的建议
--merge 合并策略:all/join/both/snps/indels 一般用all,保留所有变异类型
--info-rules 定义INFO字段如何合并 DP用sum,AF用avg,很常用
--format-rules 定义FORMAT字段(如GT、GQ)的合并规则 GT慎用avg,会搞乱基因型
--force-samples 强制包含所有样本的位点 需要并集时加上
--no-index 跳过索引检查 不推荐,除非你确定头文件一致

bcftools concat 关键参数

# 我最常用的拼接命令
bcftools concat \
  --allow-overlaps \          # 允许重叠区域
  -O z \                      # 输出压缩VCF
  -o whole_genome.vcf.gz \    # 输出文件
  chr1.vcf.gz chr2.vcf.gz chr3.vcf.gz
参数 说明 我的建议
--allow-overlaps 允许染色体间有重叠 加这个参数更安全
--rm-dups 去除重复的位点 如果可能有重叠就加上
--no-version 不添加版本信息 生产环境建议不要加

实战中容易踩的坑

坑1:样本顺序对不上
concat要求所有输入VCF的样本列顺序完全一致,否则会报错。我曾经在一个项目中,因为某个染色体的VCF样本顺序被不小心改过,concat死活跑不过去。排查了半天才发现。
解决:使用bcftools reheader -s samples.txt统一样本顺序。
坑2:merge去重过度
merge默认会对相同坐标的位点做去重合并。如果你本来就想保留不同批次call到的同一变异,要把--merge设为both或all。
小技巧:先检查再合并
我个人的工作流是:
1. 先用bcftools stats分别统计每个VCF
2. 再用bcftools isec看区间重叠情况
3. 最后才决定用merge还是concat
这套流程能挡住90%的合并错误。

总结:一句话记住

merge是"竖着拼"——增加样本数,按位点对齐

concat是"横着拼"——增加区域范围,保持样本数不变

嗯,你只要记住了这个本质区别,以后在任何场景下都不会选错工具。至于参数细节,用的时候查一下文档就好。