VCF 文件解析:深入理解 QUAL、FILTER、INFO 字段

VCF(Variant Call Format)文件,说实话,是生物信息学里绕不开的“硬通货”。不管你是做 GWAS、群体进化还是肿瘤变异检测,每天打交道最多的可能就是它。我个人习惯是,拿到一个新的 VCF 文件,先不看变异位点,而是扫一眼文件头部的元数据行——这里头埋着整个文件的质量潜规则。

VCF 文件的基本结构

一个标准的 VCF 文件,说白了就是一个带头的制表符分隔表格。头部以 ## 开头,记录元信息;数据行以 #CHROM 开头,定义列名。我刚开始接触时,总觉得头部那一堆 ##INFO、##FILTER 挺占地方,直接跳过看数据。结果后来发现,某个关键质量字段的含义只看文档根本对不上,得回头翻头部的定义。

头部元数据行长这样:

##fileformat=VCFv4.2
##FILTER=<ID=PASS,Description="All filters passed">
##FILTER=<ID=LowQual,Description="Low quality">
##INFO=<ID=DP,Number=1,Type=Integer,Description="Total Depth">
##INFO=<ID=AF,Number=A,Type=Float,Description="Allele Frequency">
##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT SAMPLE1

每个数据行包含 8 个固定列,然后是一个 FORMAT 列加上任意数量的样本列。固定列的序号和顺序不能变,这也是 VCF 的“硬规定”。

QUAL:位点的“置信度打分”

QUAL 字段放的是一个浮点数,代表“该变异位点存在的概率质量分数的 Phred 转换”。嗯,听起来有点绕,你直接把它理解为“这个位点靠谱程度的打分”就行。值越大,越可信。

计算公式基本是:

QUAL = -10 * log₁₀(P(位点是假阳性))

举个例子,QUAL 值为 30,意味着假阳性概率约为 0.001(千分之一)。QUAL 值为 40,概率就是 0.0001。说白了,每增加 10 分,假阳性概率减少一个数量级。

注意:QUAL 不是由比对软件直接给的,而是由变异检测器(如 GATK、FreeBayes)根据读段比对质量、碱基质量、比对唯一性等特征综合计算出来的。不同软件算出来的 QUAL 不能直接比较,硬比会出大问题。

我曾经在整合多个 VCF 文件时,发现同一个位点的 QUAL 值相差十几分,开始怀疑是不是数据出了问题。后来才意识到,一个来自 GATK、一个来自 Samtools,打分模型完全不同。

FILTER:筛选状态的“通行证”

FILTER 字段表示该位点有没有通过用户或软件预设的质量条件。常见的值包括:

  • PASS:通过了所有过滤规则。
  • .(点):没有应用过滤,或者过滤条件未定义。
  • LowQual / LowDepth:自定义过滤标签。
  • q10 / qd2等:某些流程按阈值直接给标签。

为什么要搞这么麻烦?因为你想想看,某些研究需要极高精度的位点(比如临床诊断),而另一些研究(比如初步筛查)可以接受一定容忍度。有了 FILTER 字段,你可以快速筛选出对应的子集,而不用每次都重新计算。

避坑:不要只看 FILTER = PASS 就以为位点是可靠的。PASS 仅代表通过了预设规则,不保证生物学真相。我曾经遇到过一批全 PASS 的位点,后来在实验验证中假阳性率高达 20%,原因是过滤规则设得太松,没考虑到重复区域的参考偏误。

INFO:位点特征信息的“百宝箱”

INFO 字段是 VCF 里信息密度最高的地方。它是一个键值对列表,用分号分隔,每条记录定义在头部元数据中。常见的 INFO 字段包括:

字段 类型 描述 典型值范围
DP Integer 该位点的总测序深度 10 – 500+
QD Float QUAL 值除以深度(质量/深度比) 0 – 30+
MQ Float 支持该变异的读段比对均一性 0 – 60
AF Float 等位基因频率(可接受多个值) 0 – 1
ExcessHet Float 杂合子过量的 p 值 0 – 1
FS Float 链偏好性的 Fisher 精确检验 p 值 0 – 60+

