可重复的研究:通过使用GNU make调用statTransfer将sas7bdat数据文件转换为csv文件

时间:2013-12-16 17:14:51

标签: r csv makefile reproducible-research

问题:

我是GNU Make的新手。是否有更好的方法以编程方式将统计数据集从sas7bdat转换为csv文件并使用GNU Make使它们保持同步以促进可重复的研究?您是否会从编码角度以不同的方式处理此问题,或者是否有更好的方法来促进可重复的研究?我可以在使用静态模式规则时添加其他先决条件(即statTransferOptions.txt)吗?

解决方案需要:

  • 查找所有子目录中的所有sas7bdat文件
  • 阅读statTransfer选项
  • 使用带选项的statTransfer命令行工具将sas7bdat文件转换为csv文件
  • 鉴于statTransfer目前的局限性,我认为这需要两个步骤:
    • 为每个SAS数据文件构建statTransfer命令文件( .stcmd)( .sas7bdat)
    • 使用stcmd文件中的选项执行statTransfer(st)为每个stcmd文件构建csv文件
    • 目标stcmd和csv文件应与先决条件sas7bdat文件位于同一子目录中
    • 查找过时的stcmd和csv文件,如果存在新的sas7bdat文件或基本选项文件发生更改,则更新它们

背景:

我继承了每年发布的大型统计报告。在过去几年中,分析是在SAS中完成的。我们现在正在使用R. SAS Enterprise Guide生成的某些sas7bdat文件无法正确导入sas7bdat package。 StatTransfer是一种商业产品,具有命令行界面,可以将sas7bdat文件正确转换为csv文件;但是,有一些选项可以改善转换(例如,编写日期格式)。 sas7bdat文件位于与数据集类型和年份对应的多个子目录中。

这种方法还得到以下提示:

Gandrud,Christopher(2013-06-21)。使用R和RStudio进行可重复研究(Chapman& Hall / CRC The R Series)(pp.104-105)。查普曼和霍尔/ CRC。 Kindle版。

故障:

建议的MAKEFILE?

RDIR := .

######
#PREP#
######
# Use BASH shell to create list of source sas7bdat files
SASDATA = $(shell find $(RDIR) -type f -name '*.sas7bdat')

# Use pattern substring functions to define variable list of filenames
# to be used as targets in recipes
STCMD_OUT = $(patsubst $(RDIR)/%.sas7bdat, $(RDIR)/%.stcmd, $(SASDATA))
CSV_OUT = $(patsubst $(RDIR)/%.sas7bdat, $(RDIR)/%.csv, $(SASDATA))

#########
#TARGETS#
#########

all: $(STCMD_OUT) $(CSV_OUT)

# I think the name "static pattern rules" is misleading
# but I found this to be helpful:
# http://www.gnu.org/software/make/manual/make.html#Static-Pattern

# can I add statTransferOptions.txt as a pre-requisite while using static pattern rules?

$(STCMD_OUT): $(RDIR)/$(@D)/%.stcmd: $(RDIR)/$(@D)/%.sas7bdat
    cp $(RDIR)/statTransferOptions.txt $@
    echo copy $(RDIR)/$< delim $(RDIR)/$(basename $<).csv -v >> $@
    echo quit >> $@

$(CSV_OUT): $(RDIR)/$(@D)/%.csv: $(RDIR)/$(@D)/%.stcmd
    st $(RDIR)/$<

clean:
    rm $(STCMD_OUT)
    rm $(CSV_OUT)

从SO输入后修改后的MAKE文件:

RDIR := .

######
#PREP#
######
# Create list of source sas7bdat files
SASDATA := $(shell find $(RDIR) -type f -name '*.sas7bdat')

STCMD_OUT := $(patsubst $(RDIR)/%.sas7bdat, $(RDIR)/%.stcmd, $(SASDATA))
CSV_OUT := $(patsubst $(RDIR)/%.sas7bdat, $(RDIR)/%.csv, $(SASDATA))

#########
#TARGETS#
#########

all: $(STCMD_OUT) $(CSV_OUT)

$(STCMD_OUT): %.stcmd: %.sas7bdat statTransferOptions.txt
    cp $(RDIR)/statTransferOptions.txt $@
    echo copy $(RDIR)/$< delim $(RDIR)/$(basename $<).csv -v -y >> $@
    echo quit >> $@

$(CSV_OUT): %.csv: %.stcmd
    st $(RDIR)/$<

clean:
    rm $(STCMD_OUT)
    rm $(CSV_OUT)

但是,正确的选项可能是调试CRAN sas7bdat包,以便整个工具链可用而不是调用专有的statTransfer。

1 个答案:

答案 0 :(得分:2)

在SO中,我们通常没有时间或精力(或通常是兴趣)来阅读相关的论文,选项,替代方案等。如果您只是简单明确地指出您遇到的问题,那么它最有效。 (在这种情况下,提供的makefile非常好),你遇到的确切问题包括错误消息或错误输出(这在你的问题中并不明显),你想要发生的事情没有发生,因为这并不总是很清楚,也许你尝试过的任何其他想法或方向都没有用。

我不确定你遇到的问题究竟是什么,但我发现你的makefile有很多问题。首先,这将起作用,但效率非常低:

SASDATA = $(shell find $(RDIR) -type f -name '*.sas7bdat')

您应该在此处使用:=形式的作业。可能在设置STCMD_OUTCSV_OUT时也应该使用它,尽管这不太重要。

但最重要的是,这些规则并不正确:

$(STCMD_OUT): $(RDIR)/$(@D)/%.stcmd: $(RDIR)/$(@D)/%.sas7bdat

您不能在目标或先决条件列表中使用$@(或其任何替代形式)等自动变量。自动变量仅在规则的配方中定义。你可以使用二次扩展,但我不确定你为什么要这样做。为什么不直接使用:

$(STCMD_OUT): %.stcmd: %.sas7bdat

?同样适用于其他静态模式规则?

至于你的问题,是的,将statTransferOptions.txt等额外先决条件添加到静态模式规则中是完全可以的。