Mutect2默认过滤规则解析:硬过滤参数详解

说实话,我刚接触Mutect2那会儿,看到一堆过滤参数简直是头皮发麻。什么FS、QD、MQ……每个缩写背后都藏着一套统计逻辑。我习惯把硬过滤比作「变异位点的安检门」——只有通过所有关卡,你才敢把这个位点放进下游分析。

为什么要搞这么复杂?因为你想想看,测序数据太脏了。PCR重复、链偏好、比对错误、同源区域……这些噪声都会伪装成「看起来很真的变异」。硬过滤就是一把快刀,先把明显靠不住的砍掉,剩下的再交给更精细的模型(比如FilterMutectCalls)。

我的经验: 硬过滤不是越严越好。我曾经在一个WES项目里把FS阈值降到20,结果真实位点被干掉一大片,最后不得不重跑。阈值调优的度,得靠摸索。

硬过滤参数全家桶

Mutect2在Calling阶段会为每个变异位点计算一组统计量。默认的硬过滤规则写在GATK的源码里,直接在VCF的FILTER字段打标记。下面这几个参数是核心中的核心:

参数 全称 默认阈值 它想表达什么
FS Fisher Strand > 30.0 链偏好的证据强度(p值取-log10)
QD QualByDepth < 2.0 质量值除以深度,类似于信噪比
MQ RMSMappingQuality < 40.0 支持该变异的reads的平均比对质量
MQRankSum MappingQualityRankSumTest < -12.5 变异位点内外reads的比对质量分布差异
ReadPosRankSum ReadPosRankSumTest < -8.0 变异位点内外reads的位置分布差异

这些都是RNA-seq或肿瘤体细胞突变中常见的「噪声指标」。FS太高说明链偏好严重,可能是个假阳性;QD太低说明质量虽高但深度不足,可能是随机错误;MQ低于40说明比对质量差,可能来自重复区域或同源序列。

注意: 默认阈值是针对人类WGS/WES设计的。如果你做植物基因组、微生物组或者低深度测序,这些值大概率要重新调。我曾在一个真菌项目中只改了一个参数——把QD降到1.5,召回率就上来了17%。

参数之间的「互相牵制」

单独看每个参数没问题,但组合起来就有意思了。举个例子,FS高但QD也高的位点,可能是真实的链偏好还是假阳性?我个人习惯先看QD:如果QD > 5.0,即使FS到50,我也倾向于保留,因为深度足够大时链偏好会被稀释。反过来,QD < 1.0的位点,就算FS只有5,我也直接过滤掉——因为信噪比太差。

这里有一张我常用的决策逻辑图,帮你理清思路:

Mutect2硬过滤决策流程 硬过滤参数联合决策流程 原始变异位点 QD < 2.0? (深度不足/随机错误) FS > 30.0? (链偏好严重?) MQ < 40.0? (比对质量差/重复区域) MQRankSum < -12.5? 或 ReadPosRankSum < -8.0? (分布差异异常) 全部通过 → 保留 任一条件不满足 → 标记为FAIL 注意 QD高可容忍高FS

看到没有,这是一个串联的安检流程。每个位点必须连续通过所有关卡。不过在实际项目中,我经常碰到FS很高但QD也很高的位点——比如肿瘤扩增子测序的高深度区域。默认阈值会把这些位点过滤掉,但我通过调整FS到50,就保留了这些可能是真的突变。

直接在命令行里改阈值

你不需要等FilterMutectCalls才改阈值。在Mutect2运行的时候就能指定硬过滤规则。看一个例子:

gatk Mutect2 \
    -R hg38.fa \
    -I tumor.bam \
    -I normal.bam \
    -O raw.vcf \
    --max-reads-per-alignment-start 6 \
    --f1r2-tar-gz f1r2.tar.gz \
    --germline-resource af-only-gnomad.vcf \
    --custom-filter "FS > 30.0" \
    --custom-filter "QD < 2.0" \
    --custom-filter "MQ < 40.0" \
    --custom-filter "MQRankSum < -12.5" \
    --custom-filter "ReadPosRankSum < -8.0"

注意这些--custom-filter参数写的是过滤条件,而不是通过条件。如果变异位点满足其中任意一条,它就会被标记为custom_filter。默认的硬过滤名字叫hard_filtered,但你用--custom-filter-name可以自定义。

一个小技巧: 如果你想先看看效果再决定,可以先用默认阈值跑,然后从VCF的INFO/FT字段提取统计量,画个分布图。我习惯先用R画FS和QD的散点图,一眼就能看出阈值附近的数据密度。这样调起来心里有底。

避坑指南:那些年我掉过的坑

  • 坑1: 默认阈值对低深度数据太激进。我做过一个cfDNA项目,平均深度只有15x。QD的2.0阈值把80%的位点都过滤了。后来我把QD降到1.0,同时把FS放宽到50,召回率就正常了。
  • 坑2: FS和QD的交互效应被忽略。你光看FS高就过滤,但QD如果>5,那个高FS可能是PCR偏好引起的,不是真正的链偏好。我的方案是:先过滤QD<2.0的,再过滤FS>60的。
  • 坑3: MQRankSum和ReadPosRankSum对插入/缺失更敏感。有时候SNP的RankSum看起来正常,但indel的RankSum特别差。我在某个项目里把indel的ReadPosRankSum阈值从-8.0改到-10.0,假阳性就降了不少。
再次提醒: 改阈值一定要保留一份默认结果做对照。我习惯用下面的命令同时跑两个工作流,然后对比VCF的行数:
# 默认版本
gatk Mutect2 ... -O default.vcf
# 宽松版本
gatk Mutect2 ... -O relaxed.vcf \
    --custom-filter "QD < 1.5" \
    --custom-filter "FS > 50.0"
然后grep -v "^#" default.vcf | wc -l看看过滤了多少。

我一直觉得硬过滤是整套流程里最「经验主义」的一环。你调的阈值必须贴合你的数据特征——测序平台、覆盖深度、样本类型、肿瘤纯度,这些都会影响最优点。没有万能配方,只有反复验证。