использовать несколько параметров в snakemake

Я только начинаю работать со snakemake и задавался вопросом, каков «правильный» способ запустить набор параметров в одном файле и как это будет работать для объединения правил?

Так, например, когда я хочу иметь несколько методов нормализации, за которыми следует, скажем, правило кластеризации с различным количеством k кластеров. Как лучше всего это сделать, чтобы выполнялись все комбинации?

Я начал вот так:

INFILES = ["mytable"]

rule preprocess:
input:
    bam=expand("data/{sample}.csv", sample=INFILES, param=config["normmethod"])

output:
    bamo=expand("results/{sample}_pp_{param}.csv", sample=INFILES, param=config["normmethod"])

script:
    "scripts/preprocess.py"

А затем вызвал скрипт через:

snakemake --config normmethod = Медиана

Но на самом деле это не масштабируется для дальнейших опций в дальнейшем в рабочем процессе. Например, как мне автоматически включить этот набор параметров?

normmethods= ["Median", "Quantile"]
kclusters= [1,3,5,7,10]

person Kam Sen    schedule 20.01.2017    source источник
comment
Расширение в вашем вводе содержит param, которого нет в строке, которую нужно раскрыть. Как себя ведет?   -  person bli    schedule 22.01.2017
comment
Код выше проходит. Если я сделаю snakemake --config normmethod = Median, будет использован метод Median. Если я запускаю рабочий процесс с помощью snakemake --config normmethod = Mean, используется среднее значение. Соответственно, выходные файлы содержат параметр normmethod в своем имени файла.   -  person Kam Sen    schedule 23.01.2017


Ответы (3)


Вы хорошо справились с использованием функции expand () в своем правиле.

Для параметров я рекомендую использовать файл конфигурации, содержащий все ваши параметры. Snakemake работает с файлами YAML и JSON. Здесь вы получили всю информацию об этих двух форматах:

В вашем случае у вас просто есть файл YAML, чтобы написать это:

INFILES : "mytables"

normmethods : ["Median", "Quantile"] 
or
normmethods : - "Median"
              - "Quantile"

kclusters : [1,3,5,7,10]
or
kclusters : - 1
            - 3
            - 5
            - 7
            - 10

Напишите свое правило так:

rule preprocess:
input:
    bam = expand("data/{sample}.csv",
                 sample = config["INFILES"])

params :
    kcluster = config["kcluster"]

output:
    bamo = expand("results/{sample}_pp_{method}_{cluster}.csv",
                  sample = config["INFILES"],
                  method = config["normmethod"],
                  cluster = config["kcluster"])

script:
    "scripts/preprocess.py {input.bam} {params.kcluster}"

Тогда вам останется только так пообедать:

snakemake --configfile  path/to/config.yml

Для работы с другими параметрами вам нужно будет изменить свой файл конфигурации, а не файл змеи (делая меньше ошибок), и это лучше для удобочитаемости и красоты кода.

РЕДАКТИРОВАТЬ:

  rule preprocess:
    input:
      bam = "data/{sample}.csv"

Чтобы исправить мою ошибку, вам не нужно использовать здесь расширение для ввода, так как вы просто хотите запускать правило один файл .csv за другим. Так что просто поместите здесь подстановочный знак, и Snakemake внесет свой вклад.

person Pereira Hugo    schedule 13.02.2017
comment
Супер гладко. Большое спасибо! - person Kam Sen; 17.02.2017
comment
Привет, хороший ответ. Не могли бы вы также предоставить пример файла сценария (preprocess.py)? - person anilbey; 16.01.2018
comment
@anilbey, извините, у меня его больше нет, но по сути это сводится к следующему (пример из snakemake.readthedocs.io/en/stable/snakefiles/): def do_something (data_path, out_path, themes, myparam): # python code do_something (snakemake.input [0] , snakemake.output [0], snakemake.threads, snakemake.config [myparam]) - person Kam Sen; 09.05.2018

Кажется, вы не передали параметры своему скрипту. Как насчет следующего?

import re
import os
import glob
normmethods= ["Median", "Quantile"] # can be set from config['normmethods']    
kclusters= [1,3,5,7,10]             # can be set from config['kclusters']
INFILES = ['results/' + re.sub('\.csv$', '_pp_' + m + '-' + str(k) + '.csv', re.sub('data/', '', file)) for file in glob.glob("data/*.csv") for m in normmethods for k in kclusters]

rule cluster:
    input: INFILES

rule preprocess:
    input:
        bam="data/{sample}.csv"
    output:
        bamo="results/{sample}_pp_{m}-{k}.csv"
    run:     
        os.system("scripts/preprocess.py %s %s %s %s" % (input.bame, output.bamo, wildcards.m, wildcards.k))
person Shiping    schedule 20.01.2017
comment
Спасибо за Ваш ответ! Мне это не кажется изящным, но позволяет справиться с задачами меньшей сложности! Тогда спасибо! ;) - person Kam Sen; 23.01.2017

