Snakemake 工作流入门:安装、语法与第一个 Snakefile

好,咱们正式开始动手了。这一章,我带你从零搭建 Snakemake 环境,并写出第一个能跑的工作流。说实话,Snakemake 的语法非常直观,你只要理解了一个核心逻辑——规则(rule)就是一个小任务——剩下的全是细节。

2.1 安装 Snakemake:两种方式,我推荐第二种

安装这件事,不同人有不同习惯。我个人偏好 conda/mamba 来管理环境,因为后面做 ADMET 预处理时,依赖的第三方工具(比如 OpenBabel、RDKit)版本冲突真的让人头大。

方式一:pip 直接安装

pip install snakemake

这种方式最快,但我踩过坑:如果系统里已经装了其他 bioinfo 工具,pip 可能会把依赖搞乱。适合你只是想快速试试语法的场景。

方式二:conda/mamba 创建干净环境(我推荐)

conda create -n snakemake_env -c conda-forge -c bioconda snakemake
conda activate snakemake_env

或者用 mamba(更快):

mamba create -n snakemake_env snakemake
mamba activate snakemake_env

验证安装

安装完后,在终端跑一下这个命令:

snakemake --version

如果看到类似 7.32.4 的版本号,那就成了。

小提示: 如果公司内网限制了 conda 源,可以换成清华的镜像,具体配置方法网上很多,我就不啰嗦了。

2.2 Snakefile 的核心语法:规则(Rule)

Snakemake 的构建块就是 规则。一个规则定义了三样东西:输入(input)、输出(output) 和 要运行的命令(shell 或 run)。

你看,这就是一个最简规则:

rule say_hello:
    output:
        "hello.txt"
    shell:
        "echo 'Hello, Snakemake!' > {output}"

这里面有几个关键点:

  • rule 名字(这里是 say_hello)就像给任务起的标签,不能重复。
  • output 定义了规则会生成什么文件。
  • shell 里写的命令会被 Snakemake 执行,{output} 会自动替换成输出文件的路径。

说白了,Snakemake 就是根据文件的存在与否来决定要不要跑某个规则。如果 hello.txt 已经存在,它就会跳过。

2.3 第一个 Snakefile:从零到一

好,咱们写个真正能跑的。假设我们要从 raw_data.smi 这个 SMILES 文件,通过 OpenBabel 转换成 mol2 格式。我们把这个工作流写进 Snakefile:

rule convert_to_mol2:
    input:
        "data/raw_data.smi"
    output:
        "data/processed/raw_data.mol2"
    shell:
        "obabel {input} -O {output} --gen3D"

在终端里,cd 到 Snakefile 所在目录,然后执行:

snakemake -j 1

-j 1 表示用 1 个 CPU 核心来跑。如果一切顺利,你会在 data/processed/ 下看到生成的 mol2 文件。

我在这里犯过一个错: 忘了先建好 data/processed/ 目录。Snakemake 默认不会自动创建输出目录,你得手动建,或者用 directory() 指令。记得提前 mkdir -p data/processed。

2.4 Snakemake 的基本概念:规则、目标和执行

为了让理解更扎实,我把 Snakemake 的核心元素整理成了一张表:

概念说明示例
规则 (rule)定义一个任务单元rule convert: ...
输入 (input)该规则依赖的文件input: "raw.smi"
输出 (output)该规则要生成的文件output: "processed.mol2"
shell 命令实际运行的命令行shell: "obabel {input} -O {output}"
目标 (target)Snakemake 决定先构建哪个文件默认第一个规则的输出
执行 (execution)Snakemake 自动推导依赖关系并运行snakemake -j 4

你想想看,Snakemake 本质上就是一个智能调度器。你告诉它想要什么文件,它自己会去找需要的输入文件在哪里,按顺序执行规则。我最初用的时候觉得最神奇的是,如果中间某一步的输入文件没生成,它不会傻等,而是直接报错告诉你“少了啥”。

2.5 多规则工作流:搭建简单处理链

实际项目中,很少只有一个规则。比如 ADMET 预处理常常需要:读取 SMILES → 生成 3D 结构 → 计算分子描述符。我们写个三步骤的工作流:

rule generate_3d:
    input:
        "data/mol.smi"
    output:
        "data/mol_3d.sdf"
    shell:
        "obabel {input} -O {output} --gen3D"

rule calculate_descriptors:
    input:
        "data/mol_3d.sdf"
    output:
        "data/descriptors.csv"
    shell:
        "obabel {input} -O {output} --append descriptors"

当你执行:

snakemake -j 1

Snakemake 会做以下事情:

  1. 发现 calculate_descriptors 需要 data/mol_3d.sdf。
  2. 检查这个文件是否存在——不存在,于是去找生成它的规则 generate_3d。
  3. 按顺序依次执行。
重要提醒: Snakemake 的第一个规则默认是“最终目标”。如果你想把某个规则设为默认目标,就把它的 output 放在最前面。否则,可以用 snakemake data/descriptors.csv 来指定目标文件。

2.6 本章核心流程:Snakemake 工作流逻辑图

我把刚才讲的核心逻辑——输入 → 规则执行 → 输出 → 依赖追踪——画成了一张图,方便你直观理解:

Snakemake 工作流核心逻辑 规则1: 生成3D结构 输出: mol_3d.sdf 规则2: 计算描述符 输出: descriptors.csv 输入: mol.smi 最终目标文件 核心逻辑: Snakemake 从最终目标反向查找依赖,若输入或中间输出缺失则自动按顺序运行规则。

2.7 常见错误与调试技巧

我在第一次带学生搭建 Snakemake 环境时,大家犯的错误基本集中在这几个地方:

  • 路径不对:Snakemake 的工作目录是运行命令的目录,不是 Snakefile 所在的目录。我建议用绝对路径或基于项目根目录的相对路径。
  • 输出文件格式不匹配:比如你在 shell 里用 obabel 生成 .sdf,但 output 写的是 .xyz,Snakemake 不会检查内容格式——它只认文件名。我就遇到过生成了错误格式然后下游报错,排查了好久才发现是名字写错了。
  • 忘记激活 conda 环境:Snakemake 本身可以激活 conda 环境,但如果你直接裸跑命令,系统会找全局的 obabel。很多人因此莫名其妙的报“command not found”。
避坑指南: 如果你用 conda 环境管理工具,可以在 Snakefile 里加上 conda: "env.yaml" 来指定每个规则的环境。但我个人建议前期先保持简单,用一个全局环境跑通再说。

小结