我发现了一个使用lm()的R的奇怪行为。
基于cars
对象,以下函数用于绘制拟合的断裂距离,并以30的速度进行局部线性回归。
func1 <- function(fm, spd){
w <- dnorm(cars$speed - spd, sd=5)
fit <- lm(formula = as.formula(fm), weights = w, data=cars)
plot(fitted(fit))
}
func2 <- function(fm, spd){
w <- dnorm(cars$speed - spd, sd=5)
fit <- lm(formula = fm, weights = w, data=cars)
plot(fitted(fit))
}
func1("dist ~ speed", 30)
func2(dist ~ speed, 30)
func1
有效。但func2
失败并显示以下消息:
Error in eval(expr, envir, enclos) : object 'w' not found
两个函数之间的唯一区别是func2
接收公式类作为参数。
在这种风格中使用R的lm(),公式对象应该作为字符传递?
我用R-3.2.1,RStudio 0.99.467,Windows7测试了这个。
答案 0 :(得分:2)
非常有趣的案例!这与R的环境特征有很大关系。 简而言之,似乎我们不应该将外部定义的公式对象传递给函数。虽然有一些方法可以调整,但这种行为可能让我们感到惊讶。
?formula
说:
公式对象具有关联环境,并且此环境(而不是父环境)由model.frame用于来评估在提供的数据参数中找不到的变量。
在func1
中,公式在函数内生成,因此它与函数环境相关联(函数形成一个环境)。
因此,当data
中找不到对象时,lm
调用会在函数环境中查找它们。这就是w
中找到func1
的方式。
在第二个示例中,公式在函数外部定义,或者更确切地说,在全局环境中定义。因此,如果在data
中找不到,则公式会查找全局中的对象。由于全局中没有w
,因此失败。更糟糕的是,如果全局中有另一个w
,则w
会被混淆并用作权重。
这是一个突出显示对象搜索顺序的示例。
数据只有y
。因此,lm
调用会在其他位置查找x
。
但有两个x
。 fm
,在全局搜索x = 1:10
中定义的公式,而在函数中定义的as.formula(ch)
找到x = 10:1
。
environment
告诉您公式与哪个环境相关联。
fun <- function(fm, ch) {
x <- 10:1
dat <- data.frame(y = 1:10)
print(environment(fm))
print(lm(fm, data = dat))
cat("<--- refers to x in the global\n")
print(environment(as.formula(ch)))
print(lm(as.formula(ch), data = dat))
cat("<--- refers to x in the function\n\n")
}
x <- c(1:10)
fun(y ~ x, "y ~ x")