【问题标题】:R - Connect Scripts via PipesR - 通过管道连接脚本
【发布时间】:2013-07-30 22:22:23
【问题描述】:

我有许多 R 脚本,我想使用 UNIX 风格的管道将它们链接在一起。每个脚本都会将一个数据框作为输入,并提供一个数据框作为输出。例如,我想像这样的东西可以在 R 的批处理模式下运行。

  cat raw-input.Rds | step1.R | step2.R | step3.R | step4.R > result.Rds

对如何做到这一点有任何想法吗?

【问题讨论】:

  • 您想要 R 代码来了解如何执行此操作吗?也许通过一系列source 调用?
  • 只需通过命令行将它们连接在一起。

标签: r unix pipe


【解决方案1】:

编写可执行脚本并不是难事,棘手的是如何使脚本从文件和/或管道中读取。我在这里写了一个有点通用的函数: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 -

【讨论】:

    【解决方案2】:

    当你拥有整个 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(...)
    

    【讨论】:

    • ...可能出于与您编写函数相同的原因。脚本就像您编写的构建块,因此您可以在以后以任何您喜欢的方式组合它们。此外,脚本不限于 R:它们可以用您喜欢的任何语言编写。您可以轻松获得所有 unix 好东西(例如 grep)。
    • @flodel 但这些不是我们正在谈论的通用脚本。这些是 R 脚本,它们在允许比字节流更丰富的对象的环境中执行。此外,R 有许多(太多?)模仿操作系统级实用程序的函数;如果您需要更多,您可能不应该为此目的使用 R。
    • 此外,如果你想要 R 中的模块化代码,比如函数,你可以使用...函数。如果source一堆函数定义对您来说不够正式,您可以将它们放入一个包中。
    • 如果您知道和使用的只是 R,来自交互式会话。 OP 已经在编写脚本这一事实告诉我,他已经超越了这种简单的用法。
    • @flodel ???交互式使用与它无关。关键是管道是编写模块化 R 代码的次优方式。
    【解决方案3】:

    您需要在每个脚本的顶部添加一行以从stdin 读取。通过this answer

    in_data <- readLines(file("stdin"),1)
    

    您还需要将每个脚本的输出写入stdout()

    【讨论】:

      猜你喜欢
      • 2019-04-21
      • 1970-01-01
      • 1970-01-01
      • 2014-10-27
      • 2017-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多