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
个文件进行格式转换
在此之前,我检查了this, snakemake's documentation,
简而言之,我在一条规则中从其他文件创建了多个文件,它们都符合通配符格式。我不知道自己创建了多少,因为我不知道最初下载了多少。
到目前为止,在我读过的所有示例中,输出都是目录(“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
个文件进行格式转换