我有许多R脚本,我想使用UNIX风格的管道链接在一起。每个脚本都将数据帧作为输入,并提供数据帧作为输出。例如,我想象这样会在R的批处理模式下运行。
cat raw-input.Rds | step1.R | step2.R | step3.R | step4.R > result.Rds
有关如何做到这一点的任何想法?
答案 0 :(得分:4)
编写可执行脚本并不困难,如何从文件和/或管道中读取脚本是多么棘手。我在这里写了一个有点通用的函数:https://stackoverflow.com/a/15785789/1201032
以下是I / O采用csv文件形式的示例:
您的step?.R
文件应如下所示:
#!/usr/bin/Rscript
OpenRead <- function(arg) {
if (arg %in% c("-", "/dev/stdin")) {
file("stdin", open = "r")
} else if (grepl("^/dev/fd/", arg)) {
fifo(arg, open = "r")
} else {
file(arg, open = "r")
}
}
args <- commandArgs(TRUE)
file <- args[1]
fh.in <- OpenRead(file)
df.in <- read.csv(fh.in)
close(fh.in)
# do something
df.out <- df.in
# print output
write.csv(df.out, file = stdout(), row.names = FALSE, quote = FALSE)
并且您的csv输入文件应如下所示:
col1,col2
a,1
b,2
现在这应该有效:
cat in.csv | ./step1.R - | ./step2.R -
-
很烦人但很有必要。还要确保运行类似chmod +x ./step?.R
的内容以使脚本可执行。最后,您可以将它们(并且没有扩展名)存储在您添加到PATH的目录中,这样您就可以像这样运行它:
cat in.csv | step1 - | step2 -
答案 1 :(得分:3)
为什么在整个R环境可用时,你想要将工作流程塞进管道中是不可能的。
制作一个包含以下内容的main.r
:
source("step1.r")
source("step2.r")
source("step3.r")
source("step4.r")
就是这样。您不必将每个步骤的输出转换为序列化格式;相反,您可以保留所有R对象(数据集,拟合模型,预测值,格子/ ggplot图形等),为下一步处理做好准备。如果内存有问题,您可以在每个步骤结束时rm
任何不需要的对象;或者,每个步骤都可以使用它在完成后删除的environment
,首先将所有必需的对象导出到全局环境。
如果需要模块化代码,您可以按如下方式重新设定工作流程。将每个文件完成的工作封装到一个或多个函数中。然后使用适当的参数在main.r
中调用这些函数。
source("step1.r") # defines step1_read_input, step1_f2
source("step2.r") # defines step2_f2
source("step3.r") # defines step3_f1, step3_f2, step3_f3
source("step4.r") # defines step4_write_output
step1_read_input(...)
step1_f2(...)
....
step4write_output(...)
答案 2 :(得分:0)
您需要在每个脚本的顶部添加一行,以便从stdin
读入。通过this answer:
in_data <- readLines(file("stdin"),1)
您还需要将每个脚本的输出写入stdout()
。