你提出的代码无法运行是因为R看到公式的方式以及在评估
i之前更新公式的事实。
相关更新方法的源代码可以通过在命令行中运行
update.default
来查看。你会看到一些错误检查后,它运行
call$formula <- update(formula(object), formula.)
,这将调用
update.formula()
函数。
update.formula()
看到你想要将术语
X[, i]
添加到公式中,并执行此操作。但是
update.formula()
此时不会评估
i
的值,而是依赖于“惰性求值”。如果我们展开循环,就可以更清楚地看到这一点。
form <- y ~ 1
form
i <- 1
form <- update.formula(form, ~. +X[, i])
form
i <- 2
form <- update.formula(form, ~. +X[, i])
form
该公式正在使用符号
X[, i]
进行更新,然后简化以删除重复的符号。这种惰性计算很有用,因为它意味着我不需要实际定义上述代码中
X
和
y
的内容即可运行。R相信我会在尝试使用它们之前创建适当的对象。
在
update()
更新公式后,它会
eval()
更新后的调用。此时会评估
i
并使用其当前值。因此,实际上,即使它不尝试更改公式,下面的循环也会给出与您的循环完全相同的输出。每次
lm()
运行时,它都会查找要使用的
i
的当前值。
for(i in 1:30){
model <- lm(y ~ X[, i])
print(model)
}
为了达到您想要的效果,您可以在
lm()
函数之外以编程方式创建公式,而不是使用
update()
函数。像这样,
n <- 1000; p <- 30
X <- matrix(rnorm(n*p), nrow = n, ncol = p)
beta <- c(rep(1, 10), rep(0, 10), rep(-2, 10))
y <- X %*% beta + rnorm(1000)
xnames <- sapply(list(1:ncol(X)), function(x) paste0("X",x))
colnames(X) <- xnames
dat <- data.frame(y,X)
for(i in 1:30){
form <- as.formula(paste0("y ~ ", paste(xnames[1:i], collapse = "+")))
model <- lm(form, data = dat)
print(model)
}
编辑:
阅读完这篇文章https://notstatschat.rbind.io/2022/06/23/getting-strings-into-code-in-base-r/后,执行公式操作的另一种方法是使用bquote()
。这样做的好处是模型摘要包含了正确的公式。
for(i in 1:30){
model <- eval(bquote(update(model, ~. + .(as.name(xnames[[i]])))))
print(model)
}
update
的意义在哪里呢?我是否可以在循环中总是说model <- lm(y~X[, 1:i])
而不使用它? - gtoques