1. Snakemake 简介:我们为什么需要它?

做批次质控的人,或多或少都经历过这种场景:几十个样本,每个样本跑 FastQC、Trimmomatic、再次 FastQC、汇总 MultiQC……你写了个 Shell 脚本 for 循环,跑完一批,换参数再跑另一批。跑着跑着某个样本报错,你翻日志找到错误,修完重跑,结果把已成功的样本也给覆盖了。

说实话,我几年前就用这种“临时脚本 + 手动标记”的方式撑过好几个项目,直到有一次漏掉了两个样本的质控报告,客户追问数据完整性,我才意识到——批次质控流程必须自动化、可重现、还能从断点继续。这就是我用 Snakemake 的原因。

1.1 什么是 Snakemake?

Snakemake 是一个基于 Python 的工作流管理系统。说白了,它像 GNU Make 一样定义“规则”(rule),每个规则指定输入、输出和执行的命令或 Python 代码。但 Snakemake 比 Make 聪明得多:

  • 它自动计算所有文件的依赖关系
  • 能并行执行互不依赖的任务
  • 支持通配符(wildcards)处理批量样本
  • 原生集成 Conda、Singularity/Docker 环境
  • 断点续跑 —— 这是批次质控的救命功能

我个人习惯把 Snakemake 理解为“带智能调度的 Python 版 Makefile”。你写一个 Snakefile,它就知道先跑什么、后跑什么、哪个任务可以并发、哪个任务失败了需要重跑。

一句话记住:Snakemake = 规则 + 通配符 + 文件依赖 + 自动调度。

1.2 为什么用于批次质控流程?

批次质控有什么特点?我给你列几个痛点:

痛点 传统做法 Snakemake 做法
样本量大(几十到几百) Shell for 循环,依赖文件列表 通配符自动匹配样本名
步骤前后依赖 手动安排脚本执行顺序 基于输入/输出文件自动推导 DAG
中途失败要重跑 重新跑整个流程,或手动跳过已完成 --restart 或 --rerun-incomplete
环境不一致 手动安装工具,版本冲突 Conda 环境隔离,每个规则指定环境
结果难以复现 脚本+参数散落在各处 Snakefile + config 文件,一键复现

你想想看,批次质控本质上是 “同一个处理模板作用于多个样本”。Snakemake 的通配符机制恰好解决这个问题——你写一个规则,它自动对每个样本执行一次。

举个例子,我有一个项目需要处理 150 个血液样本的测序数据。每条数据都走原始 FASTQ → FastQC 质控 → Trimmomatic 去接头 → 再次 FastQC → MultiQC 汇总。如果用传统脚本,要处理失败的样本、要调整参数、要确认所有文件都生成完毕……用 Snakemake,我只需要写 5 条规则,然后在命令行输入:

snakemake --cores 24 --use-conda

它会自动识别哪些样本的哪些步骤还没完成,只跑缺失的部分。嗯,这里要注意:--cores 设置并行核数,如果机器有 24 核,它一次同时跑 24 个样本的 FastQC,而不是逐个跑——效率提升不是一点半点。

我的经验:刚开始接触 Snakemake 时,我习惯把每个样本的中间产物都保留,方便检查。后来发现磁盘很快就满了。我建议你在规则中只保留最终需要的文件(比如质控报告、过滤后的 FASTQ),中间步骤用 temp() 标记,Snakemake 会自动清理。

1.3 核心概念速览

在你编写第一个 Snakefile 之前,先了解三个核心概念,足够你上手:

  1. 规则(rule):一个规则定义输入、输出和要执行的命令。它类似于函数。
  2. 通配符(wildcard):用 {sample} 这种占位符表示样本名,Snakemake 自动从文件名中提取。
  3. 配置文件(config):通常是一个 YAML 文件,存放参数(如质控阈值、参考基因组路径),让 Snakefile 更整洁。

下面是一个最简的 Snakemake 工作流,用来对多个 FASTQ 文件运行 FastQC:

# Snakefile
configfile: "config.yaml"

rule all:
    input:
        expand("qc/{sample}_fastqc.html", sample=config["samples"])

rule fastqc:
    input:
        "data/{sample}.fastq.gz"
    output:
        "qc/{sample}_fastqc.html"
    shell:
        "fastqc -o qc/ {input}"

对应的配置文件:

# config.yaml
samples:
  - S1
  - S2
  - S3

执行后,Snakemake 会生成 3 个报告文件:qc/S1_fastqc.html、qc/S2_fastqc.html、qc/S3_fastqc.html。如果只缺 S2 的报告,它只跑 S2 的 FastQC,不会重跑 S1 和 S3。

1.4 工作流逻辑图:从样本到质控报告

下面这张图展示了一个典型的批次质控工作流结构。每个矩形代表一个步骤,箭头表示文件流向。Snakemake 自动把所有这些步骤串成一个有向无环图(DAG),保证执行顺序正确。

Snakemake 批次质控工作流示例 原始 FASTQ FastQC Trimmomatic 二次 FastQC MultiQC 报告 样本批次信息 • 每个箭头对应一次 规则输出/输入匹配 • 通配符 {sample} 自动 绑定样本名

图中箭头方向就是数据流动方向。Snakemake 会先运行 FastQC,然后 Trimmomatic,再运行二次 FastQC,最后汇总。如果其中某个样本的中间文件丢失,它只重新跑那个样本对应的步骤,不会动其他样本。

我曾经踩过的坑:一开始我写规则时,把输出文件命名为 qc/{sample}_fastqc.zip,但 FastQC 默认输出 .html 和 .zip。Snakemake 严格按你写的“输出”判断文件是否已存在。如果你写的是 .html,但命令只生成了 .zip,Snakemake 会一直认为任务未完成,死循环式重跑。所以输出声明必须与命令实际生成的文件名完全一致。

1.5 一句话总结

Snakemake 不是银弹,但它把批次质控中最折磨人的“依赖管理”和“断点续跑”变成了基础设施。你只需要关注每个步骤的输入输出和参数,剩下的调度、并行、重试都交给它。