2. FASTQ格式详解:每一行含义,质量分数编码
FASTQ 是目前测序数据存储的"通用语言"。我刚开始处理测序数据时,第一反应是——这格式怎么这么简单?就四行重复,但每一行都有门道。今天我把这四行拆开讲透,顺便把 Phred 质量编码那点事说清楚。
2.1 四行结构:从 @ 到 + 再到质量串
一个完整的 FASTQ record 固定包含 四行,顺序不能乱,缺一行都不行。看个实际例子:
@EAS139:136:FC706VJ:2:2104:15343:197392 1:N:18:1
GTTCAGGGATACGACGTTTGTATTTTAAGAATCTGTGCATCACAA
+
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
我来逐行拆解:
- 第1行(标识符行):以
@开头,后面跟着测序仪器、flowcell 坐标、cluster 位置、read 方向、filter 标志等信息。不同测序平台的标识符格式略有差异,但@是铁打的开头。 - 第2行(碱基序列行):原始测序碱基,A/T/C/G 加上 N(无法判定的碱基)。长度就是测序读长,比如 150 bp 就是 150 个字符。这一行不换行,直接连着写。
- 第3行(分隔行):以
+开头,后面可以重复第1行的标识符(可选),也可以什么都不写。我见过很多数据直接只写一个+,完全没问题。 - 第4行(质量分数行):与第2行等长的 ASCII 字符,每个字符对应一个碱基的测序质量。字符的 ASCII 值经过偏移编码后,就是 Phred 质量分数。
关键点:第4行和第2行必须等长,一个字符对一个碱基。我曾经在处理一批老数据时发现长度对不上,结果是测序仪在读取时发生了跳号——这种 record 直接丢弃就好。
2.2 质量分数编码:Phred 公式 + ASCII 偏移
质量分数到底怎么来的?其实就是一个简单的对数转换:
Q = -10 × log₁₀(P)
其中 P 是该碱基的测序错误概率。Q = 30 意味着错误概率是 0.001(千分之一),Q = 20 是 0.01(百分之一)。Q 值越高,这个碱基越可信。
但问题来了——Q 值范围通常能到 40 甚至 60,直接用数字存很浪费空间。于是设计者用 单个 ASCII 字符 来编码 Q 值,做法就是:
ASCII = Q + offset
历史上出现过两种偏移量,也就是大家常说的 Phred+33 和 Phred+64。我把它们的核心差异整理成了一张表:
| 对比维度 | Phred+33(Sanger / Illumina 1.8+) | Phred+64(Illumina 1.3–1.7) |
|---|---|---|
| 偏移量 | 33 | 64 |
| 最小 ASCII | 33(!) | 64(@) |
| 最大 ASCII | 126(~) | 126(~) |
| Q 值范围 | 0 – 93 | 0 – 62 |
| 常见平台 | Sanger、Illumina 1.8+、PacBio、ONT | 早期 Illumina(GA II, HiSeq 2000 早期) |
| 现状 | 绝对主流,几乎所有公共数据都用它 | 基本淘汰,遇到时需转换 |
我的习惯:拿到一个新数据集,第一件事就是用 head -n 4 看一眼质量行的第一个字符。如果看到 !(ASCII 33)或 #(ASCII 35),那基本就是 Phred+33。如果第一个字符是 @(ASCII 64)或 B(ASCII 66),很可能是 Phred+64。这招我用了快十年,从来没失手过。
避坑指南:我曾经从一家合作机构拿到一批 HiSeq 2000 的早期数据,质量行开头全是 B(ASCII 66)。我按 Phred+33 处理,结果所有碱基质量都飙到 33 以上,明显不对。后来一查,这居然是 Phred+64 编码!如果用错了偏移,下游变异检测会全面偏倚,数据基本报废。所以 拿到数据先确认编码类型,别想当然。
2.3 实战:如何快速判断一个 FASTQ 的编码类型
写一个简单的 Python 脚本就能搞定:
def guess_encoding(fastq_path, n_records=1000):
min_ord, max_ord = 127, 0
with open(fastq_path) as f:
for i, line in enumerate(f):
if i % 4 == 3: # 质量行
for ch in line.strip():
o = ord(ch)
if o < min_ord: min_ord = o
if o > max_ord: max_ord = o
if i // 4 >= n_records:
break
print(f"ASCII range: {min_ord} – {max_ord}")
if min_ord >= 64:
return "Phred+64"
elif min_ord >= 33 and max_ord <= 126:
return "Phred+33"
elif min_ord >= 59:
return "Phred+64 (likely)"
else:
return "Phred+33 (likely)"
逻辑其实很简单:取 1000 条 record 的质量行,算最小和最大 ASCII 值。如果最小值 ≥ 64,绝不可能是 Phred+33(因为 Phred+33 的最小值是 33,对应 !)。反之,如果最小值在 33–63 之间,就是 Phred+33。
实用原则:目前 99% 的公开数据集(SRA、ENA、DDBJ)都使用 Phred+33。如果你下载的是 2015 年之后的 Illumina 数据,基本不用怀疑。但老数据(2011–2013 的 Illumina 双端)偶尔还会碰到 Phred+64,多留个心眼总没错。
下面这张图把整个 FASTQ 的结构和两种编码的对应关系串在了一起,你可以对照着理解:
看懂这张图,FASTQ 的结构就没什么秘密了。四行从左到右、从上到下,质量分数行再分支到两种编码方式,逻辑非常清楚。
2.4 一个小技巧:从 ASCII 直观看编码
其实不用每次都跑脚本。我个人的经验是:直接用 head -n 40 看一下质量行的字符分布——
- 如果看到大量
!、"、#这些低 ASCII 字符(33–40),绝对是 Phred+33。 - 如果看到的字符全都在
@(64)以上,没有低于 64 的,那就可能是 Phred+64。 - 如果看到
I(ASCII 73)特别多,说明 Q 值集中在 40 左右,测序质量很好——无论哪种编码都是好事。
嗯,这里要注意:Phred+64 的 Q 值范围只有 0–62,对应 ASCII