15

有没有办法在 R 中编写流水线函数,其中一个函数的结果立即传递到下一个函数?我来自 F#,非常欣赏这种能力,但还没有找到如何在 R 中做到这一点。它应该很简单,但我找不到方法。在 F# 中,它看起来像这样:

let complexFunction x =
     x |> square 
     |> add 5 
     |> toString

在这种情况下,输入将被平方,然后添加 5,然后转换为字符串。我希望能够在 R 中做类似的事情,但不知道如何做。我已经搜索过如何做这样的事情,但没有遇到任何事情。我想要这个来导入数据,因为我通常必须导入它然后过滤。现在,我分多个步骤执行此操作,并且真的希望能够像在 F# 中使用管道那样做一些事情。

4

5 回答 5

8

这是一种使用Reduce. 这实际上是一个例子?Reduce

square <- function(x) x^2
add_5 <- function(x)  x+5
x <- 1:5
## Iterative function application:
Funcall <- function(f, ...) f(...)

Reduce(Funcall, list(as.character, add_5, square,x), right = TRUE)
## [1] "6"  "9"  "14" "21" "30"

或者更简单地使用functional包和Compose

这很好,因为它将为您创建功能

library(functional)
do_stuff <-   Compose(square,add_5,as.character )
do_stuff(1:5)
##  [1] "6"  "9"  "14" "21" "30"

我注意到我不会认为这两种方法中的任何一种都是惯用的R(如果这甚至是一个短语)

于 2012-11-13T01:40:59.613 回答
7

我们可以Compose从功能包中使用来创建我们自己的二元运算符,它执行类似于您想要的操作

# Define our helper functions
square <- function(x){x^2}
add5 <- function(x){x + 5}

# functional contains Compose
library(functional)

# Define our binary operator
"%|>%" <- Compose

# Create our complexFunction by 'piping' our functions
complexFunction <- square %|>% add5 %|>% as.character
complexFunction(1:5)
#[1] "6"  "9"  "14" "21" "30"


# previously had this until flodel pointed out
# that the above was sufficient
#"%|>%" <- function(fun1, fun2){ Compose(fun1, fun2) }

我想我们可以在不需要功能包的情况下从技术上做到这一点——但它感觉非常Compose适合用于这项任务。

"%|>%" <- function(fun1, fun2){
    function(x){fun2(fun1(x))}
}
complexFunction <- square %|>% add5 %|>% as.character
complexFunction(1:5)
#[1] "6"  "9"  "14" "21" "30"
于 2012-11-13T02:52:00.110 回答
5

我认为您可能只想编写一个函数来执行您想要的步骤。

complexFunction <- function(x) {
    as.character(x^2 + 5)
}

然后只需调用complexFunction(x).


编辑以显示R在内部做什么(@mnel)——R解析和评估的方式as.character(x^2 + 5)是你想要的

您可以使用codetools来调查什么R 来查看值是如何传递给彼此的

flattenAssignment(quote(as.character(x^2+5)))
[[1]]
[[1]][[1]]
x

[[1]][[2]]
`*tmp*`^2

[[1]][[3]]
`*tmp*` + 5


[[2]]
[[2]][[1]]
`as.character<-`(`*tmp*`, value = `*tmpv*`)

[[2]][[2]]
`+<-`(`*tmp*`, 5, value = `*tmpv*`)

[[2]][[3]]
`^<-`(x, 2, value = `*tmpv*`)

或者您可以获取 Lisp 样式表示以查看它是如何解析的(以及传递的结果)

showTree(quote(as.character(x^2+5)))
(as.character (+ (^ x 2) 5))
于 2012-11-13T00:57:58.567 回答
3

自从提出这个问题以来,magrittr管道在 R 中变得非常流行。所以你的例子是:

library (magrittr)

fx <- function (x) {
     x %>%
     `^` (2) %>%
     `+` (5)  %>%
     as.character ()
     }

请注意,反引号表示法是因为我实际上是在使用 R 的内置函数,我需要特别引用它们才能以这种方式使用它们。更通常命名的函数(比如exp或者如果我创建了一个辅助函数add)不需要反引号,并且看起来更像你的例子。

另请注意,%>%将传入值作为第一个参数自动传递给下一个函数,尽管您可以更改它。另请注意,R 函数返回计算的最后一个值,因此我不需要return或分配计算来返回它。

这很像其他答案定义的很好的特殊运算符,但它使用了现在在 R 中广泛使用的特定函数。

于 2018-01-14T14:57:17.983 回答
0

这适用于 R 在 F# 中非常相似:

"%|>%" <- function(x, fun){
    if(is.function(x)) {
      function(...) fun(x(...))
    } else {
      fun(x)
    }
}
于 2014-03-17T15:05:23.767 回答