使用以编程方式构造的公式有任何陷阱吗?

Jos*_*ien 7 r scoping

我想要通过一长串潜在的解释变量,依次回归每个反应变量.而不是粘贴模型公式,我正在考虑使用reformulate(), 如此处所示.

fun()下面的功能似乎完成了工作,适合所需的模型.但请注意,它在其call元素中记录了构造的公式对象的名称而不是其.

## (1) Function using programmatically constructed formula
fun <- function(XX) {
    ff <- reformulate(response="mpg", termlabels=XX)
    lm(ff, data=mtcars)
}
fun(XX=c("cyl", "disp"))
# 
# Call:
# lm(formula = ff, data = mtcars)                 <<<--- Note recorded call
# 
# Coefficients:
# (Intercept)          cyl         disp  
#    34.66099     -1.58728     -0.02058  

## (2) Result of directly specified formula (just for purposes of comparison)
lm(mpg ~ cyl + disp, data=mtcars)
# 
# Call:
# lm(formula = mpg ~ cyl + disp, data = mtcars)   <<<--- Note recorded call
# 
# Coefficients:
# (Intercept)          cyl         disp  
#    34.66099     -1.58728     -0.02058  
Run Code Online (Sandbox Code Playgroud)

我的问题:这有什么危险吗?可这成为一个问题,如果,例如,我想以后应用update,或predict或(从其他一些环境可能的)其它一些功能,模型拟合对象?

然而,一个稍微更尴尬的替代方案是使用正确记录的呼叫eval(substitute()).这在任何方面都是一个通常更安全的构造吗?

fun2 <- function(XX) {
    ff <- reformulate(response="mpg", termlabels=XX)
    eval(substitute(lm(FF, data=mtcars), list(FF=ff)))
}
fun2(XX=c("cyl", "disp"))$call
## lm(formula = mpg ~ cyl + disp, data = mtcars)
Run Code Online (Sandbox Code Playgroud)

Jos*_*ien 2

我总是犹豫是否要声称在任何情况下涉及 R 环境和范围界定的东西可能会产生影响,但是......经过更多探索后,我上面的第一个用法看起来确实是安全的

事实证明,打印出来的电话有点转移注意力。

其他函数实际使用的公式(以及由和formula()提取的公式as.formula())是存储在termsfit 对象的元素中的公式,并且得到了正确的实际公式。(该terms元素包含一个 class 对象"terms",它只是"formula"带有一堆附加属性的对象。)

要查看我的问题中的所有提案和关联的注释都存储相同的"formula"对象(直到关联的环境),请运行以下命令。

## First the three approaches in my post
formula(fun(XX=c("cyl", "disp")))
# mpg ~ cyl + disp
# <environment: 0x026d2b7c>

formula(lm(mpg ~ cyl + disp, data=mtcars))
# mpg ~ cyl + disp

formula(fun2(XX=c("cyl", "disp"))$call)
# mpg ~ cyl + disp
# <environment: 0x02c4ce2c>

## Then Gabor Grothendieck's idea
XX = c("cyl", "disp")
ff <- reformulate(response="mpg", termlabels=XX)
formula(do.call("lm", list(ff, quote(mtcars))))  
## mpg ~ cyl + disp
Run Code Online (Sandbox Code Playgroud)

要确认formula()确实是从 fit 对象的元素导出其输出terms,请查看stats:::formula.lmstats:::formula.terms