第4章 头信息格式标准与规范

FASTQ 的第一行,也就是 @行,看似简单,其实坑不少。我刚入行那会儿,以为每行 @ 后面随便写个 ID 就行,结果被下游工具狠狠教育了一回——有些程序只认特定格式,不匹配就报错。今天咱们就把这 @ 行的门道捋清楚。

4.1 @ 行通用结构

每条记录都以 @ 开头,紧接着是序列标识符(ID),后面可以跟一个或多个描述字段,用空格隔开。说白了:@ID 可选描述

举个最简单的例子:

@EAS139:136:FC706VJ:2:2104:15343:197393 1:Y:18:ATCACG
CTCTTTCCCTCCTCTTTTTCTCTCCCTCTCCTTTCCTTTCCTTTCTCCTTTTCTCCTT
+
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

这里面 @ 后面跟了一长串用冒号分开的字段,最后跟了一个空格和一个描述。你想想看,如果程序按照固定的分隔符解析,多一个少一个冒号都会出问题。我曾经在接手一批第三方数据时,发现所有 @ 行末尾都带了一个看不见的制表符,导致 split 出错了——那个排查过程,一言难尽。

个人习惯:我写脚本解析 FASTQ 头时,总会先打印前 5 行的原始字节,确认有没有不可见字符。省得在后面踩坑。

4.2 字段分隔约定

各大测序平台使用的分隔符并不统一。我整理了一下常见的情况:

平台 / 工具 主要分隔符 典型字段内容
Illumina CASAVA 冒号 (:) + 空格 instrument:flowcell:lane:tile:x:y #index/readnum
PacBio CCS 斜杠 (/) moleculeId/readnum
Oxford Nanopore 下划线 (_) 或空格 readId runId start_end
Sanger / 传统 FASTA 空格 + 自由文本 sequenceId free description

你可能会问:为什么搞这么多花样?说白了,每个平台都有自己需要记录的元数据——Illumina 要记机器、芯片、坐标;PacBio 要记分子编号;Nanopore 要记通道和时间。这些字段挤在一行里,就得靠统一的分隔符来区分。

我个人建议,在写解析器时,不要死磕一种分隔符。最好先检测冒号、斜杠、下划线出现的频率,自动判断格式。我在一个项目中用 re.split(r'[:\s_/]+', header) 来做通用拆分,效果还不错,但要注意空字段的处理。

另外,Illumina 的 # 符号也很特殊。它后面跟着的是样本 index(多重索引时的 barcode 序列),再跟斜杠和读段序号。比如 #ATCACG/1。如果 index 不存在,可能会直接写成 #0/1 或干脆省略。嗯,这里要注意,有些工具遇到 #0 时直接报错——我遇到过,因为自认为“0 代表无”是常识,但工具不认。

4.3 常见头信息变体

别看只是一行字符串,不同厂家、不同版本之间的头信息变体多得让人头疼。我挑几个最常遇到的来说。

Illumina CASAVA 1.8+

这是目前最常见的格式。完整结构如下:

@EAS139:136:FC706VJ:2:2104:15343:197393 1:Y:18:ATCACG

各部分含义:

  • EAS139 – 测序仪 ID
  • 136 – flowcell 编号
  • FC706VJ – flowcell 序列号
  • 2 – lane 号
  • 2104 – tile 号
  • 15343 – x 坐标
  • 197393 – y 坐标

空格后面是质量控制字段,冒号分隔:1:Y:18:ATCACG

  • 1 – 读段序号(1 或 2)
  • Y – 过滤器是否通过(Y/N)
  • 18 – 对照文库索引值(control number)
  • ATCACG – 样本 index 序列
避坑提醒:我曾经在分析老版本 Illumina 数据时,遇到头信息末尾没有 index 序列,而是直接用 #0/1 表示。后来才发现,不同版本的 CASAVA 对 index 缺失的处理不一样。建议先查看数据配套的 RunInfo.xml 或 SampleSheet.csv 来确认真实格式。

PacBio 的变体

PacBio 的 CCS (Circular Consensus Sequencing) 头信息简洁很多:

@m64012_210805_170248/3459256/ccs

斜杠分隔三个部分:仪器 run ID / 分子编号 ZMW hole number / 读段类型(ccs 表示一致性序列)。如果是 subreads,可能类似 /3459256/0_10000 记录起止位置。

我个人觉得 PacBio 的头信息最容易解析——因为字段少,分隔统一,基本不会出错。

Oxford Nanopore 的变体

ONT 的头信息看起来最“乱”,因为里面包含了很多冗余信息:

@f7dede3a-2b9f-4f6e-8e7a-0a5bcf5b3c5c runid=xxxx sampleid=yyy read=1 ch=123 start_time=2024-08-01T12:00:00Z

它实际上是一个 UUID 作为 read ID,后面跟 key=value 形式的键值对。这种格式的好处是扩展性极强,坏处是解析起来得用正则匹配键名。

有一次我拿着 ONT 的数据去跑一个只认 Illumina 格式的比对工具,结果工具直接把描述字段里的 runid= 当作 alignment 的一个 flag 给吞掉了——你说冤不冤?所以对接不同工具时,一定要先看文档。

Sanger / NCBI 传统格式

这种格式最简单:

@SRR001666.1 1858966 HWI-EAS339_3:3:1:1614:1095 length=36

空格前面是 run_accession.序列号,后面是自由文本说明。NCBI 的 SRA 数据大量使用这种格式。我建议用 .split(maxsplit=1) 来拿 ID,后面整个字符串当作注释存储,不要自作聪明去拆解。

核心原则:写头信息解析逻辑时,永远保留原始字符串的副本。因为很多下游步骤需要回头重新提取信息,如果一开始就硬拆成固定字段,后面遇到变体就傻眼了。

知识结构总览

下面这张图整理了我上面讲的几种主要头信息变体及其解析路径。你可以把它当作一个快速参考:

FASTQ @行 知识结构 @ 行 分隔符类型 冒号 / 空格 / 斜杠 / 下划线 ID + 可选描述 @ID description 元数据变体 仪器 / 芯片 / 坐标 / index Illumina 冒号 + # + 斜杠 PacBio 斜杠分隔三字段 Oxford Nanopore UUID + key=value Sanger / NCBI 空格 + 自由文本 解析要点 1. 保留原始字符串副本,不要拆解后丢弃 2. 根据分隔符出现频率自动判断格式 3. 对接工具前务必查看其预期的头信息规范

这张图展示了 @ 行的三大核心维度:分隔符、ID+描述结构、以及具体的元数据变体。我画的时候特意把每个平台常用的分隔符标了出来——你可以快速看到,Illumina 是冒号的大户,PacBio 全靠斜杠,Nanopore 则是一套自成体系的 key-value。

写解析器的时候,我一般会按“先识别平台 → 再按对应规则拆分 → 最后提取关键字段”这个流程来。如果遇到未知格式,我会把整行存进一个 field 中,然后尝试匹配已知模式。嗯,说起来简单,真遇到那种混用冒号和空格的奇葩数据,还是得手动调。

最后说一句,头信息的标准化一直在演进。Illumina 在最新版 BCL2FASTQ 中已经开始用 @instrument:run:flowcell:lane:... #index,但许多旧数据还是老格式。我的建议是:永远留一手,做好格式兼容。