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)是100000-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 是额外的注释。

VCF 记录字段结构 (CHROM·POS·ID·REF·ALT) CHROM POS ID REF ALT 每个 VCF 行按此顺序排列:染色体 → 位置 → 标识符 → 参考碱基 → 替代碱基 CHROM 与 POS 定位变异,ID 可忽略,REF 与 ALT 定义变异类型 变异类型 可选(无则用 .)

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 文件了。我个人建议初学者背下这五列的顺序,调试时能省一半时间。