3、输入文件格式:AVinput格式详解

好,咱们开始聊 AVinput 格式。说实话,在我刚接触 ANNOVAR 那会儿,觉得这格式有点奇怪——既不是标准的 VCF,也不是常见的 BED。但用久了你会发现,ANNOVAR 之所以搞出这么个格式,就是为了省事。它把位置、碱基、等位基因信息全塞进几个列里,一行就搞定一个变异。

我个人习惯,拿到一批数据后,第一件事就是检查格式。因为格式错了,后面的分析全白搭。今天咱们就把 AVinput 的每一个字段掰开揉碎了讲清楚。

3.1 AVinput 格式长什么样

先看一个标准例子。一个 AVinput 文件,每行就是一个变异位点,用制表符(Tab)分隔。我建议你永远别用空格,否则 ANNOVAR 会直接报错。

chr1    948921  948922  A       G       NA12878 60      pass    .       .
chr1    949523  949524  T       C       NA12878 45      pass    .       .
chr1    950003  950004  G       A       NA12878 55      lowqual 0.01    .

说白了,这文件是个纯文本。你拿 Excel 打开,很可能把某些列变成科学计数法。别问我是怎么知道的……

3.2 每一列到底是什么意思

AVinput 固定要求前五列不能少。我整理了一张表,方便你对照着看。

列序号 列名 说明 示例值
1 染色体 支持 chr1 或 1 两种形式。需要与参考基因组保持一致 chr1
2 起始位置 1-based 坐标。注意不是 0-based 的 BED 坐标 948921
3 结束位置 对于 SNP,结束 = 起始 + 1。对于插入缺失,按真实长度算 948922
4 参考等位基因 与参考基因组完全一致。如果有多个碱基,用大写字母 A
5 替代等位基因 样本中检测到的变异碱基。可以跟参考一样(纯合参考) G
6+ 附加列 样本名、测序深度、质量值、过滤标签等。ANNOVAR 不强制,但数据库过滤会用 NA12878
提示:我刚开始时总把起始和结束搞反。记住——起始是1-based的坐标,结束是起始+1。对于SNP,其实它们差1。对于Indel,结束位置就是变异最后一个碱基的位置。

3.3 为什么要有起始和结束两列

你可能会问:SNP 明明就一个位点,为什么非要给两列?

嗯,这里有个历史原因。AVinput 设计时考虑了 Indel。假设你有一个三碱基的缺失:

chr1    1000    1003    ACT    .

起始是 1000,结束是 1003,参考碱基是 ACT,替代是点(表示缺失)。这样一来,ANNOVAR 内部就能准确定位到 Indel 的范围。如果是 SNP,那就写成起始和结束差 1 的形式。我见过不少人把 SNP 的结束写成和起始一样,结果 ANNOVAR 报了个错…… 那错误信息特别隐晦。

3.4 等位基因字段必须大写

这个坑我踩过。有一次从某个流程出来的 VCF 里,有的替代等位基因是小写的 a,我直接拿去做 AVinput 了。结果 ANNOVAR 不停报错说找不到参考序列——实际上就是大小写不匹配。

AVinput 要求参考和替代等位基因必须用大写字母。如果你是从 VCF 转换过来的,记得加一步 tr '[:lower:]' '[:upper:]'。

sed 's/\t[a-z]/\t\u&/g' input.txt > fixed_input.txt
警告:某些数据库(比如 dbSNP)在内部做了大小写归一化,但 AVinput 不会帮你做。大小写不一致,会造成该位点被跳过。我曾经因为这个丢掉了 3% 的变异,排查了一下午才发现。

3.5 附加列:它们是干什么的

前五列之后的东西,ANNOVAR 默认不关心具体含义。它只是把这些列原样保留到输出文件中。但你想想看,如果你不做质量控制,结果里一堆低质量的假阳性,数据库注释再全也是白搭。

我一般会留三列:

  • 第6列:样本 ID。方便多样本合并分析
  • 第7列:测序深度。低于 10× 的变异,我会标记为 low_depth
  • 第8列:过滤标签。可以是 pass、lowqual、strand_bias 等
实践建议:在送去 ANNOVAR 之前,先用 awk 或 python 过滤掉深度低于 8× 的位点。这样做有三个好处:减少假阳性、缩短运行时间、输出文件更小。我几乎每个项目都会加这一步。

3.6 从 VCF 转换成 AVinput

大部分时候你手里的数据是 VCF 格式。AVinput 跟 VCF 最大的区别:VCF 是 0-based 的,AVinput 是 1-based 的。千万别忘了加 1。

我这里有个随手用的脚本,分享给你做参考:

awk -F'\t' 'BEGIN{OFS="\t"} 
/^#/ {next}
{
    chr = $1
    pos = $2 + 1
    end = pos + length($4) - 1
    ref = $4
    alt = $5
    sample = "SAMPLE"
    qual = $6
    filter = $7
    print chr, pos, end, ref, alt, sample, qual, filter
}' input.vcf > input.avinput

注意这里有一个细节:$2 + 1 就是把 VCF 的 0-based 转成 AVinput 的 1-based。对于 SNP,end = pos 实际上就是起始位置;对于 Indel,它会自动算成正确长度。

3.7 格式验证的小窍门

文件写好了,别急着跑 ANNOVAR。先用这行命令快速检查:

awk -F'\t' '{
    if(NF < 5) print "Error: line " NR " has fewer than 5 columns";
    if($2 >= $3) print "Error: line " NR " start >= end";
    if(length($4) == 0 || length($5) == 0) print "Error: line " NR " empty ref or alt";
}' input.avinput

我在项目中遇到最多的问题是:Indel 的结束位置写错了。尤其是大片段缺失,你以为是 1000-2000,但 ANNOVAR 其实只要求覆盖缺失的两个端点。具体来说,先写缺失的起始位点,再写起始+1,参考等位基因写成完整的缺失序列,替代写成 - 表示的空白序列。

避坑:如果出现 WARNING: chromosome not found in reference 错误,百分之九十是因为染色体前缀不一致。比如参考基因组是 1,而你写了 chr1。用 sed 's/^chr//' 或 sed 's/^/chr/' 统一一下就行。

3.8 AVinput 的整体结构

下图把这章的知识点串在了一起。从原始 VCF 开始,经过格式转换、坐标调整、质量控制,最终生成干净的 AVinput 文件,送入 ANNOVAR 进行数据库注释。

AVinput 格式处理流程 VCF 原始文件 坐标转换:0-based → 1-based 附加列筛选:深度≥8,pass 纯净 AVinput 文件 检查要点: • 染色体名与前缀 • 起始 < 结束 • 等位基因大写 • 无科学计数法

3.9 我的日常检查清单

最后,分享一份我自己用的 AVinput 质量检查清单。每次跑 ANNOVAR 之前,我都会在终端跑一遍这些命令,心里才踏实。

  1. 检查染色体格式:awk -F'\t' '{print $1}' input.avinput | sort -u,确认跟参考基因组一致
  2. 检查位置逻辑:awk -F'\t' '$2 >= $3' input.avinput,不能有任何输出
  3. 检查等位基因:grep -i '[a-z]' input.avinput | head,确认没有小写字母
  4. 检查空值:awk -F'\t' 'length($4)==0 || length($5)==0' input.avinput,不能有输出
  5. 检查列数:awk '{print NF}' input.avinput | sort -u,确保每一行列数相同

嗯,能把这些都过了,你的 AVinput 文件就基本没问题了。剩下的就是丢给 ANNOVAR,等着拿结果了。