Этот ответ аналогичен ответу @ Shiping, который заключается в использовании подстановочных знаков в output правила для реализации нескольких параметров для каждого входного файла. Однако этот ответ предоставляет более подробный пример и позволяет избежать использования сложного понимания списка, регулярного выражения или модуля glob.

Подход @Pereira Hugo использует одно задание для запуска всех комбинаций параметров для одного входного файла, тогда как подход в этом ответе использует одно задание для запуска одной комбинации параметров для одного входного файла, что упрощает распараллеливание выполнения каждой комбинации параметров в одном входной файл.

Snakefile:

import os

data_dir = 'data'
sample_fns = os.listdir(data_dir)
sample_pfxes = list(map(lambda p: p[:p.rfind('.')],
                        sample_fns))

res_dir = 'results'

params1 = [1, 2]
params2 = ['a', 'b', 'c']

rule all:
    input:
        expand(os.path.join(res_dir, '{sample}_p1_{param1}_p2_{param2}.csv'),
               sample=sample_pfxes, param1=params1, param2=params2)

rule preprocess:
    input:
        csv=os.path.join(data_dir, '{sample}.csv')

    output:
        csv=os.path.join(res_dir, '{sample}_p1_{param1}_p2_{param2}.csv')

    shell:
        "ls {input.csv} && \
           echo P1: {wildcards.param1}, P2: {wildcards.param2} > {output.csv}"

Структура каталогов перед запуском snakemake:

$ tree .
.
├── Snakefile
├── data
│   ├── sample_1.csv
│   ├── sample_2.csv
│   └── sample_3.csv
└── results

Запустите snakemake:

$ snakemake -p
Building DAG of jobs...
Using shell: /bin/bash
Provided cores: 1
Rules claiming more threads will be scaled down.
Job counts:
    count   jobs
    1   all
    18  preprocess
    19

rule preprocess:
    input: data/sample_1.csv
    output: results/sample_1_p1_2_p2_a.csv
    jobid: 1
    wildcards: param2=a, sample=sample_1, param1=2

ls data/sample_1.csv &&          echo P1: 2, P2: a > results/sample_1_p1_2_p2_a.csv
data/sample_1.csv
Finished job 1.
1 of 19 steps (5%) done

rule preprocess:
    input: data/sample_2.csv
    output: results/sample_2_p1_2_p2_a.csv
    jobid: 2
    wildcards: param2=a, sample=sample_2, param1=2

ls data/sample_2.csv &&          echo P1: 2, P2: a > results/sample_2_p1_2_p2_a.csv
data/sample_2.csv
Finished job 2.
2 of 19 steps (11%) done

...

localrule all:
    input: results/sample_1_p1_1_p2_a.csv, results/sample_1_p1_2_p2_a.csv, results/sample_2_p1_1_p2_a.csv, results/sample_2_p1_2_p2_a.csv, results/sample_3_p1_1_p2_a.csv, results/sample_3_p1_2_p2_a.csv, results/sample_1_p1_1_p2_b.csv, results/sample_1_p1_2_p2_b.csv, results/sample_2_p1_1_p2_b.csv, results/sample_2_p1_2_p2_b.csv, results/sample_3_p1_1_p2_b.csv, results/sample_3_p1_2_p2_b.csv, results/sample_1_p1_1_p2_c.csv, results/sample_1_p1_2_p2_c.csv, results/sample_2_p1_1_p2_c.csv, results/sample_2_p1_2_p2_c.csv, results/sample_3_p1_1_p2_c.csv, results/sample_3_p1_2_p2_c.csv
    jobid: 0

Finished job 0.
19 of 19 steps (100%) done

Структура каталогов после запуска snakemake:

$ tree .                                                                                                                                       [18:51:12]
.
├── Snakefile
├── data
│   ├── sample_1.csv
│   ├── sample_2.csv
│   └── sample_3.csv
└── results
    ├── sample_1_p1_1_p2_a.csv
    ├── sample_1_p1_1_p2_b.csv
    ├── sample_1_p1_1_p2_c.csv
    ├── sample_1_p1_2_p2_a.csv
    ├── sample_1_p1_2_p2_b.csv
    ├── sample_1_p1_2_p2_c.csv
    ├── sample_2_p1_1_p2_a.csv
    ├── sample_2_p1_1_p2_b.csv
    ├── sample_2_p1_1_p2_c.csv
    ├── sample_2_p1_2_p2_a.csv
    ├── sample_2_p1_2_p2_b.csv
    ├── sample_2_p1_2_p2_c.csv
    ├── sample_3_p1_1_p2_a.csv
    ├── sample_3_p1_1_p2_b.csv
    ├── sample_3_p1_1_p2_c.csv
    ├── sample_3_p1_2_p2_a.csv
    ├── sample_3_p1_2_p2_b.csv
    └── sample_3_p1_2_p2_c.csv

Результат образца:

$ cat results/sample_2_p1_1_p2_a.csv                                                                                                          [19:12:36]
P1: 1, P2: a
person Logstar    schedule 05.06.2018