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



下面显示的R代码是一个最小的工作示例,可以重现一个我无法理解的错误。运行脚本应产生错误,Error in eval(expr, envir, enclos) : could not find function "fitModel"。在环境上阅读了一两件事后,我认为我明白为什么在这种情况下会发生这种情况," FitModel"在"模糊功能"的执行环境中未定义。我通过将以下更改更改为" myformula"来解决: myFormula <- "y ~ eval(fitModel(x, a), envir = environment(fitModel))"

我不明白如何在" buckurefunction"的调用环境中找到函数时如何在" fitmodel"的环境中评估" fitmodel",换句话说,我不明白为什么此代码为什么更改工作。我也不明白,如果" topfunction"的主体在不调用的情况下运行,即如果我们定义了R_GlobalEnv中的" FitModel"one_answers"模糊功能",并且从控制台中调用" Muckurefunction",则原始代码为何可以正常工作。

## 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()

好吧,这里有两个问题。首先是将字符串用于公式。最好使用

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对象中强制执行评估,该对象是数据和参数估计值组成的数据。如果它被写成

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) 

IT工作和返回

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()作者决定评估其参数的独特性。

最新更新