测序数据从公司拷回来,或者自己用 bcl2fastq 跑完下机,第一个动作往往是 vim 打开 fastq 瞄两眼,然后被满屏的 ACGT 劝退。真正靠谱的做法是:在 Linux(Ubuntu)上先跑一遍 FastQC,把每个样本的碱基质量、GC 分布、接头污染、重复序列这些指标摸清楚,再用 MultiQC 把几十甚至上百份报告合并成一张总览页面。这一套组合拳几乎是我见过的所有测序项目里最标准的“入场检查”,成本低、上手快,但对后续是不是要 trim、要不要重测、要不要换建库方式,影响极大。
这篇内容面向的是刚接触生信的实验人员、刚转行做 NGS 分析的同学,以及需要在服务器上批量处理数据的运维或平台同事。我会把 FastQC 与 MultiQC 在 Ubuntu 上的安装路线、参数含义、批量化脚本、报告读法、常见报错排查都过一遍,尽量做到你照着敲就能跑起来,跑起来之后也知道自己在看什么。
1. 先弄明白 FastQC 和 MultiQC 各自管什么
1.1 FastQC 的定位:单样本的“体检报告”
FastQC 是 Babraham Institute 出的一个 Java 写的测序质控工具,输入是 fastq(也支持 sam/bam,甚至纳米孔的长读长数据),输出是每个样本一份 HTML 报告加一个 zip 压缩包。它的核心价值在于把一堆肉眼根本看不出来的统计规律,用图表的方式摊在你面前。
它默认会跑十来个模块:Basic Statistics、Per base sequence quality、Per tile sequence quality、Per sequence quality scores、Per base sequence content、Per sequence GC content、Per base N content、Sequence Length Distribution、Sequence Duplication Levels、Overrepresented sequences、Adapter Content、Kmer Content。每个模块给出 PASS / WARN / FAIL 三档判定,遇到 FAIL 的模块就得认真看看到底是数据本身的问题,还是建库环节留下的痕迹。
这里有个很多人忽略的点:FastQC 是“单样本视角”,它一次只能处理一个文件并生成一份报告。你手里有 96 个样本,它就生成 96 份报告。它本身不带跨样本比较能力,也不做数据清洗,仅仅告诉你“这份数据现在长什么样”。
1.2 MultiQC 的定位:把 N 份报告拧成一张总览
MultiQC 解决的问题正是 FastQC 留下的空白。它由 Seqera 团队维护,是个 Python 工具,能扫描一个目录树,自动识别其中几十种生信工具的输出文件(FastQC、fastp、Trim Galore、Salmon、STAR、Qualimap、Picard、Samtools 等等),然后把它们汇总成一个 HTML 报告。
我最看重 MultiQC 的三点:第一,它会把样本名、总 reads 数、Q30 比例、GC 含量这些关键指标抽成一张 General Statistics 表,你可以直接按 Q30 排序,一眼看出哪些样本拖后腿;第二,它会按模块维度把所有样本叠在一起画图,比如 Per base sequence quality 会画成一张包含全部样本的曲线图,比一张张翻 HTML 高效太多;第三,它会顺手输出一份multiqc_data目录,里面的 txt 和 json 可以直接喂给 pandas 或者导入 Excel,方便做后续的筛选和报表。
1.3 为什么这两个工具非得搭配着用
单独用 FastQC,在样本少的时候还行,样本一多就变成了“手动翻报告”的体力活,而且人眼容易疲劳,看漏几个异常样本很常见。单独用 MultiQC 也不行,它本身不做质控计算,所有数据都来自其他工具的输出,没有 FastQC 就没东西可汇总。
所以标准的流程是:FastQC 生成原始报告 → MultiQC 扫描这些报告 → 生成总览。我在实际项目里还会把 MultiQC 的产物作为“门禁”,比如规定 Q30 低于 80% 的样本必须先做 trim 再重新质控,达到门槛才允许进入比对环节。这个门禁放在流程里,比事后靠人盯要可靠得多。
2. Ubuntu 上装 FastQC 和 MultiQC 的三条路线
2.1 三条安装路线对比与选型建议
在 Ubuntu 上装这两个工具,主流有三条路:系统包管理器 apt、Conda 生态、官方二进制或 pip。它们各有取舍,我列个表你按自己环境挑。
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| apt | 一条命令,系统级可用 | 仓库版本通常偏旧,MultiQC 不一定有 | 临时试用、教学演示 |
| Conda(推荐) | 版本可控,依赖自动解决,能锁环境 | 首次装 Miniforge 稍慢,磁盘占用大 | 生产分析、多人协作服务器 |
| 官方包 / pip | 拿到最新版,轻量 | 需要自己管 Java 和 Python 依赖 | 单机、有经验的用户 |
如果你的服务器是多个人共用,我强烈建议走 Conda 路线,并且用环境隔离。原因很实际:FastQC 依赖 Java,MultiQC 依赖 Python,而服务器上往往还跑着别的老流程,系统级的 Java 和 Python 版本一旦被你改了,可能把别人的流程搞崩。环境隔离是成本最低的“防背锅”手段。
2.2 Conda 路线完整操作与 Java 依赖处理
先说 Java。FastQC 从 0.12.0 开始要求 Java 11 及以上,0.11.x 系列 Java 8 就能跑。如果你走 Conda 安装,bioconda 会自动把 openjdk 作为依赖装进同一个环境,你完全不用操心。但如果走官方二进制包,就得自己装:
sudo apt update sudo apt install -y openjdk-17-jre-headless java -version注意这里装的是-headless版本,不带图形界面。原因后面排查章节会讲,FastQC 在纯命令行服务器上偶尔会因为没有图形环境报HeadlessException,装 headless 版本能规避一大类问题。
接下来装 Miniforge,它默认使用 conda-forge 渠道,比 Miniconda 少很多许可证上的烦心事:
curl -L -O https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh bash Miniforge3-Linux-x86_64.sh -b -p $HOME/miniforge3 source $HOME/miniforge3/etc/profile.d/conda.sh-b是静默安装,-p指定安装路径。装完之后把初始化脚本写进.bashrc,否则每次开新终端都得手动 source 一遍。
然后就到了关键的一步,创建环境:
mamba create -n qc -c conda-forge -c bioconda fastqc multiqc -y mamba activate qc fastqc --version multiqc --version渠道顺序这里值得多说一句。现在的推荐写法是把conda-forge放在bioconda前面,因为 bioconda 里的大量包依赖 conda-forge 的基础库,顺序反了容易触发依赖求解器反复回溯,装个 FastQC 能耗上好几分钟。用 mamba 代替 conda 也是同理,求解速度快一个量级。
2.3 pip 与官方包的补充方案
如果你只想用 MultiQC,其实不一定需要 Conda。它是个纯 Python 包,用 venv 隔离就够了:
python3 -m venv ~/venvs/qc source ~/venvs/qc/bin/activate pip install -U pip pip install multiqc这种方式的好处是轻,坏处是 FastQC 你得单独解决。而新版本的 MultiQC 对 Python 版本有要求,越新的版本门槛越高,所以如果你的系统 Python 是 3.6 这种老古董,先升 Python 或者干脆回到 Conda 方案。
FastQC 官方包的做法是去 Babraham 官网下载 zip,解压后把目录加到 PATH:
unzip fastqc_v0.12.1.zip -d /opt chmod +x /opt/FastQC/fastqc export PATH=/opt/FastQC:$PATHchmod +x这一步千万别忘,官方包解压出来默认没有执行权限,很多人卡在Permission denied就是这个原因。
提示:不管走哪条路,装完之后一定用
fastqc --version和multiqc --version各验证一次。文件存在不等于能跑,Java 版本不匹配的问题只有真正执行时才会暴露。
3. FastQC 实操:参数、批量运行与报告逐项解读
3.1 常用参数逐个拆解与容易踩的坑
FastQC 的参数不多,但有几个是必须理解的。
-o/--outdir指定输出目录,不指定就写在输入文件旁边。批量跑的时候一定要指定,否则你的原始数据目录会被 HTML 和 zip 淹掉。
-t/--threads是最容易误解的参数。很多人以为它能让单个大文件跑得更快,事实并非如此。FastQC 的线程是“同时处理多少个文件”,每个文件仍然由单线程处理。官方文档还提到每个线程会占用约 250MB 内存,所以-t开太大不仅不会更快,还会把内存吃满。32 位系统上官方建议不超过 6 个线程。
--memory控制每个线程的内存上限,默认就是 250MB。处理长读长数据或者压缩比特别高的 fastq 时,这个值要往上调。
--extract和--noextract决定要不要把 zip 里的内容解压出来。默认是解压的,会生成一个xxx_fastqc/目录,里面有fastqc_data.txt、summary.txt、图片等等。样本多的时候这些目录会占用大量 inode 和磁盘空间,我一般直接用--noextract,因为 MultiQC 完全可以直接读 zip。
--nogroup会让 Per base sequence quality 这类图表不再按碱基位置分组,而是每个位置单独画。读长 150bp 的时候图会变得很密,一般不推荐开,但在排查特定位置的异常时有用。
--adapters和--contaminants允许你替换默认的接头和污染序列文件。做特殊文库(比如自定义接头)的时候需要自己写一份。
还有一个隐藏的坑:命令行参数长度限制。fastqc *.fastq.gz在样本数量多、文件名长的时候可能直接报Argument list too long。解决办法是配合find和xargs。
3.2 一个可以直接抄的批量运行脚本
这是我日常用的脚本骨架,稍微改改就能用:
#!/usr/bin/env bash set -euo pipefail RAW_DIR="raw_data" OUT_DIR="qc_reports" THREADS=8 mkdir -p "$OUT_DIR" find "$RAW_DIR" -maxdepth 1 -name "*.fastq.gz" -print0 \ | xargs -0 -n 1 -P "$THREADS" \ fastqc --noextract --quiet --outdir "$OUT_DIR"几个细节解释一下。-print0和xargs -0是为了处理文件名里有空格的情况,测序文件里这种命名不算罕见。-n 1表示每次只传一个文件给 fastqc,-P 8表示最多 8 个进程并行。这里我用的是进程级并行,没有再用fastqc -t,因为两层并行叠加会导致内存占用失控。如果你想用fastqc -t,那就把-P设成 1,二选一。
set -euo pipefail也是经验之谈。不加的话,中间某个文件跑失败脚本还会继续往下走,最后你以为全跑完了,其实漏了几个样本。
3.3 十二个模块里真正需要盯的几个
FastQC 报告模块挺多,但实际工作中真正决定后续动作的其实就那么几个。
Per base sequence quality是第一优先级。横轴是碱基位置,纵轴是 Phred 质量值。Phred 值和质量概率的关系是 Q = -10 × log10(P),Q20 对应 1% 的错误率,Q30 对应 0.1%。新版本 FastQC 把绿色区间下沿定在 27 附近,黄色是 20 到 27,红色低于 20。如果曲线在 3' 端明显下滑进入黄区甚至红区,说明测序后期的质量衰减,需要考虑按质量裁剪。注意,Illumina 双端测序里 read2 的质量普遍低于 read1,这是化学原理决定的,看到 read2 整体偏低不用惊慌,看趋势就行。
Per base sequence content看的是 A/T/C/G 四条线是否平行。理论上四条线各占 25%。实际数据里,开头的 10 到 15 个碱基经常出现剧烈波动,这通常是随机引物带来的偏好,属于正常现象,不用管。但如果整条 read 上四条线都明显分离,A 和 T 不相等、G 和 C 不相等,那就要怀疑污染或者物种混杂了。
Per sequence GC content是判断污染最直观的图。正常情况下实际 GC 分布应该拟合理论分布,形成一条比较对称的钟形曲线。如果出现明显的双峰,或者实际曲线和理论曲线严重错位,往往意味着样本里混进了别的物种,或者存在大量接头二聚体。
Adapter Content的累积曲线如果在一端持续上升,说明接头没去干净,必须 trim。常见的 Illumina 通用接头是AGATCGGAAGAGC开头的那一段,Nextera 的转座酶序列是CTGTCTCTTATA。FastQC 内置了这些接头库,一般不用自己配。
Sequence Duplication Levels要结合文库类型判断。全基因组测序里一定程度的重复是正常的,因为基因组本身有重复序列。但如果是 RNA-seq,高重复可能来自高表达基因,也可能是低复杂度序列或 PCR 过度扩增,需要结合 Overrepresented sequences 一起看。
Overrepresented sequences列出的是占总 reads 超过 0.1% 的序列。如果这些序列能比对到接头或者已知的污染基因组,基本就实锤了。
3.4 不想翻 HTML?用 summary.txt 快速筛异常
样本多的时候,一张张点开 HTML 不现实。FastQC 的 zip 里有个summary.txt,格式是判定\t模块名\t文件名,用一行 shell 就能把所有有 FAIL 的样本列出来:
for z in qc_reports/*_fastqc.zip; do s=$(basename "$z" _fastqc.zip) if unzip -p "$z" "${s}_fastqc/summary.txt" | grep -q "^FAIL"; then echo "FAIL: $s" fi done这个脚本在样本量上百的时候特别好用,先跑一遍圈出可疑名单,再针对这几十个样本细看 HTML,效率提升非常明显。顺便说一句,PASS/WARN/FAIL 只是启发式判定,不是绝对标准。低覆盖度的数据、特殊的建库方式都可能触发 WARN,最终还是要结合实验背景判断。
4. MultiQC 实操:目录组织、配置定制与自动化
4.1 基本用法与目录组织建议
MultiQC 最简单的用法就是在报告所在目录下敲:
multiqc .它会递归扫描当前目录,找到所有能识别的文件,生成multiqc_report.html和一个multiqc_data目录。几个常用参数:
-o/--outdir指定输出目录;-n/--filename指定报告文件名;-f/--force覆盖已有报告(不加的话如果报告已存在会直接退出);-m/--module强制只跑某个模块,比如-m fastqc;--ignore排除路径,比如--ignore "old_data/*";--ignore-samples按样本名排除;-d/--dirs在样本名里保留目录层级,跨批次同名样本的时候非常有用。
目录组织我建议按“原始数据 → 质控报告 → 汇总”三级分:
project/ ├── raw_data/ 原始 fastq ├── qc_reports/ FastQC 输出的 html + zip └── multiqc_out/ MultiQC 汇总报告然后命令行写成:
multiqc qc_reports \ --outdir multiqc_out \ --filename sequencing_qc \ --title "RNA-seq Batch1 QC" \ --force这样做的好处是 MultiQC 的扫描范围被限定在qc_reports里,不会误扫到其他目录的无关文件。我见过有人直接在项目根目录敲multiqc .,结果把几年前的历史报告一起扫进来,样本数直接翻倍,排查了半天才发现问题。
4.2 用配置文件把报告做成“能交付”的样子
默认生成的 MultiQC 报告能用,但不够“能交付”。加一个 YAML 配置文件,能让报告更像正规的交付物:
title: "Project ABC 测序质控总览" subtitle: "Batch 2024-05" intro_text: "本报告汇总本批次全部样本的 FastQC 结果,Q30 低于 80% 的样本需执行 trim 后重跑。" report_header_info: - Contact: "bioinfo@lab.org" - Pipeline: "RNA-seq v1.3" - Date: "2024-05-20" fastqc_config: top_overrepresented_sequences: 10 max_table_rows: 500top_overrepresented_sequences控制报告里展示多少条过表达序列,默认值偏少,样本存在接头污染时会看不够。max_table_rows在样本量极大时很有用,避免浏览器打开表格直接卡死。
调用方式:
multiqc qc_reports -c multiqc_config.yaml -o multiqc_out -f如果同批次有重复样本名,用--replace-names配合一个两列的 TSV 重命名表,可以一次性把所有样本名换成实验室内部的规范命名。
4.3 把 MultiQC 的产物接进自动化流程
MultiQC 真正的价值在自动化上。跑完之后,multiqc_data目录里有一堆纯文本文件,最常用的是multiqc_general_stats.txt和multiqc_fastqc.txt。前者是每个样本一行、每个指标一列的总表,格式规整,直接就能被 pandas 读:
import pandas as pd df = pd.read_csv("multiqc_out/multiqc_data/multiqc_general_stats.txt", sep="\t") df = df.set_index("Sample") # 找出 Q30 低于 80% 的样本 low_q30 = df[df["FastQC_mqc-generalstats-fastqc-percent_duplicates"] > 50] print(low_q30.index.tolist())这段代码完全可以塞进 CI 或者流程管理的某个检查节点里,不达标就直接中断下游。我通常会再加一条规则:如果某个样本的% Dups超过 50% 且总 reads 数低于某个阈值,就标记为“建议重测”。这种基于数据而不是基于感觉的判断,能省下大量扯皮时间。
还有一个容易被忽略的用法:--pdf。MultiQC 支持直接导出 PDF,但它依赖 pandoc 和 LaTeX,装起来比较重。如果你的交付对象需要 PDF,可以在 CI 里单独跑一个装了这些依赖的镜像,而不是把依赖压到主环境里。
5. 常见问题排查与踩坑实录
5.1 安装与运行阶段的典型报错速查
下面这张表是我这些年亲身遇到过、也被别人问过最多的报错,基本能覆盖八成的情况。
| 现象 | 根本原因 | 处理方式 |
|---|---|---|
Unrecognized VM option 'MaxPermSize' | Java 8 之后移除了 PermGen 空间 | 编辑 fastqc 启动脚本删掉该参数,或升级到 0.12.x |
java.awt.HeadlessException | 服务器无图形显示环境 | 装openjdk-17-jre-headless,或设export DISPLAY= |
conda: command not found | 新终端未初始化 conda | 在.bashrc里 sourceconda.sh |
fastqc: command not found | 环境没激活或 PATH 未生效 | mamba activate qc后重试 |
Permission denied | 官方包解压后无执行权限 | chmod +x FastQC/fastqc |
Argument list too long | 通配符展开后参数超长 | 改用find + xargs |
| MultiQC 报告里没有 FastQC 模块 | 文件名不符合识别规则 | 报告文件名需含_fastqc,且未被--ignore排除 |
Duplicate sample name警告 | 跨批次同名样本被合并 | 加--dirs保留路径,或用--replace-names |
| 内存被吃满 OOM | fastqc -t与xargs -P叠加并行 | 只保留一层并行 |
| 磁盘 inode 耗尽 | 用了--extract生成大量小文件 | 改用--noextract |
关于MaxPermSize这个坑,补充一句背景。FastQC 的启动脚本在 0.11.x 时代写死了-XX:MaxPermSize=250m,这个参数在 JDK 7 及以前用来控制永久代大小,JDK 8 开始被 Metaspace 取代,参数被标记为 unrecognized。虽然它通常只是打一行警告不影响运行,但在某些严格模式下会导致启动失败。进去改脚本是最直接的解法。
5.2 报告解读阶段最容易误判的三种情况
第一种,把正常的 read2 质量下降当成问题。Illumina 双端测序的 read2 质量天然低于 read1,因为它的测序化学路径不同。只要 read2 的曲线没有掉到红区,通常不需要特殊处理。真正的红线是曲线中段就出现断崖式下滑。
第二种,把前几个碱基的 GC 波动当成污染。RNA-seq 因为随机引物的存在,开头几个碱基的碱基组成大幅偏离 25% 是普遍现象。判断污染要看的是全长的整体偏离,而不是开头那一小段。
第三种,把过表达序列直接等同于污染。Overrepresented sequences 里出现一条序列,可能来自接头、可能来自 rRNA 残留、也可能来自某个表达量极高的基因。正确做法是取这条序列去比对(可以用 blast 或者它的接头比对结果),确认来源之后再决定要不要 trim。
5.3 几条我自己踩出来的实操心得
第一,永远先在小样本上试。别一上来就把 96 个样本全丢进去跑,先用两三个样本验证流程、参数、输出格式都对,再批量铺开。我早期吃过亏,脚本里一个路径写错,跑到一半发现输出全跑到错误目录去了,白等一个多小时。
第二,把qc_reports目录当成只读。FastQC 输出之后不要再往里塞别的东西,比如自己整理的 Excel、备注文件。MultiQC 的扫描逻辑是基于文件特征的,目录越干净,误识别的概率越低。
第三,MultiQC 版本用 conda 锁住。MultiQC 更新很频繁,模块解析逻辑和报告模板偶尔会有变化。生产流程里最好在环境里锁一个确定版本,比如multiqc=1.21,别让它自动升到最新。不然某天早上你发现报告长得不一样了,还以为数据出了问题。
第四,样本命名从一开始就规范。FastQC 和 MultiQC 都靠文件名区分样本,命名里带批次、日期、样本编号,会让后续所有的合并、重命名、报表工作都轻松很多。命名混乱带来的痛苦,往往在项目后期才集中爆发,那时候再改成本极高。
第五,跑长读长数据要另眼相看。纳米孔和 PacBio 的数据在 FastQC 里会触发大量 WARN,因为默认阈值是给短读长设计的。处理这类数据时建议配合--nano参数(新版支持),并且不要拿短读长的标准去判断长读长数据的 PASS/FAIL。
第六,养成留存multiqc_data的习惯。HTML 报告给人看,multiqc_data里的文本给机器看。把每批次的multiqc_general_stats.txt按批次归档,半年之后你想回溯“这批数据当时的 Q30 是多少”,翻文件比翻聊天记录快得多。
上面这几条没什么高深理论,但每一条背后都是实打实的时间成本。FastQC 加 MultiQC 这套组合本身并不复杂,真正花时间的从来不是装和跑,而是理解每个指标背后的含义,并且在样本量上去之后依然能高效地把异常样本挑出来。