使用 R 的 lm(),公式对象应该作为字符传递吗?
Using lm() of R, a formula object should be passed as character?
我发现 R 使用 lm() 有一个奇怪的行为。
基于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
接收公式 class 作为参数。
以这种方式使用 R 的 lm(),公式对象应该作为字符传递吗?
我用 R-3.2.1、RStudio 0.99.467 测试了这个,Windows7。
很有意思的案例!这与R的环境特性有很大关系。
简而言之,我们似乎不应该将在外部定义的公式对象传递给函数。尽管有一些方法可以调整,但这种行为可能会让我们感到惊讶。
?formula
说:
A formula object has an associated environment, and this environment (rather than the parent environment) is used by model.frame to evaluate variables that are not found in the supplied data argument.
在你的func1
中,公式是在函数内部生成的,因此它与函数环境相关联(函数形成一个环境)。
因此,当在 data
中找不到对象时,lm
调用会在函数环境中查找它们。这就是在 func1
.
中找到 w
的方式
在第二个示例中,公式是在函数外部定义的,或者更准确地说,是在全局环境中定义的。因此,如果在 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")
我发现 R 使用 lm() 有一个奇怪的行为。
基于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
接收公式 class 作为参数。
以这种方式使用 R 的 lm(),公式对象应该作为字符传递吗?
我用 R-3.2.1、RStudio 0.99.467 测试了这个,Windows7。
很有意思的案例!这与R的环境特性有很大关系。 简而言之,我们似乎不应该将在外部定义的公式对象传递给函数。尽管有一些方法可以调整,但这种行为可能会让我们感到惊讶。
?formula
说:
A formula object has an associated environment, and this environment (rather than the parent environment) is used by model.frame to evaluate variables that are not found in the supplied data argument.
在你的func1
中,公式是在函数内部生成的,因此它与函数环境相关联(函数形成一个环境)。
因此,当在 data
中找不到对象时,lm
调用会在函数环境中查找它们。这就是在 func1
.
w
的方式
在第二个示例中,公式是在函数外部定义的,或者更准确地说,是在全局环境中定义的。因此,如果在 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")