使用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 关键参数
# 我最常用的合并命令
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死活跑不过去。排查了半天才发现。
解决:使用
concat要求所有输入VCF的样本列顺序完全一致,否则会报错。我曾经在一个项目中,因为某个染色体的VCF样本顺序被不小心改过,concat死活跑不过去。排查了半天才发现。
解决:使用
bcftools reheader -s samples.txt统一样本顺序。
坑2:merge去重过度
merge默认会对相同坐标的位点做去重合并。如果你本来就想保留不同批次call到的同一变异,要把
merge默认会对相同坐标的位点做去重合并。如果你本来就想保留不同批次call到的同一变异,要把
--merge设为both或all。
小技巧:先检查再合并
我个人的工作流是:
1. 先用
2. 再用
3. 最后才决定用merge还是concat
这套流程能挡住90%的合并错误。
我个人的工作流是:
1. 先用
bcftools stats分别统计每个VCF2. 再用
bcftools isec看区间重叠情况3. 最后才决定用merge还是concat
这套流程能挡住90%的合并错误。
总结:一句话记住
merge是"竖着拼"——增加样本数,按位点对齐
concat是"横着拼"——增加区域范围,保持样本数不变
嗯,你只要记住了这个本质区别,以后在任何场景下都不会选错工具。至于参数细节,用的时候查一下文档就好。