用R链接的方法

时间:2012-07-04 14:05:27

标签: r method-chaining

是否可以在R?

中链接函数

示例数据:

m <- matrix(c(1:10, 11:20), nrow = 10, ncol = 2)

例如,我想替换以下语句:

step1 <- mean(m)
step2 <- sum(step1)
res <- step2

或者,

res <- sum(mean(m))

有这样的事情:

res <- m@mean()@sum()

在某些情况下,这会大大澄清我的代码。

EDIT1 这是一个虚拟的例子。我随机选择了'sum'和'mean'。

Ben使用%@%给出了第一个答案,但它阻止在函数中使用额外的参数:

m %@% function1(arg1, arg2) %@% function2(arg1, arg2)

我该如何解决这个问题?

EDIT2 添加示例

require(xts)
require(PerformanceAnalytics)
xts.ts <- xts(rnorm(231),as.Date(13514:13744,origin="1970-01-01"))
plot(na.omit(lag( rollapply(xts.ts, width=rolling.per-1, FUN= function(x){sqrt(var(x))*sqrt(252)}), k=1)), main = "Dummy Example")

此示例似乎与Charles解决方案一起正常工作:

`%@%` <- function(x, f) eval.parent(as.call(append(as.list(substitute(f)), list(x), 1)))
xts.ts %@% rollapply( width = rolling.per-1, FUN= function(x) x%@%var%@%sqrt * sqrt(252) ) %@% lag( k=1) %@% na.omit %@% plot(main = "Dummy Example")

对我的案子不太重要,但是提到的是,以下的陈述在Charles的解决方案中失败了:

 xts.ts %@% names <- 'ts name' 

4 个答案:

答案 0 :(得分:12)

尝试功能包:

library(functional)
squared <- function(x)x*x
Compose(sum, squared)(m)
## [1] 44100
squared(sum(m))
## [1] 44100

编辑:

关于有关参数的另一个回复的评论中的问题,这里是一个用参数组成的例子。 Curry也来自功能包:

addn <- function(n, x) x + n
Compose(Curry(addn, 1), squared)(10)
## [1] 121
squared(addn(1, 10))
## [1] 121

编辑2:

关于调试的问题,debug如果函数是咖喱的,则有效。如果它还没有咖喱,那么将其包裹在Curry

# this works since addn is curried
debug(addn)
Compose(Curry(addn, 1), squared)(10)

# to debug squared put it in a Curry -- so this works:
debug(squared)
Compose(Curry(addn, 1), Curry(squared))(10)

答案 1 :(得分:9)

排序,但我认为这不是惯用的,也许是脆弱的/不是个好主意。 (我认为,这可以通过@ RichieCotton上面的评论暗示。)

来自http://cran.r-project.org/doc/manuals/R-lang.html

  

10.3.4特殊操作员

     

R允许用户定义的中缀运算符。它们具有由'%'字符分隔的字符串形式。字符串可以   包含除'%'以外的任何可打印字符。逃逸序列   字符串不适用于此。

     

请注意,以下运算符是预定义的

 %% %*% %/% %in% %o% %x%
"%@%" <- function(x,f) {
    f(x)
}

sqr <- function(x) x^2
x <- 1:4

x %@% mean  ## 2.5
x %@% mean %@% sqr  ## 6.25
x %@% (mean %@% sqr)  ## fails

鉴于上面定义的m - 也许你想到的是什么?

 m %@% colMeans %@% sum  ## 21

注意:

  • 你的例子有点搞笑,因为mean(x)总是返回一个标量(即长度为1的向量),所以sum(mean(x))总是与mean(x)相同
  • 中缀运算符必须被%包围,因此您不能拥有像单个符号那样紧凑的内容(并且已经采用%%)。
  • 这种链接是非关联性的,这让我很担心 - 看起来上面的例子很有用,所以R(显然)从左到右进行评估,但我不知道这是有保证的......

编辑:问题现在询问如何合并其他参数。我不认为建议的语法(x %@% fun1(arg1) %@% fun2(arg2))可以在没有一些严重魔法的情况下起作用。这是我目前最接近的 - 创建一个包装函数,创建原始函数的修改版本。

F <- function(f,...) {
    function(x) {
        f(x,...)
    }
}

测试:

pow <- function(x,b=2) { x^b }
sqr <- function(x) x^2
x <- 1:4

x %@% F(mean,na.rm=TRUE)  ## 2.5
x %@% F(mean,na.rm=TRUE) %@% F(pow,3)  ## 16.25

(请注意,我在这里使用F作为函数,在某些情况下可能会有点冒险,因为它会覆盖F==FALSE快捷方式)

答案 2 :(得分:4)

与Ben的答案类似,但允许参数:

`%@%` <- function(x, f) eval.parent(as.call(append(as.list(substitute(f)), list(x), 1)))

x %@% mean %@% sqr # => 6.25
c(1, 2, NA, 3, 4) %@% mean(na.rm=T) %@% sqr # => 6.25
m %@% colMeans() %@% sum() # => 21

答案 3 :(得分:4)

我会使用magrittr包。它有一个&#34;管道&#34;获取一个函数的结果并将其作为参数传递给下一个函数的运算符:

m <- matrix(c(1:10, 11:20), nrow = 10, ncol = 2)

m %>% mean %>% sum

Ceci n&#39; est pas un pipe!