引言
质控(Quality Control, QC)是生信流程中「投入产出比最高」的一步。原始测序数据里混杂着接头、低质量碱基、PCR 重复、污染序列,如果不加处理直接比对,轻则比对率下降、假变异增多,重则整个分析结论被技术噪声主导。更关键的是,质控发现问题往往能反推出上游的建库或测序问题——这是排查事故的第一现场。
但质控也最容易「过度」或「不足」。过度剪裁会丢掉真实的生物学信号(比如把真实的低复杂度区域当成污染剪掉),不足则让噪声流入下游。判断「剪到什么程度合适」,需要理解每个指标背后的含义,而非机械地套用阈值。这正是本文要解决的核心问题。
工程上,质控脚本有三个典型陷阱:一是硬编码阈值,换个物种、换个测序平台就失效;二是只跑 FastQC 出个 HTML 报告却无人解读,报告沦为摆设;三是质控与下游脱节——剪裁后的数据没有重新验证,不知道剪裁是否有效。本文会给出可复用的配置与「质控 → 验证」的闭环做法。
质控是 测序原理与数据产出 之后的第一道工程关口,也是 SAM/BAM 与 samtools 里那些质量指标的上游来源。理解它们的衔接关系,才能判断「一个低比对率到底是质控没做干净,还是别的原因」。
本文按「指标解读 → 接头识别 → 工具实战 → 剪裁策略 → 去重与污染 → 下游衔接」的顺序展开。所有命令与阈值都基于 fastp 0.23.x 与 FastQC 0.12.x,面向有经验的工程师,重点讲清「为什么这么设」。
目录
- 质控的目标与核心指标
- FastQC 报告逐项解读
- 接头与污染序列识别
- fastp 实战配置详解
- 质量剪裁:滑窗与全局策略
- 去重、UMI 与分子计数
- 双端数据的同步处理
- 污染检测与去污染
- 质控与下游流程的衔接
1. 质控的目标与核心指标
质控要回答四个问题:数据够不够(数量)、干不干净(质量)、有没有污染(来源)、能不能用(适配下游)。对应的核心指标:
| 指标 | 含义 | 健康范围 | 异常含义 |
|---|---|---|---|
| 总读段数 | 数据量 | 按深度需求 | 不足需补测 |
| Q30 比例 | 高质量碱基占比 | ≥ 85% | 测序或试剂问题 |
| GC 含量 | GC 碱基比例 | 与物种匹配 | 污染或偏倚 |
| 接头含量 | 含接头读段比例 | < 5% | 片段过短 |
| 重复率 | PCR 重复读段比例 | 随深度变化 | 循环过多/输入量低 |
| N 碱基比例 | 无法识别的碱基 | < 1% | 测序失败 |
这里有个重要的认知:指标的「健康范围」依赖于场景。同样是 30% 的重复率,在全基因组测序里是正常的(高深度必然有随机重复),在单细胞数据里可能提示严重问题(细胞数少、扩增过度)。所以不要背死阈值,而要理解「什么导致了它」。
以 GC 含量为例。人类基因组平均 GC 约 41%,如果样本 GC 显示 60%,可能有两种解释:一是样本来自高 GC 物种(如某些细菌),这是正常的;二是样本被高 GC 的污染物(如支原体)污染。区分方法是看 GC 分布的形状——正常样本是单峰且与理论分布吻合,污染会呈现双峰或偏移。
2. FastQC 报告逐项解读
FastQC 是质控的事实标准,输出 11 个模块的 HTML 报告。逐个模块的解读要点:
fastqc -t 8 -o qc/ sample_R1.fastq.gz sample_R2.fastq.gz
# 批量处理
fastqc -t 8 -o qc/ *.fastq.gz
# 汇总多个报告(推荐)
multiqc qc/ -o qc/multiqc_report.html
Per base sequence quality(每碱基质量):最重要的一张图。横轴是读段位置,纵轴是质量值。健康数据应该是「两端低、中间高」的平缓曲线。如果整条曲线在某个位置断崖式下跌,说明该循环测序失败(常见于读长过长或试剂耗尽)。
Per sequence quality scores(每读段质量):读段平均质量的分布。正常应该是单峰且偏向高分。如果出现明显的低质量峰,说明有大量读段整体质量差。
Per base sequence content(每碱基组成):A/T/C/G 的比例随位置变化。健康数据前几个碱基可能有波动(随机引物偏好),之后应稳定在 25% 附近。如果整条读段严重偏离,可能是污染或文库问题。
Adapter content(接头含量):随读段位置累积的接头比例。读段末端接头含量升高是正常的(短片段读完样本后读到接头),但如果从读段开头就高,说明片段极短,建库严重失败。
Sequence duplication levels(序列重复水平):重复读段的比例。高重复可能来自 PCR 过度扩增(应去重)或高表达基因(RNA-seq 中正常)。FastQC 默认只统计前 100k 读段,对高深度数据会高估重复率,需注意。
Overrepresented sequences(过表达序列):出现频率异常的序列。可能是接头、rRNA、或高丰度基因。这是发现污染的第一线索。
解读报告的关键心态是「看模式而非看红叉」。FastQC 会给每个模块标红/黄/绿,但这些标记的阈值是通用的,对某些场景(如 RNA-seq 的 GC 偏倚、长读数据)会误报。有经验的工程师会结合物种、文库类型、下游用途综合判断。
3. 接头与污染序列识别
接头(adapter)是最常见的「污染物」,也是最好处理的。识别接头的方法是「找读段末端的固定序列」:
Illumina TruSeq 接头(部分):
Read1 adapter: AGATCGGAAGAGCACACGTCTGAACTCCAGTCA
Read2 adapter: AGATCGGAAGAGCGTCGTGTAGGGAAAGAGTGT
通用核心: AGATCGGAAGAGC
Nextera 接头: CTGTCTCTTATACACATCT
如果 FastQC 的 Overrepresented sequences 里出现 AGATCGGAAGAGC 开头的序列,基本可以确定是接头污染。处理方式有两种:
- 自动检测 + 剪裁:
fastp默认启用接头自动检测,会比对已知接头库并剪除。 - 显式指定序列:非标准建库试剂盒需要手动提供接头序列。
# fastp 显式指定接头序列(非标准试剂盒)
fastp -i in.fq -o out.fq \
--adapter_sequence AGATCGGAAGAGCACACGTCTGAACTCCAGTCA \
--adapter_sequence_r2 AGATCGGAAGAGCGTCGTGTAGGGAAAGAGTGT
除接头外,还有几类「非接头但需处理」的序列:
- Poly-G / Poly-A:NovaSeq 的 two-color 化学在信号缺失时会读成 G,导致读段末端出现连续 G。
fastp用--trim_poly_g处理。 - Poly-X:某些平台或文库会有连续相同碱基,
--trim_poly_x处理。 - rRNA 序列:RNA-seq 中未去除的核糖体 RNA,占比可能高达 50%,需在建库时用 rRNA depletion 或分析时过滤。
判断「剪多少」有个实用原则:剪到固定序列消失为止,但保留读段至少 30 bp。太短的读段比对不上(会被比对工具丢弃),剪得太狠反而浪费数据。fastp 的 --length_required 30 就是干这个的。
4. fastp 实战配置详解
fastp 是当前最主流的 FASTQ 预处理工具(C++ 实现,比 Trimmomatic 快数倍,且自带报告)。一个生产级配置:
fastp \
-i sample_R1.fastq.gz -I sample_R2.fastq.gz \
-o clean_R1.fastq.gz -O clean_R2.fastq.gz \
--detect_adapter_for_pe \
--cut_front --cut_tail --cut_window_size 4 --cut_mean_quality 20 \
--qualified_quality_phred 15 \
--unqualified_percent_limit 40 \
--n_base_limit 5 \
--length_required 36 \
--trim_poly_g \
--dedup \
--thread 8 \
--json sample.fastp.json --html sample.fastp.html \
2> sample.fastp.log
逐参数解释:
| 参数 | 作用 | 取值建议 |
|---|---|---|
--detect_adapter_for_pe | 双端接头自动检测 | PE 数据必开 |
--cut_front / --cut_tail | 从两端滑窗剪裁低质量 | 配合窗口与均值阈值 |
--cut_window_size 4 | 滑窗大小 | 4 是默认,够用 |
--cut_mean_quality 20 | 窗口平均质量阈值 | 20(Q20)起步 |
--qualified_quality_phred 15 | 单碱基合格线 | 15(Q15) |
--unqualified_percent_limit 40 | 允许低质量碱基比例 | 40% |
--length_required 36 | 最短保留长度 | 36-50 bp |
--dedup | 去重 | 高深度 WGS 慎用 |
--dedup 需要特别注意:它会直接删除重复读段,而下游 picard MarkDuplicates 需要「标记」而非删除(因为某些重复是真实的生物学信号,如高覆盖的扩增子)。所以常规 WGS 流程不应在 fastp 阶段去重,而是留给 Picard 标记。只有在不需要考虑生物学重复的场景(如快速筛查)才用 --dedup。
另一个关键参数是 --qualified_quality_phred(默认 15)。这是「单个碱基是否算合格」的阈值,与 --unqualified_percent_limit(一条读段里不合格碱基的比例上限)配合:一条读段中超过 40% 的碱基低于 Q15,则整条丢弃。这两个参数的组合决定了「激进」还是「保守」。
5. 质量剪裁:滑窗与全局策略
质量剪裁(trimming)的核心是「在哪个位置切」。两种主流策略:
全局阈值(global):从两端逐碱基检查,遇到第一个低于阈值的碱基就切掉。简单但激进——一个孤立的低质量碱基会导致后面全被切掉,即使后面质量又变好了。
滑窗(sliding window):在窗口内计算平均质量,平均低于阈值才切。fastp 的 --cut_front/--cut_tail 就是滑窗。它更平滑,不会因为单个碱基波动就大段剪裁。
读段质量: Q35 Q38 Q40 Q12 Q39 Q40 Q41 ...
全局策略: ────────────┘ 从 Q12 处切断(后面全丢)
滑窗(4): 窗口[Q38,Q40,Q12,Q39]均值=32 > 20,保留;继续滑动
实践建议:
- 默认用滑窗(
--cut_front --cut_tail),它对绝大多数数据都稳健。 - 只在读段末端质量崩塌时加大力度:如果 FastQC 显示末端质量 < Q20,可以调低
--cut_mean_quality或增加--cut_tail_window_size。 - 不要盲目追求「全 Q30」:强行剪到只剩高质量区,会损失大量数据且引入位置偏倚(所有读段都从同一位置开始)。质量值与比对工具是配合的,Q20 的碱基在比对中仍有价值。
还有一个常被忽略的剪裁:前几个碱基的处理。Illumina 读段前 1-3 个碱基常因随机引物而有组成偏倚,--cut_front 会处理。但如果数据本身没问题,强行剪前几碱基反而丢失信息。
剪裁效果的验证方法是「剪裁后再跑一次 FastQC」:看质量曲线是否变平、接头是否消失、总读段数损失多少。如果损失超过 20%,需要重新评估阈值是否过严。
6. 去重、UMI 与分子计数
去重(deduplication)处理的是 PCR 扩增引入的「伪重复」:同一个原始 DNA 分子被扩增成多个拷贝,测序后看起来像「多个分子」。如果不处理,会虚高覆盖度并产生假变异(一个错误被复制成「多数票」)。
两种去重时机:
| 工具 | 时机 | 方式 | 适用 |
|---|---|---|---|
fastp --dedup | 比对前 | 按序列精确匹配删除 | 快速筛查 |
picard MarkDuplicates | 比对后 | 按坐标+方向标记 | 标准 WGS |
samtools markdup | 比对后 | 按坐标标记(更快) | 高通量 |
umi_tools dedup | 比对后 | 按 UMI 分组 | 低输入/单细胞 |
为什么标准流程在比对后去重? 因为比对前的「序列完全相同」不等于「来自同一分子」——高覆盖区可能有多个真实的相同片段。比对后结合坐标、方向、CIGAR 一起判断,准确性更高。
UMI(Unique Molecular Identifier) 是低输入量场景的关键。建库时给每个原始分子加上一段随机序列(如 8-12 bp),扩增后即使有多个拷贝,它们的 UMI 也相同,可以据此合并计数:
# UMI 处理三步:提取 → 比对 → 按 UMI 去重
umi_tools extract --bc-pattern=NNNNNNNNNN --stdin in.fq --stdout umi.fq
# ... 比对到 BAM ...
umi_tools dedup -I aln.bam -S dedup.bam --output-stats=umi_stats
UMI 的工程细节:UMI 本身也可能有测序错误,所以 umi_tools dedup 默认允许 1 个碱基的 UMI 差异(--edit-distance-threshold 1)来合并「同一分子的错误 UMI」。这个阈值的设置需要权衡——太大(如 2)会把不同分子错误合并,太小则同一个分子被拆成多个。
7. 双端数据的同步处理
双端(PE)数据的质控有一个铁律:R1 和 R2 必须同步。如果对 R1 剪了 10 个碱基而对 R2 没剪,两条读段的坐标就错位了,比对时会产生错误的插入片段长度,甚至比对失败。
错误做法(不同步):
R1: ATCGATCGATCG---- (剪掉末端 4 个)
R2: TTTTGGGGCCCCAAAA (未剪)
→ R1 和 R2 长度不等,坐标错位
正确做法(fastp 自动同步):
R1: ATCGATCG----
R2: TTTTGGGG---- (同一位置同步剪裁)
fastp 对 PE 数据会自动同步剪裁,这是它的核心优势之一。但要注意几个细节:
--detect_adapter_for_pe:PE 接头检测比 SE 复杂,因为接头可能在 R1 末端、R2 末端或两者都有。这个参数让 fastp 从两端互相验证。--unpaired输出:当一条读段被丢弃而另一条保留时,剩下的「孤儿读段」默认会被丢弃(因为无法配对)。可以输出到--unpaired文件,用于某些不需要配对的场景(如组装)。- 读段顺序一致性:剪裁后的 FASTQ 中,R1 和 R2 的读段顺序必须严格对应。
fastp保证这一点,但自己写脚本时容易出错。
对于 Trimmomatic 用户,对应的是 PE 模式加 -baseout 参数;但 fastp 的接口更简洁且更快,新项目建议直接上 fastp。
8. 污染检测与去污染
污染(contamination)比接头更隐蔽,也更危险。常见来源:
- 交叉污染:多样本混测时 index 串扰,或实验室操作污染;
- 微生物污染:细胞系被支原体(Mycoplasma)污染是细胞实验的经典问题;
- 人源污染:小鼠样本混入人 DNA(或反之);
- 环境 DNA:低生物量样本(如空气、水)容易被环境微生物主导。
检测方法:
# 方法1:提取未比对上的读段,做物种分类
samtools view -f 4 aln.bam | awk '{print $10}' > unmapped.fa
# 用 Kraken2 分类
kraken2 --db standard --report report.txt unmapped.fa
# 方法2:用 FastQ Screen 快速筛查
fastq_screen --conf fastq_screen.conf sample.fastq.gz
FastQ Screen 的思路很巧妙:把样本读段同时比对到多个参考基因组(人、小鼠、细菌、真菌、病毒等),看有多少读段匹配到「不应该匹配」的物种。如果人类样本有 30% 的读段匹配到大肠杆菌,说明有严重污染。
支原体检测是细胞系实验的必查项。支原体基因组小(约 0.6-1.4 Mb),污染后会在数据里留下低比例但稳定的读段。可以用专门的工具(如 MycoSNP)或直接比对到支原体参考基因组检测。
去污染的策略取决于污染程度:
| 污染比例 | 策略 |
|---|---|
| < 5% | 记录,忽略(不影响结论) |
| 5-30% | 比对后过滤污染读段(如 samtools view 排除污染 contig) |
| 30-70% | 分析结果需谨慎,重新建库 |
| > 70% | 数据不可用,必须重做 |
关键原则:污染检测应在流程早期做,而不是结果出来才发现。把 FastQ Screen 或 Kraken2 作为流程的可选步骤,能及早暴露问题。
9. 质控与下游流程的衔接
质控不是孤立的步骤,它的输出直接影响下游。几个必须衔接好的点:
一是「剪裁参数与比对参数」的配合。如果剪裁去掉了读段末端,比对工具就不该再对末端做宽松处理;反之亦然。例如 BWA-MEM 的 -T(最小比对得分)与剪裁强度需要匹配——剪得太狠导致读段变短,可能过不了比对阈值而被丢弃。
二是「质量值过滤的重复」。质控阶段已经过滤了低质量碱基,下游再用严格的 -q 过滤一遍,是重复劳动且可能过度。建议把质量过滤集中在质控阶段,下游用宽松阈值(如 samtools view -q 10)兜底即可。
三是「QC 指标的传递」。剪裁后的数据必须重新验证:
# 质控闭环:剪裁后重新评估
fastqc -o qc_after/ clean_R1.fastq.gz
multiqc qc/ qc_after/ -o multiqc_combined.html
# 关键对比:剪裁前后
# - 总读段数:损失比例(应 < 20%)
# - Q30 比例:是否提升
# - 接头含量:是否归零
# - 读长分布:是否出现异常截断
一个成熟的流程会把「质控报告」作为流程的产出物之一,与比对率、覆盖度等指标一起汇总到 MultiQC,形成样本级的质量档案。这样当某个样本的分析结果异常时,可以回查它的 QC 历史。
最后给一组「质控通过」的参考基线(人类 WGS,PE150):
Q30 比例 ≥ 85%
接头污染 < 5%
比对率 ≥ 95%(BWA-MEM)
重复率 < 20%(30x)
平均覆盖深度 ≥ 30x
覆盖均匀性 90% 位点 ≥ 10x
达不到这些基线时,先排查原因,而非硬着头皮往下跑。
权衡取舍
| 决策点 | 方案 A | 方案 B | 建议 |
|---|---|---|---|
| 剪裁策略 | 滑窗(平滑) | 全局(激进) | 默认滑窗,末端崩塌时调参 |
| 去重时机 | 比对前(快) | 比对后(准) | 标准 WGS 比对后,UMI 场景专用 |
| 质量阈值 | 严格(Q30) | 宽松(Q20) | 按下游容错度定,勿一刀切 |
| 污染处理 | 过滤读段 | 重做实验 | < 30% 过滤,> 30% 重做 |
| 工具 | fastp(快、全) | Trimmomatic(老牌) | 新项目用 fastp |
| 报告 | 单样本 HTML | MultiQC 汇总 | 批量项目必用 MultiQC |
常见坑清单
- R1/R2 剪裁不同步:手动脚本只处理一条,导致坐标错位;用 fastp 的 PE 模式自动同步。
- fastp 阶段误去重:
--dedup删除了需要下游标记的重复;标准 WGS 交给 Picard。 - 阈值硬编码:把人类参数用到植物/微生物上,剪裁过度或不足;按物种与文库类型调参。
- 只看红叉不看模式:FastQC 的通用阈值对特殊场景误报;结合场景解读曲线形状。
- 忽略 Poly-G:NovaSeq two-color 化学的 Poly-G 未处理,导致末端质量虚低;开
--trim_poly_g。 - 剪裁后不验证:不知道剪掉了多少、效果如何;剪裁后重跑 FastQC 对比。
- 读段剪得过短:
--length_required设得太高,大量读段被丢;一般 36-50 bp 即可。 - 忽略污染筛查:结果异常才发现污染;把 FastQ Screen/Kraken2 纳入早期流程。
- UMI 阈值不当:edit distance 设太大合并了不同分子,太小则拆分同一分子;默认 1 通常合适。
- QC 指标不落盘:样本质量信息丢失,事后无法追溯;用 MultiQC 汇总并归档。
小结
FASTQ 质控的价值不在于「跑了几个工具」,而在于「理解了数据的健康状态并据此做决策」。FastQC 帮你看见问题,fastp 帮你处理问题,而「剪到什么程度」的判断来自对下游用途的理解——这是工具无法替代的部分。
工程上最该建立的习惯是「质控闭环」:原始数据 QC → 剪裁 → 剪裁后 QC → 指标归档。没有验证的剪裁等于没做剪裁,因为你不知道它是否有效、是否过度。把 QC 报告作为流程的标准产出,与样本元数据一起保存,是排查问题时的第一手资料。
下一步是 序列比对 ——干净的数据进入比对环节,你会看到质控的质量如何直接决定比对率与后续分析的可信度。如果你的数据质量指标异常,先别急着调比对参数,回头看看质控这一环是否还有空间。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。