我的论文研究软件的源代码树(R
)反映了传统的研究工作流程:"收集数据 - >准备数据 - >分析数据 - >收集结果 - >发布结果"。我使用make
来建立和维护工作流程(大多数项目的子目录包含Makefile
个文件)。
但是,我经常需要通过项目子目录中的特定Makefile目标(不是通过顶级Makefile
)来执行工作流的各个部分。这会产生一个问题,即设置Makefile
规则以维护工作流不同部分的目标之间的依赖关系,换句话说 - {{1}中的目标之间文件,位于不同的子目录中。
以下代表我的论文项目的设置:
Makefile
我的部分+-- diss-floss (Project's root)
|-- import (data collection)
|-- cache (R data objects (), representing different data sources, in sub-directories)
|-+ prepare (data cleaning, transformation, merging and sampling)
|-- R modules, including 'transform.R'
|-- analysis (data analyses, including exploratory data analysis (EDA))
|-- R modules, including 'eda.R'
|-+ results (results of the analyses, in sub-directories)
|-+ eda (*.svg, *.pdf, ...)
|-- ...
|-- present (auto-generated presentation for defense)
文件中的目标片段:
"〜/ DISS-牙线/生成文件" (几乎已满):
Makefile
"〜/ DISS-牙线/进口/生成文件":
# Major variable definitions
PROJECT="diss-floss"
HOME_DIR="~/diss-floss"
REPORT={$(PROJECT)-slides}
COLLECTION_DIR=import
PREPARATION_DIR=prepare
ANALYSIS_DIR=analysis
RESULTS_DIR=results
PRESENTATION_DIR=present
RSCRIPT=Rscript
# Targets and rules
all: rprofile collection preparation analysis results presentation
rprofile:
R CMD BATCH ./.Rprofile
collection:
cd $(COLLECTION_DIR) && $(MAKE)
preparation: collection
cd $(PREPARATION_DIR) && $(MAKE)
analysis: preparation
cd $(ANALYSIS_DIR) && $(MAKE)
results: analysis
cd $(RESULTS_DIR) && $(MAKE)
presentation: results
cd $(PRESENTATION_DIR) && $(MAKE)
## Phony targets and rules (for commands that do not produce files)
#.html
.PHONY: demo clean
# run demo presentation slides
demo: presentation
# knitr(Markdown) => HTML page
# HTML5 presentation via RStudio/RPubs or Slidify
# OR
# Shiny app
# remove intermediate files
clean:
rm -f tmp*.bz2 *.Rdata
"〜/ DISS-牙线/准备/生成文件":
importFLOSSmole: getFLOSSmoleDataXML.R
@$(RSCRIPT) $(R_OPTS) $<
...
&#34;〜/ DISS-牙线/分析/生成文件&#34;:
transform: transform.R
$(RSCRIPT) $(R_OPTS) $<
...
目前,我担心创建以下依赖项:
通过eda: eda.R
@$(RSCRIPT) $(R_OPTS) $<
中的Makefile
制作目标而收集的数据始终需要通过在import
中Makefile
制作相应的目标进行转换,然后再进行分析,示例prepare
。如果我在eda.R
中手动运行make
,然后忘记转换,请在import
中运行make eda
,事情进展不顺利。因此,我的问题是:
我如何使用analyze
实用程序的功能(以最简单的方式)来建立和维护不同目录中make
个文件的目标之间的依赖关系规则?
答案 0 :(得分:1)
您现在使用makefile的问题是您只将代码列为依赖项,而不是数据。这就是很多魔法发生的地方。如果&#34;分析&#34;我知道它将使用哪些文件并将它们列为依赖项,它可以回顾它们是如何制作的以及它们具有的依赖关系。如果管道中的早期文件已更新,则可以运行所有必要的步骤以使文件保持最新。例如
import: rawdata.csv
rawdata.csv:
scp remoteserver:/rawdata.csv .
transform: tansdata.csv
transdata.csv: gogo.pl rawdata.csv
perl gogo.pl $< > $@
plot: plot.png
plot.png: plot.R transdata.csv
Rscript plot.R
因此,如果我执行make import
,它将下载新的csv文件。然后,如果我运行make plot
,它会尝试生成plot.png
,但这取决于transdata.csv
,这取决于rawdata.csv
,并且自rawdata.csv
更新后,它将会更新需要更新transdata.csv
然后它就可以运行R脚本了。如果您没有明确设置很多文件依赖项,那么您就会错失许多make的强大功能。但是要失败,有时候在那里获得所有正确的依赖关系会很棘手(特别是如果你从一个步骤产生多个输出)。
答案 1 :(得分:0)
以下是关于将我的研究工作流程的数据依赖性添加到项目当前的想法(来自@ MrFlick的一些想法 - 谢谢) make
基础架构(使用代码段)。我还尝试通过在make
目标之间指定依赖关系来反映所需的工作流程。
导入/生成文件:强>
importFLOSSmole: getFLOSSmoleDataXML.R FLOSSmole.RData
@$(RSCRIPT) $(R_OPTS) $<
@touch $@.done
(similar targets for other data sources)
<强>准备/生成文件:强>
IMPORT_DIR=../import
prepare: import \
transform \
cleanup \
merge \
sample
import: $IMPORT_DIR/importFLOSSmole.done # and/or other flag files, as needed
transform: transform.R import
@$(RSCRIPT) $(R_OPTS) $<
@touch $@.done
cleanup: cleanup.R transform
@$(RSCRIPT) $(R_OPTS) $<
@touch $@.done
merge: merge.R cleanup
@$(RSCRIPT) $(R_OPTS) $<
@touch $@.done
sample: sample.R merge
@$(RSCRIPT) $(R_OPTS) $<
@touch $@.done
<强>分析/生成文件:强>
PREP_DIR=../prepare
analysis: prepare \
eda \
efa \
cfa \
sem
prepare: $PREP_DIR/transform.done # and/or other flag files, as needed
eda: eda.R prepare
@$(RSCRIPT) $(R_OPTS) $<
@touch $@.done
efa: efa.R eda
@$(RSCRIPT) $(R_OPTS) $<
@touch $@.done
cfa: cfa.R efa
@$(RSCRIPT) $(R_OPTS) $<
@touch $@.done
sem: sem.R cfa
@$(RSCRIPT) $(R_OPTS) $<
@touch $@.done
目录Makefile
和results
中present
个文件的内容仍为TBD。
感谢您对上述内容的想法和建议!