4. bcftools 常用校验命令:stats、filter、query

聊到 VCF 校验,bcftools 绝对是我每天都要打交道的工具。它不光是处理工具,更是咱们质检的“照妖镜”。今天我就把压箱底的三板斧——stats、filter、query——掰开揉碎了讲给你听。相信我,用好它们,绝大多数质控问题都能一眼看穿。

4.1 先上硬菜:bcftools stats —— 全局态势感知

我个人习惯,拿到一个 VCF 文件,第一件事不是看具体位点,而是跑一遍 bcftools stats。这就像体检时的血常规报告,告诉你整体质量是优是劣。

基本命令很简单:

bcftools stats input.vcf.gz > stats.txt

这个输出文件可了不得,里面包含了十几种统计指标。我重点盯下面这几个:

统计项目意义我的关注点
number of SNPsSNP 总数跟预期目标区域大小对比,差异过大就是异常
number of indelsIndel 总数Indel 占比过高,暗示比对或组装有问题
number of multiallelic sites多等位基因位点数我见过测序深度不均时,这个数会飙升
Ts/Tv ratio转换/颠换比全基因组大概 2.0-2.1,外显子组更高
number of samples样本数跟预期对不上?可能是样本合并时出了岔子
number of records总记录数空位点?重复行?这里会露馅
小技巧: 我会把 stats 结果用 plot-vcfstats 直接画成图。图像比数字更直观,一眼就能看出哪个染色体变异率异常。

举个例子,有一次我处理一份肿瘤配对样本。stats 跑完发现 Ts/Tv 只有 1.5。我当时就警觉了——这肯定不对。后来仔细查,原来是测序数据里混入了大量接头序列,导致虚假变异。你看,一个数就揪出了上游的大问题。

4.2 精准打击:bcftools filter —— 按规则有选择地清除

Stats 告诉你哪有问题,那 filter 就是帮你动手解决问题的。它最大的优势是速度极快,不需要解压整个文件,直接流式处理。

基础语法我习惯这么写:

bcftools filter -e 'QUAL < 20 || DP < 10' input.vcf.gz -o filtered.vcf.gz

注意那个 -e 参数,后面跟的是“剔除条件”。意思就是:满足这些条件的记录,删掉。-i 则是“保留条件”,刚好相反。

4.2.1 常用过滤表达式

我整理了几条在实际项目中绕不开的规则:

  • 基于测序深度: DP < 10 || DP > 1000 —— 深度太低是随机噪音,深度太高可能是重复区域或拷贝数异常
  • 基于基因型质量: GQ < 20 —— 基因型分型不可靠的位点,果断扔掉
  • 基于等位基因平衡: AB < 0.2 || AB > 0.8 —— 杂合位点等位基因比例严重失衡,很可能是假阳性
  • 基于缺失率: F_MISSING > 0.1 —— 缺失率超过 10% 的位点,统计效力会大打折扣
警告: 千万不要一个条件从头用到尾。我个人会把过滤分成“硬过滤”和“软过滤”。硬过滤用 bcftools filter 做机械剔除,软过滤只标记不删除,给后续分析留条后路。

4.2.2 用 filter 做标记(Soft Filter)

有时候我不想直接删,而是先标记出来看看效果:

bcftools filter -s "LowQual" -e 'QUAL < 20 || DP < 10' input.vcf.gz -o soft_filtered.vcf.gz

加个 -s 参数,会把不满足条件的位点在 FILTER 列写上 “LowQual”。这样下游分析可以选择忽略或者降低权重。

4.3 庖丁解牛:bcftools query —— 字段提取与定制输出

你想想看,有时候我们不想看整个 VCF,只想看看某个样本的基因型,或者某个区域的深度信息。这时候 query 就派上用场了。它就像一个瑞士军刀,能把 VCF 里任意字段精准掏出来。

最常用的几个场景:

# 提取所有样本的 GT 和 DP
bcftools query -f '%CHROM\t%POS\t%REF\t%ALT[\t%GT\t%DP]\n' input.vcf.gz

# 只输出 PASS 通过的位点
bcftools query -f '%CHROM\t%POS\t%REF\t%ALT[\t%GT]\n' -i 'FILTER="PASS"' input.vcf.gz

# 输出特定格式的基因型矩阵
bcftools query -f '%CHROM\_%POS[\t%GT]\n' -o genotype_matrix.txt input.vcf.gz

这里 -f 后面跟的格式化字符串是关键。我刚开始学的时候老写错,后来总结了个规律:

  • %CHROM、%POS 这些是固定字段,直接写
  • [ ] 方括号内的东西,会对每个样本逐一遍历
  • \t 是制表符,\n 是换行
经验之谈: 用 query 别忘了加 -o 重定向到文件。我曾经直接在终端输出一个百万行级别的 VCF,屏幕刷了十分钟,最后 Ctrl+C 也救不回来,只能干瞪眼。

4.4 组合拳:stats + filter + query 一体化校验

真正的校验流程,从来不是单个命令跑完就算。我一般分三步走:

  1. 第一步:stats 全局扫描 —— 了解 VCF 的整体健康度
  2. 第二步:filter 精准去噪 —— 根据第一步发现的异常,定制过滤规则
  3. 第三步:query 抽样复核 —— 对过滤后的结果,提取关键字段做人工核查
VCF 校验三步走流程 VCF 校验的三步组合拳 原始 VCF 文件 Step 1: bcftools stats 全局统计与质量报告 Step 2: bcftools filter 按规则硬/软过滤 Step 3: bcftools query 字段提取与抽样复核 校验通过的干净 VCF 注意:三步并非严格串行,stats 发现问题后可以回到 filter 调整规则,反复迭代直到质量达标。

为什么一定要按这个顺序?

因为 stats 能告诉你“哪里疼”,filter 根据疼痛点去“下药”,而 query 负责“复查疗效”。我见过很多人一上来就用 filter 把所有位点过滤一遍,结果把真阳性也误杀了。你想想看,先看看整体分布再做决定,是不是稳妥得多?

4.5 避坑指南与实用建议

最后,我分享几个实战中的小坑,都是真金白银换来的教训。

  • stats 输出文件切记加后缀 .txt —— 我试过一次没加,结果被后续脚本错误解析,浪费了俩小时。
  • filter 条件里用双引号还是单引号? — 我建议统一用单引号 ' '。双引号在 shell 里会和变量展开冲突,尤其是在循环脚本中。
  • query 输出大文件时担心内存吗? —— 不用怕,bcftools 的设计就是流式读写,不占内存。但要注意磁盘空间,我见过有人 query 出几百 GB 的文本文件。
  • 参数太复杂记不住? —— 把常用过滤模板写到一个配置文件里,每次 source 一下。我自己就存了个 vcf_filter_rules.sh,里面全是写好的 bcftools filter -e 命令。
踩坑复盘: 我曾经在一次大规模 GWAS 项目中,忘记在 stats 里加上 -s 指定样本,结果所有统计都基于全部样本计算。后续分析里样本分群效果特别差,查了两天才发现是 stats 用了默认的样本集,把病例和对照混在一起统计了。从那以后,每次跑 stats 前我都会确认样本名单。

嗯,以上就是我对 bcftools 三剑客的实战总结。记住,校验不是机械地跑命令,而是要结合数据特点,灵活地组合运用。下次当你面对一个陌生的 VCF 文件时,不妨先用 stats 摸个底,再用 filter 洗个澡,最后用 query 仔细瞅瞅——心里就有底了。