为什么 INFO 字段这么重要?因为它把位点的多个质量维度都打包进来了。只靠 QUAL 一个值,你很难判断一个深度低但碱基质量好、和一个深度高但链偏好明显的位点哪个更可靠。但有了 DP、QD、FS、MQ 这些特征,你可以做更精细的分层过滤。

我个人最喜欢用的是 QD(质量/深度比)。为什么?因为它天然地对高深度假阳性不敏感。我见过一个深度达 1000× 的位点,QUAL 值只有 200,看起来还过得去,但 QD 只有 0.2,明显是假阳性——可能是重复区域或比对错误导致的。

一个典型的 INFO 记录示例

下面是从真实 VCF 文件中截取的一行:

chr1    123456  .   A   G   945.77   .    DP=218;QD=13.8;MQ=59.3;FS=3.2;AF=0.44

解读一下:

  • QUAL = 945.77,非常高,但单独看意义不大。
  • DP = 218,深度充足。
  • QD = 13.8,远高于常见的过滤阈值 2,靠谱。
  • MQ = 59.3,接近完美(最高 60),说明读段比唯一性好。
  • FS = 3.2,非常低(小于 10 通常视为无链偏好),说明正反链覆盖平衡。
  • AF = 0.44,接近杂合子期望值 0.5,符合真实变异分布。

这样一个位点,如果在你的过滤规则里还在挣扎,那说明你的规则太严了。

VCF 三大字段的评估流程

下面这张图总结了我在工作中解析 VCF 的核心逻辑。从原始 VCF 出发,先理解头部定义,然后分别处理 QUAL、FILTER、INFO,最后统一进入过滤决策。

VCF 三个关键字段的解析与过滤决策流程 原始 VCF 文件 解析头部元数据(##INFO / ##FILTER) QUAL 评估 质量分数 > 30 ? FILTER 评估 PASS / 自定义标签 INFO 字段提取 DP、QD、FS、MQ 等 组合过滤规则 QD > 2.0,MQ > 40,FS < 60 标记为可疑位点 保留但低置信度 标记为高质量位点 用于下游分析 小提示:不要只依赖一个字段 结合 QUAL、FILTER、INFO 做多维度评估

三个字段的关系与权衡

你可能会问:三个字段能不能互相替代?答案是不能。QUAL 反映统计置信度,FILTER 反映规则是否通过,INFO 提供多维特征。它们三个就像“分数、考勤、作业表现”的关系,单独看哪一项都不全面。

我举个实际例子:某个高深度 CNV 区域,QUAL 很低但 FILTER=PASS,信息字段里的 FS 却非常高。这种情况很可能是重复序列导致的比对偏好,但又没触发软件默认的过滤阈值。如果你只看 FILTER 就放过,模型就被污染了。

经验之谈:我在构建位点质量特征的时候,会把 QUAL 作为基线,然后用 INFO 字段(比如 QD、FS、MQ)构建一个多维度评分向量。最后再结合 FILTER 做一个二分类筛选。这样既能保留高质量位点,又不轻易丢弃潜力位点。

实操小贴士

最后,分享一个我常用的小脚本片段。它用于从一个 VCF 文件中提取关键质量字段,并打印出来做快速质控:

import vcf

with open('input.vcf', 'r') as vcf_file:
    reader = vcf.Reader(vcf_file)
    for record in reader:
        qual = record.QUAL
        filt = record.FILTER
        info_dp = record.INFO.get('DP', None)
        info_qd = record.INFO.get('QD', None)
        info_fs = record.INFO.get('FS', None)
        print(f"位点: {record.CHROM}:{record.POS}")
        print(f"  QUAL: {qual}, FILTER: {filt}")
        print(f"  DP: {info_dp}, QD: {info_qd}, FS: {info_fs}")

这段代码读入 VCF 文件,分别提取三个关键字段。你可以在自己的流程里套用,快速扫描一批位点的质量分布,然后决定下一步要替换还是调整过滤参数。