Snakemake:使用检查点和函数使用通配符聚合未知数量的文件

Snakemake: Use checkpoint and function to aggregate unknown number of files using wildcards

在此之前,我检查了this, snakemake's documentation, ,and this。也许他们真的回答了这个问题,但我只是不明白。

简而言之,我在一条规则中从其他文件创建了多个文件,它们都符合通配符格式。我不知道自己创建了多少,因为我不知道最初下载了多少。

到目前为止,在我读过的所有示例中,输出都是目录(“the/path”),而我有一个“the/path/{id}.txt。所以这个我想修改了我在函数本身中调用检查点的方式。以及扩展的使用。

有问题的规则是:

download_mv

textgrid_to_ctm_txt

get_MV_IDs

merge_ctms

规则的顺序应该是:

download_mv(创建 {MV_ID}.TEX 和 .wav(虽然数量不一定相同)

textgrid_to_ctm_txt(从 {MV_ID}.TEX 匹配 .txt 和 .ctm 创建)

get_MV_IDs(应该列出 .ctm 文件)

merge_ctms(应该连接 ctm 文件)

kaldi_align(从 .wav 和 .txt 目录创建一个 ctm 文件)

analyse_align(比较来自 kaldi_align 和 merge_ctms 的 ctm 文件)

upload_print_results

我尝试将 download_mv 的输出作为目录,然后尝试获取 ID,但我遇到了不同的错误。现在 snakemake --dryrun 我得到

Building DAG of jobs...
InputFunctionException in line 40 of Snakefile:
Error:
  WorkflowError:
    Missing wildcard values for MV_ID
Wildcards:

Traceback:
  File "Snakefile", line 35, in get_MV_IDs

Snakefile 是:

import os


rule all:
  input:
    "mv_data/results.txt"


rule download_mv:
  params:
    allas="allas:2004354-mv/mv/",
    textgrid="mv_data/TEXTGRID",
    wav="mv_data/wav",
  output:
    textgrid="mv_data/TEXTGRID/{MV_ID}.TEX",
    wav="mv_data/wav/{MV_ID}.wav",
  shell:'''
    rclone copy {params.allas}/mv_original/TEXTGRID/ {params.textgrid}
    rclone copy {params.allas}/mv_added/wav/ {params.wav}
    '''


checkpoint textgrid_to_ctm_txt:
  input:
    textgrid="mv_data/TEXTGRID/{MV_ID}.TEX",
    script="data_preparation/read_mv_TextGrid.py"
  output:
    ctm="mv_data/ctm/{MV_ID}.ctm",
    txt="mv_data/txt/{MV_ID}.txt",
  shell:
    "python {input.script} {input.textgrid}"


def get_MV_IDs(wildcards):
  checkpoint_output = checkpoints.textgrid_to_ctm_txt.get(**wildcards).output[0]
  TMP_VAR, = glob_wildcards(os.path.join(checkpoint_output,"{MV_ID}.TEX"))
  return expand(os.path.join(checkpoint_output,"{mv_id}.TEX"),mv_id=TMP_VAR)


rule merge_ctms:
  input:
    get_MV_IDs
  output:
    gold_ctm="mv_data/ctm/ctm",
  shell:
    "cat {input.get_MV_IDs} > {output.gold_ctm}"


rule kaldi_align:
  input:
    gold_ctm="mv_data/ctm/ctm",
    script="interfaces/kaldi-align.py",
  params:
    alignments="mv_data/align",
    wav="mv_data/wav",
  output:
    created_ctm="mv_data/align/ctm",
  shell:'''
    python {input.script} --wav {params.wav} --txt mv_data/txt --lang fi {params.alignments} < kaldi-align_prompts
    '''


rule analyse_align:
  input:
    script="analysis/calculate_metrics.py",
    gold_ctm="mv_data/ctm/ctm",
    created_ctm="mv_data/align/ctm",
  output:
    results="mv_data/results.txt"
  shell:
    "python -m analysis.calculate_metrics {input.gold_ctm} {input.created_ctm} mv > {output.results}"


rule upload_print_results:
  input:
    results="mv_data/results.txt",
  params:
    allas="allas:2004354-mv/mv/",
  shell:
    "rclone copyto {input.results} {params.allas}"

更新

所以我通过使用 bash 功能而不是 snakemake 来完成这项工作。如果有人可以指导我如何完成此操作,我将不胜感激:

import os


rule all:
  input:
    "mv_data/results.txt"


rule download_mv:
  params:
    allas="allas:2004354-mv/mv",
  output:
    textgrid=directory("mv_data/TEXTGRID"),
    wav=directory("mv_data/wav"),
  shell:'''
    rclone copy {params.allas}/mv_original/TEXTGRID/ {output.textgrid}
    rclone copy {params.allas}/mv_added/wav/ {output.wav}
    '''


checkpoint textgrid_to_ctm_txt:
  input:
    textgrid="mv_data/TEXTGRID",
    script="data_preparation/read_mv_TextGrid.py"
  output:
    ctm=directory("mv_data/ctm"),
    txt=directory("mv_data/txt"),
  shell:'''
    for textgrid in {input.textgrid}/*.TEX;
    do
      python {input.script} "$textgrid";
    done
    '''

rule merge_ctms:
  input:
    ctm="mv_data/ctm"
  output:
    gold_ctm="mv_data/gold_ctm",
  shell:
    "cat {input.ctm}/*.ctm > {output.gold_ctm}"


rule kaldi_align:
  input:
    wav="mv_data/wav",
    txt="mv_data/txt",
    script="interfaces/kaldi_align.py",
  params:
    alignments="mv_data/align",
  output:
    created_ctm="mv_data/align/ctm",
  shell:'''
    python {input.script} --wav {input.wav} --txt mv_data/txt --lang fi {params.alignments} < kaldi-align_prompts
    '''

rule analyse_align:
  input:
    script="analysis/calculate_metrics.py",
    gold_ctm="mv_data/gold_ctm",
    created_ctm="mv_data/align/ctm",
  output:
    results="mv_data/results.txt"
  shell:
    "python -m analysis.calculate_metrics {input.gold_ctm} {input.created_ctm} mv > {output.results}"


rule upload_print_results:
  input:
    results="mv_data/results.txt",
  params:
    allas="allas:2004354-mv/mv/",
  shell:
    "rclone copyto {input.results} {params.allas}"

我可以看出您出现错误的原因是:

您使用规则 merge_ctms 中的输入函数来访问检查点生成的文件。但是 merge_ctms 在输出文件名中没有通配符,snakemake 不知道在你的检查点 MV_ID 中应该填写哪个通配符。

我对你使用检查点的方式也有点困惑,因为你不确定会下载多少 .TEX 个文件(我猜),你不应该使用存储 .TEX 作为检查点的输出,然后使用 glob_wildcards 找出您下载了多少 .TEX 个文件?

我能想到的另一种解决方案是让 download_mv 成为您的检查点并将输出设置为包含 .TEX 文件的目录,然后在输入函数中,替换 .TEX文件有 .ctm 个文件进行格式转换