通配符与模式匹配:Wildcards 的使用、多文件扩展示例
你写了一个规则,能处理一个样本的质控。但面对 200 个样本,难道要复制 200 次规则?
我刚开始接触 Snakemake 时就是这么干的——累得半死,还容易漏改参数。后来才发现,通配符(wildcards)就是为这种批量场景设计的。
Wildcards 是什么?
说白了,通配符就是一个占位符。你在规则输出里写 {sample},Snakemake 就会自动根据实际要生成的文件名,把 {sample} 替换成真实的值。比如我有一个规则要生成 QC/ERR123456_trimmed.fastq,Snakemake 就知道 wildcards.sample = "ERR123456"。
我习惯把通配符看作是规则的“参数化入口”——它让一条规则能匹配成百上千个文件。
通配符的匹配逻辑
看一个最简例子:
rule trim:
input:
"raw/{sample}.fastq"
output:
"QC/{sample}_trimmed.fastq"
shell:
"fastp -i {input} -o {output}"
当我执行 snakemake QC/ERR123456_trimmed.fastq 时,Snakemake 会做三件事:
- 把输出文件名里的
{sample}绑定为ERR123456 - 把输入里的
{sample}替换为raw/ERR123456.fastq - 执行 shell 命令
注意,通配符名称必须一致。输出里写了 {sample},输入和 shell 里也得用 {sample},不能一会写 {id} 一会写 {sample}。
sample、run、patient,别用单个字母 a、b。代码跑一跑还能排查,但半年后回来看自己写的 Snakefile,{a} 和 {b} 基本就是天书。
多文件扩展:从规则到批量目标
光有规则还不够。要让 Snakemake 一次性处理所有样本,我们需要用 expand() 函数生成所有目标文件。
SAMPLES = ["ERR123456", "ERR123457", "ERR123458"]
rule all:
input:
expand("QC/{sample}_trimmed.fastq", sample=SAMPLES)
运行 snakemake -j 4,Snakemake 会推断出需要生成三个 QC 文件,然后自动调用 trim 规则三次,每次使用不同的 sample 值。
我遇到过最典型的坑:expand() 默认做笛卡尔积。假如你有两个列表:
MODULES = ["R1", "R2"]
DATASETS = ["A", "B"]
expand("QC/{dataset}_{module}.fastq", dataset=DATASETS, module=MODULES)
它会生成 QC/A_R1.fastq、QC/A_R2.fastq、QC/B_R1.fastq、QC/B_R2.fastq——四个文件。如果你只想配对(A配R1,B配R2),需要用 zip 模式:expand("QC/{dataset}_{module}.fastq", zip, dataset=DATASETS, module=MODULES)。
嗯,记着,默认笛卡尔积,想配对就加 zip。
通配符冲突与限定
同一个 Snakefile 里两条规则输出同名模式怎么办?看这个:
rule trim_se:
output: "QC/{sample}_se_trimmed.fastq"
rule trim_pe:
output: "QC/{sample}_pe_trimmed.fastq"
没问题,因为通配符模式不同——_se_ 和 _pe_ 区分开了。
但如果两条规则的输出模式完全相同(比如都输出 QC/{sample}.fastq),Snakemake 会报 AmbiguousRuleException。解决办法:要么改输出命名,要么用 wildcard_constraints 给通配符加限制。
通配符限定示例:
wildcard_constraints:
sample = "[A-Z0-9]+"
rule trim:
output: "QC/{sample}.fastq"
强制 sample 只能匹配大写字母和数字。我曾在项目中遇到样本名包含特殊字符(比如“ERR-001”),一旦连字符被当成目录分隔符解析,后果很惨。加约束是最稳的办法。
多文件扩展实战:质控参数调优
回到我们的课程主题——分类质控参数调优。假设你有三种数据类型:WGS、RNA、ATAC,每种需要不同的质控参数。我们可以用通配符 {datatype} 来组织:
DATATYPES = ["WGS", "RNA", "ATAC"]
rule fastp_with_config:
input:
"raw/{sample}_{datatype}.fastq"
output:
"QC/{sample}_{datatype}_trimmed.fastq"
params:
config = lambda wildcards: f"configs/{wildcards.datatype}.json"
shell:
"fastp -i {input} -o {output} -j {params.config}"
每个数据类型单独配一个 JSON 文件,完美实现分类调优。
| 数据类型 | 通配符值 | 配置示例 |
|---|---|---|
| WGS | WGS | 低 stringency,保留多平台 mismatch |
| RNA | RNA | 高 stringency,3' 端修剪短序列 |
| ATAC | ATAC | 中 stringency,去除线粒体 reads |
DATATYPES 里写的是 "WGS"、"RNA",但 JSON 配置文件名是 "wgs.json"、"rna.json"——大小写不匹配。Snakemake 不会自动帮你转换大小写!{datatype} 替换成什么就是什么,你得自己维护一致性。后来我统一用大写枚举,配置文件也改成大写。
下面这张图把通配符——多目标——限定——配置调优的逻辑串了一遍:
避坑指南:通配符使用的常见问题
- 通配符未定义:输出里用了
{sample},但输入或 params 里写的是{s}。Snakemake 报错:WildcardError: No wildcard named 's'。解决办法——统一定义,名称一致。 - 过度匹配:输出模式
{sample}.fastq可能会匹配到ERR123.fastq,也可能匹配到ERR_123.fastq。如果 schema 不严格,会导致错误实例。用wildcard_constraints限定字符集。 - expand() 与 zip 混淆:我想批量配对两个列表,结果笛卡尔积生成了 9 个文件而不是 3 个。后来老实加
zip。 - 大小写敏感:上面讲过了,配置文件、样本列表、通配符值必须大小写一致。
wildcard_constraints 做输入校验。这样跑批量任务时,问题一眼就能看出来。