FASTQ 文件结构深度解析
做生信的人每天都会和 FASTQ 打交道。我第一次接触这格式的时候,以为它跟 FASTA 差不多,结果被质量值那串乱码坑了好几天。今天咱们就把 FASTQ 的四行结构彻底拆开,看看每一行到底在说什么。
四行结构:一个记录就是一个方块
你随便打开一个 FASTQ 文件,看到的是一块一块的文本。每一块代表一条测序读段(read),固定由四行组成:
- @头信息行 – 以 @ 开头,后面跟着读段的标识符和可选描述
- 序列行 – 碱基序列(A、C、G、T、N)
- +行 – 通常只有一个加号,有时会重复头信息
- 质量值行 – 每个碱基对应的质量分数 ASCII 码
我可以放一个实际例子,你一看就明白:
@SEQ_ID 1:1101:12345:54321/1
GATTTGGGGTTCAAAGCAGTATCGATCAAATAGTAAATCCATTTGTTCAACTCACAGTTT
+
!''*((((***+))%%%++)(%%%%).1***-+*''))**55CCF>>>>>>CCCCCCC65
嗯,这四行必须严格按顺序出现,中间不能有空行。少了任何一行,整个记录就废了。我在项目里见过有人用文本编辑器打开 FASTQ 时,不小心删了 + 行,结果下游工具报了一堆莫名其妙的错误。
@头信息行 – 读段的身份证
头信息行以 @ 开头,后面紧跟仪器标识符、流动槽坐标、条码信息等等。不同测序平台产出的格式略有差异,但核心字段大同小异。
我最常见到的 Illumina 头信息长这样:
@EAS139:136:FC706VJ:2:2104:15343:197393 1:Y:18:ATCACG
用冒号和空格分隔的字段,我来拆解一下:
| 字段 | 含义 | 示例值 |
|---|---|---|
| 仪器 ID | 测序仪唯一标识 | EAS139 |
| 运行号 | 同一次 run 的编号 | 136 |
| 流动槽 ID | Flow cell 的编号 | FC706VJ |
| 泳道 | Lane 编号 | 2 |
| Tile | Flow cell 上的 Tile 编号 | 2104 |
| X | 簇在 Tile 上的 X 坐标 | 15343 |
| Y | 簇在 Tile 上的 Y 坐标 | 197393 |
| 配对/过滤 | 读段编号(1 或 2)和是否通过 filter | 1:Y |
| 控制位 | 控制碱基指标 | 18 |
| 样本条码 | index 序列 | ATCACG |
小心头信息里的空格和冒号 我曾经遇到过一个 FASTQ 文件,头信息行末尾多了一个空格,结果某款比对工具直接把整条记录丢弃了。解析时最好用字符串 split 而不是正则截取,容错性更高。
序列行 – 碱基字符串
第二行就是测出来的碱基序列。长度通常固定(比如 150 bp),但双端测序时两个文件长度可能不同。这里要注意:
- 只允许出现 A、C、G、T、N(模糊碱基),偶尔有 . 或 - 但标准格式没有。
- 序列不换行,一气呵成。如果序列特长,有些工具会自动分行?不会!FASTQ 规定序列只有一行,不能切分。
- 我在项目中接过一批奇怪的数据,序列行里混了小写字母。虽然技术上测序碱基不区分大小写,但很多比对软件只认大写。所以我习惯用
seq = seq.upper()提前做归一化。
+行 – 分隔符(但有时也带信息)
第三行通常只有一个加号,没有别的内容。但有些工具会把头信息行重复一遍,比如:
+EAS139:136:FC706VJ:2:2104:15343:197393 1:Y:18:ATCACG
这个加号 + 空行 + 再加内容,其实是历史遗留。当年的开发者觉得这样更对称。我个人的习惯是:解析时先检查 + 行是否以 + 开头,然后直接忽略剩余内容。你不需要费力去匹配头信息是否一致——大多数质量控制工具只看行号,不比对。
小技巧 如果你在写 Python 脚本逐行读取 FASTQ,可以用迭代器按四行一组取。遇到行数不够 4 的倍数,大概率文件损坏,要报错。
质量值行 – 碱基准确度的分数
第四行长得跟序列行一样长,但每个字符对应一个质量分数。这串字符看着像乱码,其实是 ASCII 编码的 Phred 质量分数。质量分数的定义:
Q = -10 * log₁₀(p)
其中 p 是该碱基被测错的概率。Q 值越高,越可靠。常见的 Q 值范围是 0~40,对应错误概率从 1 到 1/10000。
编码方式主要有两种(核心区别是 ASCII 偏移量):
| 类型 | ASCII 偏移 | Q 值范围 | ASCII 字符范围 |
|---|---|---|---|
| Sanger / Illumina 1.8+ | 33 | 0~41 | ! 到 J |
| Illumina 1.3~1.7 | 64 | 0~62 | @ 到 ~ |
现在绝大多数公共数据库要求 Sanger(Phred+33)。我几年前从老的 Illumina 下载过一批 1.3 格式的数据,没做转换直接输入到 GATK,结果质量值全部偏移,差点导致变异检测失败。从那以后,我每条数据都会先用工具筛查质量编码方式。
你可以在 Linux 下用这个命令快速判断:
head -n 1000 sample.fastq | awk 'NR%4==0' | od -An -tuC | awk '{for(i=1;i<=NF;i++) print $i}' | sort -n | head -3
看最小的 ASCII 值:如果大于 64,就是 Phred+64;小于 64 且大于 33,就是 Phred+33。嗯,这个小技巧救我很多次。
文件扩展名与压缩格式
一个完整的 FASTQ 文件名至少包含 .fastq 扩展名,有时也简写成 .fq。但生信数据动不动几十 GB,不压缩根本没法传输。常见的压缩搭配:
.fastq.gz或.fq.gz— gzip 压缩,最通用.fastq.bz2— bzip2 压缩,压缩率更高但解压慢.fastq.xz— xz 压缩,压缩率极高,我很少见
注意:不要用 zip 或 7z,因为很多生信管道不支持流式读取。gzip 的优势在于可以管道传输:
zcat sample.fastq.gz | head -n 4
另外有些机构会打包成 .tar.gz,里面放多个 FASTQ。我个人建议尽量保持单文件压缩,避免解包之后再找文件的麻烦。
核心要点 FASTQ 结构千篇一律,但细节(头信息格式、质量编码、压缩方式)一不留神就踩雷。解析前先做完整性检查:行数是否是 4 的倍数、每行长度(序列行与质量行是否一致)、头信息是否以 @ 开头。
一张图看懂四行结构
下面我用一个简单的图展示 FASTQ 记录的组织方式。你把它想象成一层层堆叠的方块,每个方块必须完整。
经验总结 你只要记住这个四行结构,就能手动写出 FASTQ 解析器。但我建议别造轮子——用 BioPython 的 SeqIO 模块,一行代码搞定:for record in SeqIO.parse("sample.fastq", "fastq"):
好了,FASTQ 的结构就这些。接下来你可以放心去处理文件扩展名和压缩格式的适配问题了。记住:先检查行数、再检查长度、最后评估质量编码偏移。三步走,稳得很。