用R链接的方法

Sam*_*Sam 10 r method-chaining

是否可以在R中链接函数?

样本数据:

m <- matrix(c(1:10, 11:20), nrow = 10, ncol = 2)
Run Code Online (Sandbox Code Playgroud)

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

step1 <- mean(m)
step2 <- sum(step1)
res <- step2
Run Code Online (Sandbox Code Playgroud)

要么,

res <- sum(mean(m))
Run Code Online (Sandbox Code Playgroud)

有这样的事情:

res <- m@mean()@sum()
Run Code Online (Sandbox Code Playgroud)

在某些情况下,这将大大澄清我的代码.

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

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

m %@% function1(arg1, arg2) %@% function2(arg1, arg2)
Run Code Online (Sandbox Code Playgroud)

我该如何解决这个问题?

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")
Run Code Online (Sandbox Code Playgroud)

这个例子似乎适用于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")
Run Code Online (Sandbox Code Playgroud)

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

 xts.ts %@% names <- 'ts name' 
Run Code Online (Sandbox Code Playgroud)

G. *_*eck 12

试试功能包:

library(functional)
squared <- function(x)x*x
Compose(sum, squared)(m)
## [1] 44100
squared(sum(m))
## [1] 44100
Run Code Online (Sandbox Code Playgroud)

编辑:

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

addn <- function(n, x) x + n
Compose(Curry(addn, 1), squared)(10)
## [1] 121
squared(addn(1, 10))
## [1] 121
Run Code Online (Sandbox Code Playgroud)

编辑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)
Run Code Online (Sandbox Code Playgroud)


Ben*_*ker 9

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

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

10.3.4特殊操作员

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

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

 %% %*% %/% %in% %o% %x%
Run Code Online (Sandbox Code Playgroud)
"%@%" <- 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
Run Code Online (Sandbox Code Playgroud)

鉴于m上述定义的-也许你脑子里想的是什么?

 m %@% colMeans %@% sum  ## 21
Run Code Online (Sandbox Code Playgroud)

笔记:

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

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

F <- function(f,...) {
    function(x) {
        f(x,...)
    }
}
Run Code Online (Sandbox Code Playgroud)

测试:

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
Run Code Online (Sandbox Code Playgroud)

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


sdg*_*sdh 5

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

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

m %>% mean %>% sum
Run Code Online (Sandbox Code Playgroud)

Ceci n'est pas un pipe!


Cha*_*les 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
Run Code Online (Sandbox Code Playgroud)