R:嵌套函数中的作用域,第 2 部分:嵌套 do.call 的

R: Scope in nested functions, part 2: nested do.call's

这里我有一个真正的问题和一个大大简化的问题,可能会或可能不会概括我对第一个问题的困惑。

下面的函数multi_quad应该整合dfun,这里dgb2来自GB2包,超过了从下限lb到上限ub。 base-R integrate 函数成功地对此处给出的参数值和限制进行了此集成,但对 ub=4.55e8 或更多失败。我有一个关于这个问题的问题,here: R: Convergence problems with numerical integration

我努力解决收敛问题,我有下面的函数 multi_quad,它应该尝试与 pracma 包中的各种替代正交方法集成。我正在使用 purrr 包中的 safely( ) 尝试尝试所有方法,如果它们收敛则为 return 值,否则为错误消息。

对于 map 的每次迭代,我都会收到参数 "lb" is missing, with no default 的错误。这里外层do.call的围层和调用环境都是m_quad的执行环境,m_quad的围层和调用环境都是[=57=的执行环境=].由于我为 multi_quad 提供了 lb 的值,因此我希望 m_quaddo.call 能够找到它,无论 lb 在外部 do.call 范围。这是不正确的,我不知道为什么。

library(GB2)
library(pracma)
library(purr)

multi_quad <- function(dfun, params, lb, ub){
  m_quad <- function(q_method, dfun, params, lb, ub){
    do.call(what=q_method, 
            args=list(f=function(X){do.call(what=dfun, args=params)}, a=lb, b=ub))
    }
  safe_m_quad <- safely(m_quad)
  q_methods<- list("quadgk",  "quadcc",  "simpadpt", "renshaw", "quadgr") %>% 
    map(safe_m_quad)  -> out
  out
}

GB2_params <- list(shape1 = 3.652, scale = 65797, shape2 = 0.3, shape3 = 0.8356)

results <- multi_quad(dfun=dgb2, params=GB2_params, lb=1, ub=3e8)

results

下面是一个大大简化的示例,我认为我对内部函数何时以及如何找到提供给调用函数的值的期望以类似的方式受挫。这里名称以 "extra" 开头的变量是为了防止位置匹配。

本例中,fa的执行环境既是fb的调用环境,又是封闭环境。为什么 arg1 的值不在 fafbarg1 范围内?无论 fbarg1 是在其调用环境还是封闭环境中寻找 arg1,还是在 fb 的执行环境中及以上,在任何情况下它应该到达 fa 的执行环境。但事实并非如此。为什么是这样?它在看哪里?

fa <- function(extra0=0, arg1, extra2=2){
  extra0
  extra2
  fb(arg1)
  fb <- function(extra3=3, arg1){
    extra3
    print(arg1)}  
}

fa(arg1=1)

(1) 对我来说,integrate 最高支持 7.0e08。想想这是多么巨大的整合领域。您正在应用 pracma 中的函数,这些函数更像是方法演示,而不是用于自命不凡的测试。 quadgkintegrate 类似,最高可达 1.0e09,pracma 中的 integral 函数最高可达 1.0e10 !

如果您想在无限区间 [0. Inf] 上积分,那么 integrate 将不再起作用。但是 integral 认识到无限性并恢复到其他一些方法:

fun = function(x) dgb2(x, shape1 = 3.652, scale = 65797,
                          shape2 = 0.3, shape3 = 0.8356)
pracma::integral(fun, 0, Inf)
## For infinite domains Gauss integration is applied!
## [1] 1

它实际上使用 pracma::quadinf 在应用高斯求积规则之前将无限域转换为有限域。

(2) 在您的简化文本示例中,第一个错误是您在定义 fb(arg1) 之前调用它。如果你把fb(arg1)放在函数定义之后,arg1会被赋值给extra3,参数arg1仍然是undefined.

可能的更正可能是:

fa <- function(extra0=0, arg1, extra2=2){
    fb <- function(extra3=3, arg1){
        print(arg1)
    }
    fb(arg1 = arg1)
}

fa(arg1=1)
## [1] 1

或将fb改为fb <- function(arg1, extra3=3) {...}extra0extra1 等行的用途尚不清楚。

(3) 添加以提供一些合理的积分值:

积分函数 integralquadgk 能够通过选择适当的参数 return 间隔 5e08 或更大的合理值。

I1 = integrate(fun, 0, 5.0e08, rel.tol=1e-14, subdivisions=1000)$value; I1 - 1
## [1] -4.792833e-13

I2 = integral(fun, 0, 5.0e08, reltol=1e-14); I2 -1
## [1] -4.775069e-13

I3 = quadgk(fun, 0, 5.0e08, tol=1e-14); I3 - 1
## [1] -4.773959e-13

这样我们就得到了如下的整数值:

| Function          | Value             |
|-------------------|-------------------|
| stats::integrate  | 0.999999999999521 |
| pracma::integral  | 0.999999999999522 |
| pracma::quadgk    | 0.999999999999523 |

这些函数使用相似的 "adaptive Gaussian quadrature" 规则,所以难怪它们 return 相似的结果。其他完全不同的集成例程可能会得出(稍微?)不同的结果。