VCF文件格式基础
VCF,全称Variant Call Format,是生物信息学里最常用的变异文件格式。我刚开始做生信那会,整天跟VCF打交道,第一感觉就是——这格式看着吓人,其实拆开来看就几块东西。
你想想看,一个标准的VCF文件,无非就是三大部分:头信息(Header)、主体记录(Records),以及最关键但很多人忽略的——样本字段(Sample Fields)。咱们一个一个说。
头信息(Header)
头信息以 ## 开头,每一行都定义了一个元数据。我习惯先快速扫一眼头信息,就知道这个VCF是谁跑的、用了什么参考基因组、有哪些INFO和FORMAT字段。
常用的头信息类型:
##fileformat=VCFv4.2—— 版本号,现在主流是4.2或4.3##fileDate=20231015—— 文件创建日期,说实话经常不准,不少工具会漏掉##reference=file:///ref/hg38.fa—— 参考基因组路径,嗯,这里要注意:路径写绝对还是相对容易导致迁移问题##INFO=<ID=AF,Number=A,Type=Float,Description="Allele Frequency">—— 定义INFO字段的结构##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">—— 定义样本格式字段##FILTER=<ID=LowQual,Description="Low quality">—— 过滤器说明
我个人经验:写完代码批量处理VCF之前,一定要先 grep "^##" 把头信息提取出来看一眼,否则后面解析INFO字段类型对不上就麻烦了。
Number 的值除了数字,还有 A(按等位基因数)、R(按参考+等位基因总数)、G(按基因型数)、.(可变长度)。我曾经写过一个脚本,默认
Number=1 解析 INFO=AF,结果人家是 Number=A,直接索引越界。从那以后我都是先读头信息动态判断。
主体记录(Records)
头信息下面,从 #CHROM 开始才是真正的记录行。每一行包含9个固定字段,然后跟样本列。我列出这些字段,你大概看一眼:
| 列号 | 名称 | 说明 | 避坑要点 |
|---|---|---|---|
| 1 | CHROM | 染色体名称 | 可能带"chr"前缀,一定要统一 |
| 2 | POS | 左对齐的位置(1-based) | 很多人搞错0-based还是1-based |
| 3 | ID | dbSNP rs号或点号 | 空值用 "." 表示,别用 " " 或 "NA" |
| 4 | REF | 参考碱基 | 可以是多个碱基,注意大小写 |
| 5 | ALT | 替代等位基因,逗号分隔 | 多个ALT时顺序很重要 |
| 6 | QUAL | 质量分数(Phred scale) | 缺失用 ".",数值可能很大 |
| 7 | FILTER | 过滤状态,通过用 "PASS" | 多个过滤器用分号隔开 |
| 8 | INFO | 键值对,分号分隔 | 浮点数精度可能丢失 |
| 9 | FORMAT | 样本列格式定义,冒号分隔 | 顺序必须与样本数据一致 |
| 10+ | 样本列 | 每个样本一个列,冒号分隔 | 缺失用 "." 或 "./." |
这里我要特别提一下 POS 和 REF。VCF强制使用左对齐标准化。什么意思?如果一个indel出现在重复序列里,不同工具叫出来的位置可能不一样。我建议用 bcftools norm 做一次标准化,不然合并多个VCF时会疯掉。
基因型格式(FORMAT字段)
FORMAT字段直接定义了每个样本的数据结构。常见的有:
- GT —— 基因型,比如
0/1表示杂合,1|1表示纯合。分隔符/表示无相位,|表示有相位 - AD —— 每个等位基因的深度,比如
10,5表示REF深度10,ALT深度5 - DP —— 该位点总覆盖深度
- GQ —— 基因型质量分数(Phred scale)
- PL —— 三种基因型的归一化似然值(Phred scale)
举个实际的样本字段例子(假设FORMAT=GT:AD:DP:GQ:PL):
0/1:15,8:23:88:100,0,200
解析出来就是:杂合,REF深度15,ALT深度8,总深度23,GQ=88,PL值表示最可能基因型是0/1。
record.samples[0].alleles 获取等位基因索引,别自己手动拆GT字符串,因为处理相位符号和缺失值时容易出错。pysam已经帮你做好了。
常用INFO标签解读
INFO字段是变异级别的注释,常见的就那么几个:
| 标签 | 类型 | 含义 | 个人经验 |
|---|---|---|---|
| AF | Float | 人群等位基因频率 | 注意有些VCF的AF是逗号分隔的多个值,对应多个ALT |
| AN | Integer | 有效等位基因总数 | 用于计算AC时要注意 |
| AC | Integer | 每个ALT的等位基因计数 | 如果ALT有3个,AC就有3个值 |
| DP | Integer | 该位点总深度(跨所有样本) | 与样本级别DP不同,别搞混 |
| MQ | Float | 映射质量(Mapping Quality) | 低MQ可能表示结构变异假阳性 |
| QD | Float | 质量除以深度(QualByDepth) | 我自己常用QD<2.0做硬过滤 |
| FS | Float | Fisher链平衡检验的P值(Phred scale) | FS>60通常表示链偏置严重 |
你肯定注意到了,INFO字段里的标签名都是大写、无空格。这是VCF规范,写pysam脚本时直接 record.info['AF'] 就能获取。
一图看懂VCF结构
下面这张SVG图是我自己画的结构拆解,建议收藏:
chr1 带chr前缀。很多公共数据(比如1000 Genomes)是不带chr的,而Ensembl又带。你用pysam处理时务必先用 record.chrom 检查规范,或者预先统一染色体命名。
说白了,VCF没那么神秘。你只要搞懂头信息->固定列->样本列这个三层结构,再加上几个常见标签的含义,就能轻松用pysam进行后处理了。我推荐你拿一个真实的小型VCF文件,用 less -S 看一下原始内容,再对比上面的SVG图,立马就通透。