Snakemake 工作流基本概念
我第一次接触 Snakemake 的时候,心里想的是:这不就是个加强版 Make 吗?后来才发现,嗯,它远比我想象的聪明。说白了,Snakemake 就是一个能帮你把数据分析流程串起来的工具——你只需要告诉它“我要从 A 得到 B,中间用 C 这个脚本”,剩下的依赖分析和并行调度,它自己搞定。
2.1 工作流是什么
工作流(Workflow)就是一系列有先后依赖关系的任务集合。在生物信息学里,我们经常要跑这样的流程:原始测序数据 → 质控 → 比对 → 定量 → 差异分析。手动一个个跑,容易忘参数,也容易出错。
Snakemake 把整个流程写在一个叫 Snakefile 的文件里。你定义好每个步骤的输入、输出和要执行的命令,它自动帮你安排顺序。举个例子,我团队里有个项目,一次处理 96 个样本,每个样本要跑 8 个步骤。用传统脚本调度,光等依赖关系就得写半天。换成 Snakemake 后,我只定义了规则,它自己就并行跑起来了。
2.2 Snakefile:核心配置文件
Snakefile 是一个 Python 风格的文本文件,里面定义规则(rule)和全局配置。它的后缀名就是 Snakefile,也可以用 .smk。
一个最简单的 Snakefile 长这样:
rule all:
input:
"results/clean_reads.fq.gz"
rule fastqc:
input:
"data/raw_reads.fq.gz"
output:
"results/clean_reads.fq.gz"
shell:
"fastp -i {input} -o {output}"
你看,rule all 是默认目标,Snakemake 看到它要的 results/clean_reads.fq.gz 不存在,就去寻找能生成它的规则。找到 rule fastqc,发现它需要 data/raw_reads.fq.gz——如果这个文件存在,就直接执行 fastp 命令。
2.3 规则(rule)的构成
每个规则包含几个关键部分:
| 部分 | 说明 | 我的经验 |
|---|---|---|
input | 上游文件列表 | 可以根据通配符动态指定,我经常用 lambda wildcards: 做复杂匹配 |
output | 本规则生成的文件列表 | Snakemake 严格校验输出是否生成,缺文件会报错 |
shell / run / script | 执行的命令、Python 代码或外部脚本 | 推荐用 shell 配合通配符 {input} {output},清晰 |
params | 额外的参数 | 可以放阈值、线程数等,方便后期修改 |
threads | 需要的 CPU 核数 | Snakemake 会根据这个分配资源 |
snakemake --print-compilation 看 Snakemake 是怎么解析你的规则的。
2.4 输入与输出:依赖关系图
当工作流变大,规则之间会形成一张依赖图(Directed Acyclic Graph, DAG)。Snakemake 会自动构建这张图,保证每个任务都在其上游任务完成后才启动。
我个人习惯先画出 DAG 再写 Snakefile。看一眼 Snakemake 自动生成的图,心里就有底了。命令很简单:
snakemake --dag | dot -Tsvg > workflow.svg
生成出的 SVG 图里,每个规则是一个节点,箭头表示输入输出依赖。下面这张就是我根据上面示例手动画的简化版:
input 里直接写文件名但忘了写路径,Snakemake 报错说文件找不到。后来我养成了习惯,所有路径都用 config["data_dir"] 这样的变量统一管理。
2.5 通配符:让规则泛化
当你要处理多个样本时,总不能为每个样本写一条规则吧?通配符就是用来解决这个问题的。
看这个例子:
rule fastqc:
input:
"data/{sample}.fq.gz"
output:
"results/{sample}_fastqc.html"
shell:
"fastqc {input} -o results/"
这里的 {sample} 就是通配符。当你运行 snakemake results/sampleA_fastqc.html 时,Snakemake 自动把 {sample} 替换成 sampleA。如果有 100 个样本,它就能自动生成 100 条任务,并行执行。
通配符还可以在多个规则间传递。比如:
rule trim:
input:
"data/{sample}.fq.gz"
output:
"results/{sample}_trimmed.fq.gz"
shell:
"fastp -i {input} -o {output}"
如果你同时依赖 fastqc 的输出,可以用 rules.fastqc.output 引用。但要注意,通配符必须能在上下游之间匹配成功。
2.6 工作流执行过程
当你敲下 snakemake 时,背后发生了什么?我简单拆解一下:
- 解析 Snakefile:读入所有规则,建立规则索引
- 确定目标:如果没有指定,就找第一个
rule all的输入;也可以手动指定文件名 - 构建 DAG:从目标开始反向搜索,找到所有必须执行的规则和它们的依赖
- 拓扑排序:保证先执行没有上游依赖的任务
- 调度执行:按顺序或并行(根据
--cores)运行任务,并在完成后检查输出是否生成 - 报告完成:输出日志,生成统计信息
执行过程中,Snakemake 会把每次运行的参数记录在 .snakemake 目录下,方便下次增量更新。如果你改了上游某个步骤的参数,它只会重新跑受影响的部分——这正是它比纯脚本高效的地方。
我曾经用它处理一个 512 个样本的 RNA-seq 流程,第一次全跑完用了 12 小时。后来修改了比对参数,重新运行 snakemake --cores 20,只花了 2 小时就完成了增量更新。这体验,真的舒畅。