第1章 VCF文件格式基础

做多批次VCF一致性评估,最先要面对的就是VCF文件。

我第一次接触VCF时,打开文件一看,满屏的#号和TAB分隔符,说实话有点懵。后来啃了很久的官方规范,又在实际项目里摔了几次跟头,才算真正搞明白。

这一章,我就带你仔细看看VCF到底长什么样。

VCF是什么?

VCF全称Variant Call Format,是GA4GH(Global Alliance for Genomics and Health)制定的变异数据标准。说白了,它就是为了统一记录基因组上的变异信息而存在的。无论你是做WGS全基因组测序,还是做WES全外显子组测序,最后产出的变异结果基本都是VCF格式。

VCF文件的核心结构可以用三个层级来理解。

三个核心层级:
  • 元数据层:以##开头的注释行,记录文件版本、参考基因组、数据来源和过滤条件
  • 表头层:以#CHROM为起始的最后一行注释,告诉你怎么解读后面的数据列
  • 数据层:Tab分隔的变异记录行,每行代表一个变异位点

嗯,这里要注意。很多人误以为VCF就只是变异信息的罗列,其实元数据部分包含了很多评估一致性的关键信息,比如工具版本、参数配置等。我曾遇到过一个项目,两个批次文件看起来差不多,但Filter列的含义完全不同。原因就在元数据里的Filter定义不一致。

VCF文件结构全貌

下面我手绘了一张结构图,你一看就明白。

VCF文件结构总览 元数据行 (Header Lines) ##fileformat=VCFv4.2 ##reference=GRCh38 ##INFO=<ID=DP, ...> ##FILTER=<ID=PASS, ...> ##FORMAT=<ID=GT, ...> 以 ## 开头,文件的基础配置字典 #CHROM POS ID REF ALT QUAL FILTER INFO FORMAT sample1 sample2 数据行 (Data Lines) chr1 10010 . A G 50.2 PASS DP=100;AF=0.5 GT:AD 0/1:30,70 chr1 10020 rs123 T C 99.8 PASS DP=200;AF=0.3 GT:AD 1/1:0,200 chr2 50000 . G A 30.1 q10 DP=50;AF=0.1 GT:AD 0/0:50,0 每行一条变异,Tab分隔 关键信息藏在哪里? • 参考基因组版本在元数据里写 • QUAL和FILTER决定位点可信度 • FORMAT定义每个样本的格式

元数据:解读VCF的第一把钥匙

元数据行以##开头,包含文件的所有配置信息。我个人习惯,拿到任何VCF文件,第一件事就是看元数据头。

以下是几种最常见的元数据类型。

元数据标签 含义 示例
##fileformat VCF规范的版本号 ##fileformat=VCFv4.2
##reference 参考基因组文件路径或版本 ##reference=file:///ref/GRCh38.fa
##INFO INFO字段中各标签的定义 ##INFO=<ID=DP,Number=1,Type=Integer,Description="Total depth">
##FORMAT FORMAT字段中各标签的定义 ##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
##FILTER 过滤条件定义 ##FILTER=<ID=q10,Description="Quality below 10">
##ALT 替代等位基因的定义(如结构变异) ##ALT=<ID=DEL,Description="Deletion">
我的经验:在做多批次一致性评估时,##INFO和##FORMAT的定义必须对齐。有一次我发现两个批次的DP含义不一样——一个表示总深度,一个表示平均深度,直接导致下游分析出现偏差。

表头行:数据列的含义总纲

表头行是元数据部分的最后一行,以#CHROM开头。它不是##,而是单#。这一行告诉你每一列分别代表什么。

固定列一共9列,顺序严格固定。

列名 说明
CHROM 染色体编号,如chr1、chrX
POS 位点坐标,1-based整数
ID dbSNP rsID或自定义标识,没有用.表示
REF 参考基因组上的碱基序列
ALT 变异后的碱基序列,多个用逗号分隔
QUAL 质量值,越高越可信
FILTER 过滤状态,PASS表示通过
INFO 冒号分隔或分号分隔的键值对
FORMAT 样本数据字段格式定义

第10列之后是样本列,数量不定。FORMAT定义了如何解读这些样本列。你想啊,如果FORMAT写的是GT:AD:DP,那样本列里就是三个值,用冒号隔开,依次对应GT、AD和DP。

关键字段详解

关键字段里,我最想聊的是以下这几个。评估一致性时,它们经常出问题。

1. CHROM和POS:定位位点身份

