4. VCF格式详解:头信息、样本列、INFO、FORMAT、过滤等
VCF(Variant Call Format)是生物信息学里最常用的变异格式。说实话,我刚开始接触VCF时也被那密密麻麻的##行搞得头大。但用久了你会发现,这个结构其实很清晰——就像一份带注释的表格,每一块都有明确用途。
核心要点:VCF文件分为三大部分——文件头(##行)、列名行(#CHROM开头)和数据行(每一行一个变异)。理解这三层,整个格式就通了。
4.1 文件头(Header)——元信息大本营
文件头以##开头,记录描述性信息。一个合法的VCF文件必须有##fileformat=VCFv4.2这行。其他常见条目包括:
| 头信息键 | 作用 | 示例 |
|---|---|---|
##fileformat | 格式版本(必选) | VCFv4.2 |
##source | 产生VCF的软件 | GATK4.3.0.0 |
##reference | 参考基因组文件路径 | file:///ref/hg38.fa |
##contig | 染色体信息(长度等) | <ID=chr1,length=248956422> |
##INFO | INFO字段的详细定义 | <ID=DP,Number=1,Type=Integer,Description="Total Depth"> |
##FORMAT | FORMAT字段的详细定义 | <ID=GT,Number=1,Type=String,Description="Genotype"> |
##FILTER | 过滤条件说明 | <ID=LowQual,Description="Low quality"> |
##ALT | 替代等位基因描述(非SNP/INDEL时用) | <ID=DEL,Description="Deletion"> |
嗯,这里要注意:头信息里的##INFO和##FORMAT必须与实际数据行中的标签一一对应。我曾在项目中遇到一个情况:下游工具解析时因为缺少##INFO定义行直接报错退出。排查了半天才发现是头信息不完整。所以写头信息别偷懒,一个都不能少。
我个人习惯是在生成VCF时,先用bcftools head或grep "^##"快速检查头信息完整性。尤其是做pipeline时,头信息的标准化能节省大量debug时间。
4.2 列名行与固定列——表格的标题栏
文件头之后,紧接着是列名行,以#CHROM开头。格式固定:
#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT 样本1 样本2 样本3 ...
每一列的含义如下:
- CHROM / POS:染色体和位置(1-based)。注意不同参考基因组坐标可能不同。
- ID:dbSNP rs号或其他唯一标识,若无则用
.。 - REF / ALT:参考等位基因和替代等位基因。ALT可以多个(逗号分隔)。
- QUAL:变异质量值(Phred scale)。值越高越可靠。
- FILTER:过滤状态。
PASS表示通过,其他值对应头信息中定义的FILTER。 - INFO:变异级别的聚合信息(键值对,分号分隔)。
- FORMAT:该行样本字段的格式(冒号分隔的标签名,如
GT:DP:GQ)。 - 样本列:每个样本一个列,值按FORMAT定义顺序用冒号分隔。
你看,这里FORMAT列名本身也是列名行的一部分。我曾经犯过糊涂,以为FORMAT列是数据行的内容,其实是列名。搞清楚这点后,解析样本数据就顺畅多了。
4.3 INFO字段——变异级别的“聚合信息”
INFO列存放的是整个变异位点的统计量,不区分样本。常见的INFO键包括:
DP:该位点的总覆盖深度(所有样本合并)。AF:等位基因频率(通常基于等位基因计数)。AC:该ALT等位基因在样本中的出现次数。AN:所有样本在该位点的等位基因总数。MQ:Mapping质量均值。QD:质量值除以深度。
举个例子:
##INFO=<ID=AF,Number=A,Type=Float,Description="Allele Frequency">
...
chr1 100 . A G 1200.5 PASS DP=200;AF=0.15;AC=30;AN=200 GT:DP:GQ 0/1:10:99 0/0:8:95 ...
我在做群体遗传分析时常用INFO中的AF来过滤低频位点。但要注意:不同caller产生的INFO字段名称可能不同,比如GATK用AF,freebayes用AF但含义相同。标准化时最好用bcftools annotate --rename-annots统一命名。
避坑:INFO中的Number项至关重要。Number=A表示每个ALT等位基因对应一个值;Number=R表示每个REF+ALT对应一个值;Number=.表示可变数量。解析时如果忽略Number类型,很容易取错索引。我因为这事debug过整整一天,后来才发现是Number类型搞混了。
4.4 FORMAT与样本列——每个样本的“基因型详情”
FORMAT列定义了每个样本字段的格式,样本列则按此格式写入具体数值。例如:
FORMAT 样本A 样本B
GT:DP:GQ 0/1:15:99 1/1:8:45
常用FORMAT键:
- GT:基因型(
0/0、0/1、1/1等)。0表示REF,1表示第一个ALT,2表示第二个ALT(多等位基因时)。分离符号/表示未phased,|表示phased。 - DP:该样本在该位点的覆盖深度。
- GQ:基因型质量(Phred scale)。值高说明基因型可信。
- PL(或GL):基因型似然值(Phred-scaled),通常三个值对应三种基因型。
- AD:等位基因深度(REF深度, ALT深度1, ...)。
注意:若样本数据缺失,通常用.或.填充。比如FORMAT是GT:DP,但某样本的DP未知:./.:.。
我建议在解析样本列时,先通过头信息中##FORMAT定义了解每个字段的类型和Number,再按FORAMT顺序分割样本列字符串。用Python的vcfpy或Java的htsjdk能省去很多手工解析的麻烦。
4.5 FILTER列——通过还是淘汰
FILTER列只有两个常见状态:PASS或者具体的过滤原因。如果FILTER列为.或者空,表示未经过滤(很多工具默认不过滤时写.)。
常见过滤原因:
LowQual:质量低于阈值。QD:QD值过低(质量/深度)。FS:Fisher检验p值过高。BaseQRankSum:碱基质量秩和检验异常。
我个人习惯是保留所有变异(即使FILTER不是PASS),在后续分析时再按需过滤。因为有些过滤条件在不同项目中并不通用。比如我做过一个病毒变异检测项目,默认的GATK硬过滤会把很多真实低频变异误杀。当时我调整了FILTER阈值,才找回关键位点。
4.6 VCF文件结构总览
下面这张SVG图梳理了VCF文件的整体结构,以及各部分之间的关系:
4.7 实战要点与常见问题
- 强制校验头信息:使用
bcftools view -H可以只输出头信息,检查##INFO和##FORMAT是否完整。 - 样本顺序:列名行中样本列的顺序必须与
##SAMPLE头信息或实际样本列表一致,否则下游工具会乱序。 - 缺失值处理:样本列中的
.表示缺失,但不同工具对缺失值的容忍度不同。我在合并多个VCF时遇到过因缺失值格式不一致导致合并失败的情况。 - 多等位基因:ALT列可包含多个用逗号分隔的等位基因,GT中用
0/1、1/2等表示。解析时需注意等位基因索引从1开始。 - FILTER=.:很多caller默认输出
.而不是PASS。如果后续用bcftools filter请先确认过滤状态。
我最常用的调试命令:bcftools view -h input.vcf | grep -c "^##"统计头信息行数;bcftools query -l input.vcf查看样本列表。这两个命令能快速定位VCF常见问题。
VCF格式看似繁琐,但一旦理解了“头信息→列名→数据行”的层级,以及INFO/FORMAT/样本列的职责分工,你就能轻松驾驭它。在实际项目中,标准化VCF的关键就是确保头信息完整、字段命名一致、样本排列有序。后面章节我将带你亲手做格式转换和清洗,把理论变成可重复的代码。