eval(expr,envir,enclos)中的错误:找不到函数 - 嵌套函数&环境

时间:2015-05-07 00:00:43

标签: r

下面显示的R代码​​是一个简单的工作示例,用于重现我无法理解的错误。运行脚本应该产生错误Error in eval(expr, envir, enclos) : could not find function "fitModel"。在environments上阅读了一两件事后,我想我明白为什么会出现这种情况,&#34; fitModel&#34;未在&#34; obscureFunction&#34;的执行环境中定义。我通过对&#34; myFormula&#34;进行以下更改来修复: myFormula <- "y ~ eval(fitModel(x, a), envir = environment(fitModel))"

我不明白&#34; fitModel&#34;可以在&#34; fitModel&#34;的环境中进行评估。当函数无法在&#34; obscureFunction&#34;的调用环境中找到时,换句话说,我不明白为什么这个代码更改有效。我也不明白为什么如果&#34; topFunction&#34;的主体原始代码工作正常。如果我们定义&#34; fitModel&#34;和&#34; obscureFunction&#34;在R_GlobalEnv并致电&#34; obscureFunction&#34;从控制台。

## Minimum Working Example to reproduce error
rm(list = ls())
library(minpack.lm)

topFunction <- function(){

       fitModel <- function(x, a){
              exp(-a * x)
       }

       ## Create a function to use with lapply()
       obscureFunction <- function(){

              x <- seq(-1, 1, 0.01)
              y <- exp(-0.5 * x)
              Data <- data.frame(x, y)

              init      <- c(a = 1)
              myFormula <- "y ~ fitModel(x, a)"
              myFormula <- as.formula(myFormula)
              nlsOutput <- nlsLM(formula = myFormula, start = init, data = Data)

              return(nlsOutput)

       }

       ## Function call
       obscureFunction()

       ## Other calculations done with fitModel()
} 

topFunction()

1 个答案:

答案 0 :(得分:7)

嗯,这里有两个问题。第一个是使用字符串表示公式。最好使用

myFormula <- y ~ fitModel(x, a)

原因是公式捕获他们的环境,而字符串则没有。 (正如@BridieG所指出的,as.formula()将捕获环境;我在阅读代码时跳过了那一行。我仍然认为最好直接创建公式。)拥有一个参考环境可以更容易地找到函数在公式中使用。因此,如果您使用lm()而不是nlsLM,则可以使用这两项更改

# myFormula <- "y ~ fitModel(x, a)"  ... becomes
myFormula <- y ~ fitModel(x, 1)

#nlsOutput <- nlsLM(formula = myFormula, start = init, data = Data) ...becomes
nlsOutput <- lm(formula = myFormula, data = Data)

这适用于公式语法(不带引号的var名称)而不是字符串,因为公式可以捕获环境。

至少应该如何运作。包作者可以随意评估公式,nlsLM()函数的作者决定忽略分配给公式的环境。他们在nlsLM()

内的这个函数中这样做
FCT <- function(par) {
    mf[m] <- par
    rhs <- eval(formula[[3L]], envir = mf)
    res <- lhs - rhs
    res <- .swts * res
    res
}

所以这是第二个问题。在这里,他们在mf对象中强制执行评估,该对象是由数据的协变量和参数估计组成的data.frame。如果它写成

rhs <- eval(formula[[3L]], envir = mf, environment(formula))
它会起作用。这基本上是model.frame() lm()中允许此操作的内容。我们可以用

制作我们自己的“修正”版本的功能
# tested with minpack.lm_1.1-8
nlsLM2<-nlsLM
body(nlsLM2)[[27]][[3]][[3]][[3]]<-quote(rhs<-eval(formula[[3L]], envir = mf, environment(formula)))

然后进行这些替换

# myFormula <- "y ~ fitModel(x, a)"  ... becomes
myFormula <- y ~ fitModel(x, a)

#nlsOutput <- nlsLM(formula = myFormula, start = init, data = Data) ...becomes
nlsOutput <- nlsLM2(formula = myFormula, start = init, data = Data) 

工作并返回

Nonlinear regression model
  model: y ~ fitModel(x, a)
   data: Data
  a 
0.5 
 residual sum-of-squares: 0

Number of iterations to convergence: 5 
Achieved convergence tolerance: 1.49e-08

因此,关于所有R函数如何处理环境和范围,你所能说的并不多。这种行为对于nlsLM()作者决定评估其参数的方式是独一无二的。