2015-12-02 89 views
2

在数学中,当组合函数时,可以使用普通算术运算(例如,在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

如果你问“怎么做这个R中的最佳途径”,而不是你会得到更少的厌恶你的问题“做了包存在吗?” –

+1

可能会看到[** Ryacas **](https://cran.r-project.org/web/packages/Ryacas/index.html)包。例如'库(Ryacas); u < - 表达式(2 * x); v < - 表达式(log(x)); yacas(表达式(U + V));简化(yacas(表达式(U * U + V)));的eval(yacas(表达式(U + V))),列表(x = 44)'等 –

+0

(这一句应改为'的eval(yacas(表达式(U + V)),列表(x = 44) )') –

回答

3

这里有几种方法:

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)定义自己的函数这并不是真正意义上的工作。可能少于一页来定义所有常用功能。这可以使用%...%infix操作符完成,但是如果您确实想要使用上面的中缀路由(1),那么似乎更可取。所以采用这种方法我们保持简单。可以增强以下内容以允许将数值参数视为常量函数,就像我们在(1)中所做的那样。

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

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

方法1看起来非常接近,我在想什么的 - 很优雅。我也应该通过实施来学到很多东西。 –

4

这是一个中缀“+”的形式G.Grothendieck的答案投 - 运营商:

`%+%` <- 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页面需要被拉到了功能性成分的例子其中一个函数名称,例如?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 

一些这种编程风格可以通过哈德利的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 
+0

我认为,但它也需要为师,求幂和乘法特殊infixed(危险!)我可能需要编写代码,例如(在伪代码) lapply(参数, function.arithmetic(exp(u * v)/(1 + x)^ 2,x)) 等等 - 比我们通常使用的组合更容易阅读。 –

+0

好像您应该超出请求的伪代码级别并实际创建一些R对象来开始工作。无论是'u'还是'v'都没有用无错代码定义。 –

相关问题