10

是否可以在 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")

这个例子似乎适用于查尔斯解决方案:

`%@%` <- 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")

对我来说不太重要,但值得一提的是,以下陈述因查尔斯的解决方案而失败:

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

4 回答 4

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)
于 2012-07-04T15:07:00.520 回答
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快捷方式)

于 2012-07-04T14:27:10.693 回答
5

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

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

m %>% mean %>% sum

Ceci n'est pas un pipe!

于 2015-09-01T10:13:20.173 回答
4

与本的回答类似,但允许争论:

`%@%` <- 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
于 2012-07-05T05:18:02.457 回答