【问题标题】:How to use Reduce to create a new function from a list of functions?如何使用 Reduce 从函数列表中创建新函数?
【发布时间】:2013-09-15 11:17:45
【问题描述】:

我想添加一些函数 f1,f2,...,fn 以便我有一个新函数产生 f(x)=f1(x)+...+fn(x)(称为逐点加法)。所以我有一个功能列表并尝试过

Reduce("funadd",fun.list)

其中 funadd 定义为

funadd <- function(f1,f2){
    retfun <- function(x){
        f1(x)+f2(x)
    }
    retfun
}

在两个函数上测试 funadd 时,它可以完美运行。但是,当我尝试评估 Reduce 命令的结果时,我得到了错误

Error: evaluation nested too deeply: infinite recursion / options(expressions=)?

【问题讨论】:

  • 只是说这是一种对函数求和的非常低效的方法。您的 sum 函数将需要 n-1 个额外的函数调用,这在 R 中非常耗时。

标签: r reduce


【解决方案1】:

有趣的是Reduce 不起作用...请注意“手动减少”有效:

f <- function(x) x^2
g <- function(x) x^3
h <- function(x) x^4
x <- runif(3)

f(x)+g(x)+h(x)
#[1] 0.9760703 0.1873004 0.1266966

funadd(funadd(f,g),h)(x)
#[1] 0.9760703 0.1873004 0.1266966

或者,你可以使用这个:

funadd2 <- function(...){
    function(x) Reduce(`+`, lapply(list(...), function(f) f(x)))
}

funadd2(f,g,h)(x)
#[1] 0.9760703 0.1873004 0.1266966

编辑:这是怎么回事:

查看Reduce 的源代码,我们可以看到它(大致)有一个循环执行此操作:

init <- f
init <- funadd(init, g)

如果有更多元素,则继续(init &lt;- funadd(init, h),...)。

这会导致对f 的引用在第一次循环迭代中丢失:

init(x)
# Error: evaluation nested too deeply: infinite recursion / options(expressions=)?

这是因为最后一个retfun 中的f1 指向自己:

identical(environment(init)$f1, init, ignore.environment=FALSE)
# [1] TRUE

正如@Vincent 发现的那样,这也可以通过强制参数来解决,即通过制作一个避免对f1f2 进行懒惰评估的本地副本:

funadd3 <- function(f1,f2){
    f1.save <- f1
    f2.save <- f2
    retfun <- function(x){
        f1.save(x)+f2.save(x)
    }
    retfun
}

Reduce(funadd3, list(f,g,h))(x)
# [1] 0.9760703 0.1873004 0.1266966

【讨论】:

  • 是的,我还注意到手工减少与迭代相比。真的很奇怪!我认为它很优雅......
【解决方案2】:

强制评估参数可以解决问题。

funadd <- function(f1,f2){
    force(f1)
    force(f2)
    retfun <- function(x){
        f1(x)+f2(x)
    }
    retfun
}
r <- Reduce( funadd, list( f, g, h ) )
r(x)  # works

【讨论】:

    猜你喜欢
    • 2016-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-27
    • 2013-11-14
    相关资源
    最近更新 更多