第1章 VCF格式概述

我个人做变异分析这么多年,接触过的格式少说也有十几种。但要说哪个最绕不开,那还得是VCF。说白了,VCF就是变异 calling 结果的通用语言。你不管用什么软件跑的变异检测,最终要想做注释、做筛选、做可视化,几乎都得回到VCF这个格式上来。

本章咱们就把VCF的骨架先摸清楚。我不打算一上来就丢一长串规范文档,咱们从实际文件的结构入手,把每个字段是干什么的、为什么要这么设计,都掰扯明白。

1.1 VCF文件的三大块

一个标准的VCF文件,其实就三部分内容。我习惯这样记:元数据、表头、数据行。元数据告诉你这个文件是怎么来的,表头告诉你每一列代表什么,数据行就是真正的变异记录。拿一个最简单的VCF文件片段来说:

##fileformat=VCFv4.2
##source=myPipeline_v1.0
##contig=<ID=chr1,length=248956422>
##INFO=<ID=DP,Number=1,Type=Integer,Description="Total Depth">
##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
#CHROM  POS     ID      REF     ALT     QUAL    FILTER  INFO    FORMAT  SAMPLE1
chr1    10000   .       A       G       500.23  PASS    DP=120  GT      0/1

元数据行以两个#开头,表头行以一个#开头,数据行不要#。这个区分其实挺好记的。我在项目初期带新人时,经常看到有人把元数据和表头混着写,结果解析工具直接报错。嗯,这里要注意,元数据必须放在表头之前,顺序不能乱。

1.2 核心字段逐个拆解

表头后面的数据行,固定有8个核心字段,再加上后面的样本列。我把它们的含义和常见坑点整理成了一张表:

字段 含义 我遇到过的坑
CHROM 染色体名称,需与参考基因组一致 引物设计时发现染色体名前带"chr"和不带混用,直接导致下游报错
POS 变异在染色体上的起始位置(1-based) 1-based的坐标容易和BED格式(0-based)搞混,我吃过这个亏
ID 已知变异的标识符,如dbSNP的rs号 常用点号占位,不代表没有ID
REF 参考基因组上的等位碱基 长度可为多碱基,但必须与参考一致
ALT 检测到的替代等位碱基 多个等位基因用逗号分隔,不要用空格
QUAL Phred质量分数 分数越高越可靠,但我见过有人直接当p-value用,完全不是一回事
FILTER 过滤标签 PASS表示通过,否则是具体失败原因
INFO 位点级别的附加信息 使用key=value形式,多个用分号隔开

FILTER字段的潜规则:PASS是唯一被广泛认可的通过标记。如果你用点号或者空值代替,很多工具会默认当作未过滤,可能把一些假阳性也放进来。我个人建议,经过过滤的VCF一定要写PASS,别偷懒。

1.3 元数据说了什么

元数据这部分,初学者容易忽略。其实它就像菜的包装说明,告诉你这包数据过了哪些处理、用了什么参考基因组、定义了哪些INFO键和FORMAT键。

最常用到的元数据标签有这么几类:

  • fileformat:VCF规范的版本号,目前主流是VCFv4.2
  • source:生成该VCF的软件或流程
  • reference:参考基因组的路径或版本
  • contig:定义每条染色体的ID和长度
  • INFO:声明INFO字段中的键,包含类型、数量和描述
  • FORMAT:声明FORMAT字段中的键,包含类型、数量和描述
  • FILTER:声明FILTER字段中出现的过滤原因

为什么要花篇幅讲元数据?因为下游工具,比如SnpEff、ANNOVAR、VEP,它们的解析逻辑高度依赖元数据中的声明。如果你自己写脚本处理VCF,也一定要先提取元数据做校验。我曾经接手过一个历史项目,里面INFO字段的DP被声明为Float,但实际数据里写的是Integer,解析直接崩了。所以,元数据就是契约,别自己破坏它。

1.4 INFO与FORMAT的区别与结构

这个问题我每次讲课都会被问到。INFO和FORMAT都是一个键值对字符串,但作用域完全不同:

  • INFO:作用于整个位点(一行就一个值),比如覆盖深度、变异类型
  • FORMAT:作用于每个样本的单个基因型,比如GT、AD、PL

拿之前那个例子来说:INFO=DP=120表示这个位点的总覆盖深度是120,无论有多少样本,这个值都是一个。而FORMAT=GT对应样本列0/1,表示该样本在这个位点是杂合子。

为什么不能把样本级别的深度也放进INFO?你想想看,如果我有100个样本,每个样本的深度都不一样,放在INFO里就得写100个键,那得多乱。FORMAT就是为了这种样本级别的结构化数据而设计的。

1.5 常用格式规范小结

聊完结构,我把自己常用的几条规范清单列出来。这些规矩不遵守,工具就报错;遵守了,大家数据交换时也省心。

规范项 具体要求
字段分隔符 使用制表符,不能混用空格
缺失值 用.占位,不要留空
字符串编码 统一用UTF-8,无BOM
换行符 Unix风格(LF),不要用CRLF
压缩方式 推荐使用bgzip压缩,配合tabix建立索引

关键警告:别用普通gzip压缩VCF!普通gzip不支持随机访问,而bgzip压缩的文件可以配合tabix快速索引和区域查询。我刚开始学的时候,把上百G的VCF用gzip压了,结果每次想查一个区域都要解压整个文件,白白浪费了几个小时。bgzip是标配,没有商量余地。

最后,我把本章的知识体系用一张图串起来,方便你了解VCF的全局结构:

VCF 文件结构总览 元数据(## 行) 表头(# 行) 数据行(无 #) fileformat / source INFO / FORMAT 定义 contig / FILTER 定义 8个核心字段名 FORMAT + 样本列 CHROM / POS / ID / REF / ALT QUAL / FILTER / INFO FORMAT + 样本基因型数据 文件必须严格按 元数据 → 表头 → 数据行 的顺序排列 推荐使用 bgzip 压缩 + tabix 索引,以便快速随机访问 8个核心字段顺序固定 CHROM · POS · ID REF · ALT · QUAL FILTER · INFO 缺失值用 . 表示 多个ALT等位基因 用逗号分隔 INFO用分号分隔

一点小建议:学VCF格式最好的方法就是打开一个真实的VCF文件看。你可以用less或者head -n 20预览,看清每一行的结构。我自己的习惯是,拿到一个新VCF文件,先看元数据里INFO和FORMAT的定义,再看数据行的实际内容,这样心里就有数了。