r-可再现研究:通过使用GNU make调用statTransfer将sas7bdat数据文件转换为csv文件



问题:

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

解决方案需要:

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

上下文:

我继承了一份每年出版的大型统计报告。前几年,SAS进行了分析。我们现在使用的是R。SAS Enterprise Guide生成的一些sas7bdat文件无法正确导入sas7bdat包。StatTransfer是一款商业产品,它有一个命令行界面,可以正确地将sas7bdat文件转换为csv文件;然而,也有一些选项可以改进转换(例如,编写日期格式)。sas7bdat文件位于多个子目录中,对应于数据集的类型和年份。

进一步推动了这种方法

Gandrud,Christopher(2013-06-21)。R和RStudio的可复制研究(Chapman&Hall/CRC R系列)(第104-105页)。Chapman和Hall/CRC。Kindle版

故障排除:

  • 这几乎实现了我想要的:GNU中的递归通配符是什么

建议的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输入后修改了MAKEFILE:

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。

在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)是完全可以的。

最新更新