【问题标题】:make for reproducible research进行可重复的研究
【发布时间】:2018-07-31 09:44:00
【问题描述】:

Make 可以方便地使依赖项的研究和数据分析更可重复,例如:

# make file
R = R CMD BATCH --no-save --no-restore 
datafiles = *.csv
outputfiles = *.{pdf,Rout}

.PHONY: all clean

all: fig_A.pdf fig_B.pdf 

clean: 
    rm -f $(datafiles) $(outputfiles)
    rm -rf output
    mkdir output

# produce outputs
fig_A.pdf fig_B.pdf: interim_data.csv plot_figs.R
    $(R) plot_figs.R
    mv plot_figs.Rout ./output

# derive interim data
interim_data.csv: source_data.csv source_to_interim.R 
    $(R) source_to_interim.R 
    mv source_to_interim.Rout ./output

# download source data
source_data.csv: download_source.R
    $(R) download_source.R 
    mv download_source.Rout ./output

从源数据重新生成数字,将所有输出保存到./output。但是我们可以让事情变得更紧凑吗?例如,通过

  1. 避免重复,如:

    $(R) script.R
    mv script.Rout ./output
    
  2. 重组以更通用地关联代码(本示例中为 R 脚本)数据 (csv) 和输出(pdf、Rout)?

  3. 更好地处理将输出导出到./output 目录?

【问题讨论】:

    标签: r makefile data-analysis reproducible-research


    【解决方案1】:

    1) 和 2)

    你应该看看make的automatic variables

    $ cat Makefile
    .NOTPARALLEL:
    
    OUTPUT := output
    R      = R CMD BATCH --no-save --no-restore
    PDF    := fig_A.pdf fig_B.pdf
    CSV    := interim_data.csv source_data.csv
    
    all: $(PDF) $(CSV)
    
    $(PDF): plot_figs.R interim_data.csv
    interim_data.csv: source_to_interim.R source_data.csv
    source_data.csv: download_source.R
    
    $(CSV) $(PDF):
        $(R) $<
        mv $<out $(OUTPUT)
    
    $ make
    R CMD BATCH --no-save --no-restore download_source.R
    mv download_source.Rout output
    R CMD BATCH --no-save --no-restore source_to_interim.R
    mv source_to_interim.Rout output
    R CMD BATCH --no-save --no-restore plot_figs.R
    mv plot_figs.Rout output
    

    $&lt; 自动变量被 make 扩展为当前目标的第一个先决条件(这就是我重新排序 fig_A.pdffig_B.pdfinterim_data.csv 的先决条件的原因)。此外,您可以将带有配方的规则和带有先决条件(和没有配方)的规则分开。

    注意.NOTPARALLEL,它告诉 make 不要并行运行多个配方。在您的情况下,它是必需的,因为您有两个目标(fig_A.pdffig_B.pdf)产生相同的 plot_figs.Rout 副产品,该副产品被相同的配方移出。如果允许 make 以并行模式运行,则存在竞争条件的风险。

    3)

    这有点困难,因为您的食谱会产生 2 个不同的输出:*.csv(或*.pdf)和*.Rout。并且在设计时并未考虑到这种情况。它更倾向于一种配方=一种文件产品。但我们可以尝试使用宏 (R) 隐藏这些文件移动:

    $ cat Makefile
    .NOTPARALLEL:
    
    OUTPUT := output
    R      = R CMD BATCH --no-save --no-restore $(1) && mv $(1)out $(OUTPUT)
    PDF    := fig_A.pdf fig_B.pdf
    CSV    := interim_data.csv source_data.csv
    
    all: $(PDF) $(CSV)
    
    $(PDF): plot_figs.R interim_data.csv
    interim_data.csv: source_to_interim.R source_data.csv
    source_data.csv: download_source.R
    
    $(CSV) $(PDF):
        $(call R,$<)
    
    $ make
    R CMD BATCH --no-save --no-restore download_source.R && mv download_source.Rout output
    R CMD BATCH --no-save --no-restore source_to_interim.R && mv source_to_interim.Rout output
    R CMD BATCH --no-save --no-restore plot_figs.R && mv plot_figs.Rout output
    

    $(call...) make 函数扩展为其第一个参数变量 (R) 的值,其中 $(1) 已替换为第二个参数 ($&lt;),$(2) 已替换为第三个参数 (none in我们的案例),...

    注意R的定义:它使用递归赋值运算符(=),而不是简单的赋值运算符(:=),因为我们希望它只在需要时才被扩展,就在make通过配方之前到shell执行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-09
      • 1970-01-01
      • 2012-12-14
      • 1970-01-01
      • 1970-01-01
      • 2023-01-28
      • 1970-01-01
      • 2015-12-20
      相关资源
      最近更新 更多