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