对R中的函数进行算术运算的最佳方法是什么?

时间:2015-12-02 18:03:38

标签: r

在数学中,当组合函数时,您可以使用普通的算术运算来表明这一点,例如

u = 2*x
v = log(x)

然后简单地

f = u + v

我做了很多数值工作,你必须构建复杂的数学运算。能够使用更像这样的符号会非常有帮助。例如,在R中它可能看起来像

f <- function.arithmetic('u+v', args=c('x'))

通过一些非标准评估,这可能就像

一样简单
f(x) %def% u + v

其中u和v已经定义了x的函数。

有没有简单的方法来设置此语法?例如,分解表达式并用u(x)和v(x)代替它们 - 然后做一个普通的eval。 (我相信现有的解析功能比我写的一些黑客更多。而且我知道“解析”不会这样做。)

已经建议的答案可行,但它们似乎比编写

更复杂
f <- function(x) u(x) + v(x)

如果表达式更复杂,这种表示法开始变得越来越难以阅读。我想设置一些更简单,更易读,更接近上述数学符号的东西。

2 个答案:

答案 0 :(得分:4)

这是G.Grothendieck的答案,以中缀&#34; +&#34; -operator:

的形式出现
 `%+%` <- function(f1, f2) { function(x) {f1(x) +f2(x)} }

  f <- cos %+% sin
f
#-----
function(x) {f1(x) +f2(x)}
<environment: 0x7ffccd7eeea8>
#-------

f(0)
#[1] 1

在funprog&#39;上也有功能组合的例子。需要使用其中一个函数名称提取的页面,例如?Reduce。也可以定义为接受其他参数:

`%+%` <- function(f1, f2) { function(x,...) {f1(x,...) +f2(x,...)} }
f2 <- dt %+% dt
#-- testing---
> f2(0)
Error in f1(x, ...) : argument "df" is missing, with no default
> f2(0, 6)
[1] 0.7654655
> dt(0,6)
[1] 0.3827328

要了解如何在内部处理此问题,您可以通过检查存储在结果闭包中的环境来恢复定义:

> ls(envir=environment(f2) )
[1] "f1" "f2"
> environment(f2)$f1
function (x, df, ncp, log = FALSE) 
{
    if (missing(ncp)) 
        .Call(C_dt, x, df, log)
    else .Call(C_dnt, x, df, ncp, log)
}
<bytecode: 0x7ffcc63e8ff8>
<environment: namespace:stats>

您的示例的问题在于您没有以R函数方式定义u和v。据推测,这不是您提议的用例的情况。

> u = function(x,...)2*x
> v = function(x,...) (log(x))
> f <- u %+% v
> f(4)
[1] 9.386294

Hadley的lazyeval软件包可能支持某些编程风格:

> require(lazyeval)
Loading required package: lazyeval
> help(pac=lazyeval)
> lazy_eval(interp(~ u + v, u =  sum(1:10), v=sum(1:5)) )
[1] 70
> x <- 1:10; y=1:5
> lazy_eval(interp(~ u + v, u =  sum(x), v=sum(y)) )
[1] 70
> lazy_eval(interp(~ u / v, u =  sum(x), v=sum(y)) )
[1] 3.666667
> lazy_eval(interp(~ log(u) / v, u =  sum(x), v=sum(y)) )
[1] 0.2671555

但是我遇到了一些我无法理解的难题:

e2 <- ~ exp(u * v)/(1 + x)^2
lazy_eval(interp(e2, u =  sum(x)/100, v=sum(y)/100) )
 #[1] 0.271499668 0.120666519 0.067874917 0.043439947 0.030166630 0.022163238 0.016968729
 #[8] 0.013407391 0.010859987 0.008975196

 exp( sum(x)/100 +sum(y)/100 )/(1+x)^2
 [1] 0.50343818 0.22375030 0.12585954 0.08055011 0.05593758 0.04109699 0.03146489 0.02486114
 [9] 0.02013753 0.01664258

答案 1 :(得分:4)

以下是两种方法:

1)Ops / Math 这可以使用S3或S4完成。我们只说明了S3。

Compose <- function(f, g) {
    if (missing(g)) structure(f, class = c("functional", "function"))
    else Compose(function(...) f(g(...)))
}

Ops.functional <- function(e1, e2) {
  op <- match.fun(.Generic)
  Compose( if (is.numeric(e1)) function(...) op(e1, e2(...)) 
           else if (is.numeric(e2)) function(...) op(e1(...), e2) 
           else function(...) op(e1(...), e2(...)))
}

Math.functional <- function(x, ...) {
  op <- match.fun(.Generic)
  Compose(op, x)
}

以下是两个例子:

u <- Compose(function(x) 2*x)
v <- Compose(log)

(u + v)(pi/2)  # example 1
## [1] 3.593175

(exp(u*v) / (1 + u^2 + v^2)) (pi/2)  # example 2
## [1] 0.3731149

注意: u可以交替定义为u <- 2 * Compose(identity)。事实上,我们可以定义:

Id <- Compose(identity)
u <- 2*Id
v <- log(Id)

2)定义自己的功能这不是很多工作。可能不到一页定义所有常见功能。这可以使用%...%中缀运算符来完成,但如果你真的想要使用上面的中缀路由(1)似乎更可取。因此,通过这种方法,我们保持简单。可以增强以下内容,以允许数字参数被视为常量函数,如我们在(1)中所做的那样。

Plus <- function(f, g) function(...) f(...) + g(...)

Plus(function(x) 2*x, log)(pi/2)
## [1] 3.593175