这两个字段共同决定了变异的位置。不同批次的VCF,染色体命名可能不同。有的用chr1,有的只用1。我建议在评估前统一标准化chr前缀,否则同样的位点可能会被判定为不同位置。

2. REF和ALT:描述变异内容

REF是参考等位基因,ALT是替代等位基因。注意,对于SNP来说REF=A ALT=G就一行。但对于Indel,REF和ALT长度不同。举个例子:REF=ACGT ALT=A表示删除了一个CGT。

曾经踩过的坑:在做两个批次的位点匹配时,我遇到过一个情况。A批次用REF=ACGT ALT=A表示删除,B批次用REF=CGT ALT=A表示同一个变异,但因为参考等位基因不完整导致没匹配上。这类问题在合并VCF时经常发生,稍不注意就会遗漏位点。

3. QUAL和FILTER:质量评估过滤器

QUAL是浮点数,值越高表示可信度越高。FILTER则是一个条件标签,PASS是唯一表示通过的标签。其他如q10、LowQual都被认为是没有通过的。

多批次评估时,我建议那些通过了QUAL而FILTER不是PASS的位点,直接剔除,因为它们可能因为各种原因被标记为了不靠谱的变异。

4. INFO:变异级别的注释

INFO字段包含变异级别的额外信息,比如等位基因频率AF、测序深度DP、等位基因支持数AC等。这些值在不同批次之间可能存在差异,但要注意数值类型是否一致。

5. FORMAT和样本数据:转录组级别与基因型

FORMAT定义了样本数据的格式,最常见的标签是GT(基因型)、AD(等位基因深度)、DP(样本深度)。

基因型GT的编码规则是这样的。

GT编码 含义
0/0 纯合参考
0/1 杂合变异
1/1 纯合变异
./. 缺失(无有效基因型)
检查清单:拿到VCF文件后,建议先确认以下几点。
  • ##fileformat版本是否一致?
  • ##reference指向的参考基因组版本是否相同?
  • CHROM的命名风格是否统一?
  • FILTER中PASS的定义是否相同?
  • FORMAT字段是否一致?

一个完整的VCF示例

下面是一个实际的VCF文件片段,你可以对照着体会一下。

##fileformat=VCFv4.2
##reference=GRCh38
##INFO=
##INFO=
##FILTER=
##FILTER=
##FORMAT=
##FORMAT=
#CHROM  POS     ID      REF     ALT     QUAL    FILTER  INFO            FORMAT  sample1
chr1    10010   .       A       G       50.2    PASS    DP=100;AF=0.5   GT:AD   0/1:30,70
chr1    10020   rs123   T       C       99.8    PASS    DP=200;AF=0.3   GT:AD   1/1:0,200
chr2    50000   .       G       A       30.1    q10     DP=50;AF=0.1    GT:AD   0/0:50,0
chr3    200000  .       ACGT    A       80.0    PASS    DP=150;AF=0.2   GT:AD   0/1:120,30

你看看第三行,QUAL=30.1,FILTER=q10,虽然质量值不太差,但被过滤掉了。这种位点在一致性评估时,是否要纳入,取决于你的研究目标。如果是要高精度的位点,我建议直接过滤掉。

一致性评估视角下的VCF关键点

从评估一致性的角度出发,我总结了三个必须注意的点。

  1. 位点对齐性:同一批次的两个VCF,或者不同批次之间的VCF,必须使用相同的坐标系统和参考基因组。否则位点无法直接比较。
  2. 字段命名一致性:INFO和FORMAT的标签名必须相同。即使内容含义一样,但标签名变了,也无法通过一致性检查。曾经在一个项目中,一个批次用DP表示深度,另一个批次用DP_HQ表示深度,导致了一个错误率的误判。
  3. 基因型编码规则:GT的编码方式要一致。有些工具使用0|1分隔符表示已定相,有些使用0/1。如果混在一起使用,一致性评估会出错。

VCF文件格式虽然看起来复杂,但只要抓住元数据、表头、数据行这个骨架,再搞清楚INFO、FORMAT、GT这些核心字段,做一致性评估时就能知其然并知其所以然了。说白了,VCF不是什么黑盒,它就是个精心设计的表格文件。

一点建议:在我个人的工作流里,拿到新的VCF后,我会先写一个小脚本,输出元数据中的关键信息,比如文件版本、参考基因组、FORMAT定义等。这样在开始评估之前,就已经对数据有个大致的底了。这个小习惯,帮我省了不少排查问题的工夫。