VCF 格式基础:定义、版本历史与基本结构
大家好,我是老李。在基因组分析这行混了七八年,每天打交道最多的文件格式之一就是 VCF。说实话,刚入行那会儿我以为 VCF 就是个简单的变异表格,直到有一次用错了版本解析器,把 4.2 的文件当 4.1 读,结果 INFO 字段全乱套了——嗯,从那以后我就老老实实把 VCF 的基础啃透了。今天咱们就从头捋一遍:VCF 到底是什么,怎么来的,长什么样。
1. VCF 格式定义
VCF,全称 Variant Call Format,是存储变异位点信息的标准文本格式。它由一千人基因组计划(1000 Genomes Project)提出,现在由 GA4GH 维护。你想想看,一个 VCF 文件就是一张「变异清单」:每个位点一行,包含参考基因组上的位置、碱基变化、质量分数、过滤状态,以及样本的基因型信息。
我个人的习惯是把它理解成「三联单」:元信息说明数据怎么来的,表头定义每一列的含义,数据行就是实际的变异记录。缺了任何一块,你都没法正确解释一个 VCF 文件。
核心要点:VCF 既是存储格式,也是交换格式。你在不同的分析流程之间传递变异信息,通常就靠它。
2. 版本历史与重要里程碑
VCF 版本迭代不算快,但每次升级都挺关键。我整理了一个简表,方便你对照:
| 版本 | 发布时间 | 主要变化 |
|---|---|---|
| v4.0 | 2010 | 初始版本,定义核心字段(CHROM、POS、ID、REF、ALT、QUAL、FILTER、INFO、FORMAT、样本列) |
| v4.1 | 2011 | 增加 FILTER 行必须大写的约定,规范 ALT 中 |
| v4.2 | 2014 | 引入 |
| v4.3 | 2019 | 增加 #CHROM 前允许空行,规范 contig 元信息,支持更灵活的 FORMAT 字段 |
一个小提醒:现在 99% 的公共数据库和工具都兼容 v4.2 和 v4.3。但如果你手头还有旧版 4.0 的文件,记得用 bcftools 升级一下,千万别直接用老解析器去读。
为什么会分这么多版本?说白了,随着测序技术和分析算法发展,单核苷酸变异(SNV)已经不够用了,结构变异、复杂替换都需要在 VCF 里表达清楚。我曾经在项目里遇到过用 v4.1 的 标记大片段删除,结果入数据库时才发现新版规范已经要求用 加上 INFO/SVLEN 和 INFO/END 字段……那一次花了两天重写转换脚本,教训深刻。
3. 基本结构:从元信息到数据行
一个标准的 VCF 文件分三大部分:元信息行(Meta-information lines)、表头行(Header line)和数据行(Data lines)。我们来看一个实际片段:
##fileformat=VCFv4.2
##FILTER=<ID=PASS,Description="All filters passed">
##INFO=<ID=DP,Number=1,Type=Integer,Description="Total depth">
##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
##FORMAT=<ID=AD,Number=R,Type=Integer,Description="Allelic depths">
#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT sampleA sampleB
chr1 100 . A G 30.5 PASS DP=100 GT:AD 0/0:50,0 0/1:30,20
注意这里的 ## 开头的行就是元信息,用来声明版本号、定义 FILTER、INFO、FORMAT 等字段的元数据。紧接着 #CHROM 开头的行是表头,固定 9 列(CHROM 到 FORMAT),之后每多一个样本就多一列。下面的每一行就是一条变异记录。
3.1 元信息区
元信息行基本遵循 ##key=value 格式。常用的有:
##fileformat=版本声明,绝对不可缺少##FILTER=定义过滤条件##INFO=定义 INFO 标签的类型和含义##FORMAT=定义每个样本列的格式##contig=染色体长度等参考信息
避坑指南:我曾经遇到过一个同事导出的 VCF 没有写 ##fileformat 行,结果 bcftools 默认按 v4.0 解析,导致 FORMAT 字段的 Number=R 被当成固定个数处理,基因型表全部错位。从那以后,我定了个规矩:自己写的生成脚本第一行必须输出版本元信息。
3.2 固定数据列(前9列)
前 9 列是必需的,顺序不可改:
| 列名 | 含义 | 常见问题 |
|---|---|---|
| CHROM | 染色体名称(chr1 或 1) | 命名不统一会导致合并 VCF 时出错 |
| POS | 1-based 起始位置 | 与 0-based 的 BED 对比时容易搞混 |
| ID | 已知的 dbSNP ID 或自定义标识,无则用 . | 很多工具不接受空值,必须用 . |
| REF | 参考等位基因 | 多碱基替换时大写中间不要有空格 |
| ALT | 替代等位基因,多个用逗号分隔 | 空值表示该位点无变异 |
| QUAL | Phred 质量分数 | 缺失时用 . |
| FILTER | 过滤状态,PASS 或具体过滤名 | 多个过滤用 ; 连接 |
| INFO | 键值对格式,如 DP=100;AF=0.5 | Key 需在元信息中定义 |
| FORMAT | 样本字段标签,如 GT:AD:DP | 顺序与后续样本列对应 |
3.3 样本列
FORMAT 列之后,每一列对应一个样本,数据格式按照 FORMAT 定义的顺序,用 : 分隔。比如 GT:AD 对应的样本数据可能是 0/1:30,20。
关键:样本索引从第 10 列开始,个数可变。校验一个 VCF 文件是否完整,第一件事就是数表头的列数是否等于 9 + 样本数。
4. 整张图看清 VCF 结构
下面我手画了一张结构图,把上面说的三大部分串起来。你把它当成一张地图,以后看 VCF 就能快速定位。
5. 接下来你该做什么
了解了基本结构,我建议你动手做三件事:
- 拿一个真实的 VCF 文件(比如 1000 Genomes 的公开 VCF),打开看看元信息行、表头、数据行是不是都齐全。
- 数一数列数:用
head -1 your.vcf | awk '{print NF}'看表头有几个字段。 - 验证一下:用
bcftools view -H your.vcf | head -3看看前几条数据行有没有异常(比如行列不对齐、TAB 被空格替换)。
个人小习惯:我每次拿到新的 VCF 文件,第一时间先用 bcftools stats 跑个统计,既能校验格式,又能快速了解数据质量。