3. 常见错误类型总览与分类归纳
GFF 和 GTF 文件的错误,说白了就那几大类。我早期做基因组注释时,经常被各种报错搞得焦头烂额。后来接触的项目多了,发现大部分错误其实都逃不出这几类。咱们先把它们捋清楚,后面才好一个个地修。
3.1 按错误性质分四大类
我把遇到过的错误归纳成四类:结构错误、语义错误、坐标错误、属性错误。下面这张图能帮你快速建立整体印象。
3.2 结构错误——最基础也最容易犯
结构错误指的是文件格式本身不满足规范。我一开始手写 GTF 时,经常漏掉制表符或者多打个空格。你想想看,GFF/GTF 是严格的制表符分隔文件,每行必须有 9 列,一个都不能少。
常见表现:
- 列数不对:某行只有 8 列或 10 列。原因往往是漏了第 9 列的属性,或者属性里含有制表符被误认为分隔符。
- 分隔符错误:用了空格、逗号或者混合制表符。我见过用 Excel 导出的 GFF,制表符被替换成空格,解析直接崩掉。
- 字段顺序错乱:比如 seqid 和 source 写反了。GFF 的前 8 列顺序是固定的,不能乱。
- 空行或注释行:某些工具会把空行当有效行处理,导致解析中断。
一条正常 GFF 行的结构(9列):
seqid source type start end score strand phase attributes
每列之间必须用单个制表符(\t)分隔。
3.3 语义错误——工具认不出来的标签
结构对了,但内容不符合规范。我记得有一次用 GFF 跑 cufflinks,老是报“unknown feature type”。查了半天,原来是我把“CDS”写成了“Cds”——大小写敏感。
典型场景:
- feature type 不在标准列表内:比如你写成“exon”而不是“exon”,或者用了自定义名称如“my_gene”,但下游工具只认“gene”。
- strand 值错误:只允许“+”或“-”,偶尔允许“.”(表示未知)。填成“+”加号后面多个空格就直接报错。
- phase 值超出范围:只能填 0、1、2 或“.”。我见过有人填了“-1”,解析器直接终止。
我的小经验:如果不确定 feature type 是否合法,去查看 GFF3 或 GTF2.2 的官方规范文档,里边有枚举列表。或者直接参考你的参考基因组注释文件里的 type 值。
3.4 坐标错误——注释位置不合理
坐标错误是最隐蔽的一类,因为程序不一定报错,但结果完全错位。我遇到过一个案例,注释说某个外显子从 1000 到 500,显然是 start 大于 end,但因为是 GFF 第三、四列,有些工具不会主动检查。
常见情形:
- start > end:正链上应该 start ≤ end。负链也一样,坐标顺序永远是 start(较小编号)在前。
- 坐标超出染色体长度:比如染色体 chr1 只有 2M,你写了个 5M 的位置。最好用序列文件(fasta)的 .fai 索引对照一下。
- 跨染色体错误:同一个基因的 exon 居然分布在 chr1 和 chr2 上?一般是组装时搞混了。
- 负坐标或零坐标:GFF 坐标必须是正整数,不能是 0 或负数。
警告:坐标错误会导致下游分析(比如 reads 计数、变体注释)产生荒谬结果。一定要做边界验证,别等跑完才知道。
3.5 属性错误——第九列的坑最多
属性列是自由格式,但也有很多规则。尤其是 GTF 和 GFF3 对属性列的语法要求不一样,混用就会出问题。
常见问题:
| 错误类型 | 示例 | 后果 |
|---|---|---|
| 键值对格式错误 | gene_id ABC(缺少“=”或引号) | 解析器无法提取 ID |
| 引号不匹配 | gene_id "ABC(缺少闭合引号) | 整行属性被吞掉 |
| ID 重复 | 两个基因使用相同 ID | 工具合并或覆盖 |
| 必需属性缺失 | GTF 缺少 gene_id | 被标准工具拒绝 |
| 分号使用错误 | 属性末尾多分号或少分号 | 解析结果偏移 |
3.6 分类之间的重叠与联动
其实很多错误是交织的。比如你少写了一个制表符(结构错误),导致后面几列串位,进而出现 start 大于 end(坐标错误),同时还丢失了属性中的 gene_id(属性错误)。所以修错时最好从结构层面开始排查——结构对了,再检查语义,最后做坐标和属性验证。
我曾经踩过的坑:有一次脚本批量处理 200 个 GFF,只检查了列数没检查属性引号,结果跑完才发现一半样本的 gene_id 是空字符串。自那以后我写了一个校验脚本,把四大类错误全部自动化检测,成本低见效快。
3.7 分类总览表——快速定位错误类型
这张表把常见错误和它们所属的类别、严重程度以及修复重点列在一起,方便你对照排查。
| 错误描述 | 所属类别 | 严重程度 | 修复重点 |
|---|---|---|---|
| 列数不足/过多 | 结构错误 | 致命 | 检查分隔符,补全列 |
| feature type 不合法 | 语义错误 | 致命 | 对照规范,修改名称 |
| start > end | 坐标错误 | 致命 | 交换或验证坐标 |
| ID 重复 | 属性错误 | 严重 | 生成唯一标识 |
| 引号缺失 | 属性错误 | 严重 | 补全或修复引号 |
| strand 值错误 | 语义错误 | 严重 | 替换为 + / - / . |
| 坐标超出染色体 | 坐标错误 | 严重 | 比对 .fai 文件修正 |
| 属性键值对格式错 | 属性错误 | 中等 | 重写属性字符串 |
| 空行/注释行 | 结构错误 | 中等 | 删除或加 # |
| phase 值非法 | 语义错误 | 中等 | 修改为 0/1/2/. |
3.8 记住一条原则
不管什么错误,先确认第 9 列(属性列)的完整性。因为它最自由,最容易被误改。我个人的习惯是:写任何 GFF/GTF 处理脚本后,第一件事就是用格式校验工具跑一遍结构检查,再跑一遍属性检查。剩下的坐标和语义问题,通常靠写几个 awk 或者正则就搞定了。
一句话总结:结构决定能否被解析,语义决定工具认不认,坐标决定位置对不对,属性决定信息全不全。后面的章节,咱们针对每一类慢慢拆解修复方法。