VCF 记录字段:CHROM, POS, ID, REF, ALT 的涵义与规范
VCF 文件的每一行,代表一个变异位点。你看第一眼可能觉得不就是几个字母数字嘛,但这里面的坑可不少。我今天就掰开揉碎,把 CHROM、POS、ID、REF、ALT 这五个核心字段讲透。
1. CHROM —— 染色体名称
这个字段告诉你了变异在哪个染色体上。规范要求:必须与参考基因组一致。比如 GRCh37 里是 1、2、… 22、X、Y、MT;GRCh38 里可能多出一些未组装片段的 accession 号。
我遇到过最头疼的情况:同一个项目里,有人用 chr1,有人用 1。程序一合并,染色体名对不上,直接崩掉。所以我的习惯是,预处理阶段统一加或去掉 chr 前缀,用 sed 或 bcftools 搞定。
注意:CHROM 不能出现空格、逗号等特殊字符。写脚本时别忘检查一下。
2. POS —— 位置
POS 是变异在染色体上的坐标。它是 1-based 的,也就是说参考序列的第一个碱基位置是 1。这一点和 BAM 文件里的 0-based 坐标不同,千万别混用。
举个例子:10000 表示参考基因组上第 10000 个碱基。如果变异是插入,POS 指的是插入位点之前那个碱基的位置;如果是缺失,POS 是缺失片段第一个碱基的位置。
我个人经验:检查 POS 是否超出染色体长度是一个很常见的 bug 来源。我在一次全基因组分析中,用了一个质量不好的 VCF,结果 POS 写成了 0,程序直接抛异常。后来我养成了用 bcftools view -i 'POS>0' 过滤的习惯。
3. ID —— 变异标识符
这个字段可用来放 dbSNP 的 rs 号,或者其它数据库的 ID。如果该变异没有已知的 ID,必须用 . 表示缺失。注意:ID 可以包含多个值,用分号 ; 分隔,但标准 VCF 规范里更推荐只用点或单个 ID。多个值容易造成下游工具解析混乱。
我早年对一个公共数据集做注释,发现里面有不少行的 ID 写成了 rs123;rs456。后来问同事才知道,那是不同数据库合并时遗留的“历史问题”。
小技巧:如果你自己生成 VCF,ID 字段最好只放一个 rs 号或空。实在要多个,先确认你用的工具支持。
4. REF —— 参考等位基因
REF 必须是参考基因组上该位置实际存在的碱基序列。对于单核苷酸变异(SNV),就是一个字母 A/C/G/T;对于插入缺失(Indel),就是一段序列。
关键规范:
- REF 必须与参考基因组完全一致,大小写敏感。
- 长度至少为 1(不能为空)。
- 不能包含 IUPAC 模糊碱基(如 R、Y、N)——这些只能在 ALT 中出现。
警惕:如果一个变异是 deletion,比如 REF=ACGT,ALT=A,那么 POS 指示的是第一个碱基 A 的位置。我在处理一份 1000 Genomes 数据时,发现有些行 REF 的左端居然和前面一个碱基重复了——这是左归一化没做干净,导致所有统计全错了。
左归一化(Left Normalization):对于 Indel,要将变异表示到最左侧的坐标。工具如 bcftools norm 可以帮你做。
5. ALT —— 替代等位基因
ALT 是该位置检测到的非参考等位基因。可以是一个碱基、多个碱基,也可以是多个等位基因用逗号分隔(比如 A,T 表示两个不同的替代)。
规范要求:
- ALT 不能等于 REF(否则是无效变异)。
- 如果该位点没有变异(纯合参考),ALT 必须用
.表示。 - 允许用
<DEL>、<INS>等符号表示结构变异,但那是高级用法,初学者先别碰。
我踩过的坑:有一次我用 GATK 的 SelectVariants 过滤,结果输出了一堆 ALT=* 的行。我看着文档才知道,星号表示该位点不是真正的变异,只是被其他变异覆盖的“引用等位基因”。如果不小心把这个 * 当作真实变异传进后续分析,后果很严重。
6. 字段规范速查表
| 字段 | 数据类型 | 必须性 | 示例 | 常见错误 |
|---|---|---|---|---|
| CHROM | 字符串 | 是 | 1, chrX, NC_000001.11 | 混用 chr 前缀 |
| POS | 整数 (1-based) | 是 | 10000 | 0-based 坐标、超出染色体长度 |
| ID | 字符串,分号分隔 | 是(可用 .) | rs12345, . | 多个 ID 导致下游报错 |
| REF | 碱基序列 (A/C/G/T) | 是 | A, ACGT | 大小写错误、包含模糊碱基 |
| ALT | 碱基序列,逗号分隔 | 是(可用 .) | G, A,T, <DEL> | 等于 REF、包含非法字符 |
7. 一个完整的 VCF 记录示例
#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT NA00001
1 12345 rs12345 A G 100 PASS DP=50 GT:DP 0/1:30
1 12346 . AC A 80 q20 DP=20 GT:DP 1/1:10
第一行是标准的文件头,第二行展示了一个 SNV(A→G),第三行展示了一个 deletion(AC→A)。
你看到那个 . 了吗?ID 和 ALT 都可以用点表示缺失。建议新手先把点用对,不要在 ID 里乱填东西。
8. 核心逻辑关系图
下面这张图把五个字段的关系和顺序画清楚了——为什么要这么排?因为 POS 依赖 CHROM,REF/ALT 依赖 POS,ID 是额外的注释。
9. 避坑指南
我之前犯过的错误:有一次我写脚本解析 VCF,直接用 split() 按 tab 切分后取了第 0 到第 4 列。结果某个 VCF 文件里 INFO 列居然有 tab 字符(实际是软件 bug),导致整行被切多了一个字段,后面全乱了。从那以后,我改用正规的 VCF 解析库(如 pysam 或 htslib),再也不手写 split。
建议:在写任何 VCF 相关程序前,先用 bcftools view -h your.vcf 检查头文件,确认列名顺序是 #CHROM POS ID REF ALT QUAL FILTER INFO FORMAT ...。头文件中第 9 列之后才到样本数据,不要数错。
最后总结一下:CHROM 和 POS 是定位,ID 是标签,REF 和 ALT 是变异内容。搞懂这五个字段,你就能正确读、写、改 VCF 文件了。我个人建议初学者背下这五列的顺序,调试时能省一半时间。