函数内 lm() 中的权重调用未正确评估

be_*_*een 5 r non-standard-evaluation

我正在编写一个需要加权回归的函数。我一再收到权重参数的错误,并且我创建了一个最小的可重现示例,您可以在此处找到:

wt_reg <- function(form, data, wts) {
  lm(formula = as.formula(form), data = data,
     weights = wts)
}

wt_reg(mpg ~ cyl, data = mtcars, wts = 1:nrow(mtcars))
Run Code Online (Sandbox Code Playgroud)

这返回

eval(extras, data, env) 中的错误:找不到对象“wts”

如果你单独运行这一切,它工作正常。我已经深入研究了 lm,看来问题是调用eval(mf, parent.frame()). 即使 wts 在 parent.frame() 中,它似乎也没有在调用中正确评估。这里有更多细节:

mf 被分配为与

stats::model.frame(formula = as.formula(form), data = data, weights = wts, 
    drop.unused.levels = TRUE)
Run Code Online (Sandbox Code Playgroud)

当我跑

parent.frame()$wts
Run Code Online (Sandbox Code Playgroud)

它确实返回一个数字向量。但是当我跑

eval(stats::model.frame(formula = as.formula(form), data = data, weights = wts, 
    drop.unused.levels = TRUE), parent.frame()) 
Run Code Online (Sandbox Code Playgroud)

它没有。

我可以跑

stats::model.frame(formula = as.formula(parent.frame()$form), 
    data = parent.frame()$data, weights = parent.frame()$wts, 
    drop.unused.levels = TRUE)
Run Code Online (Sandbox Code Playgroud)

它有效。如果您想使用顶部的示例,您可以自己测试。

有什么想法吗?我真的不知道这里发生了什么......

MrF*_*ick 6

公式在 R 中的特殊之处在于它们不仅跟踪符号/变量名称,还跟踪创建它们的环境。查看

ff <- mpg ~ cyl
environment(ff)
# <environment: R_GlobalEnv>
foo <- function() {
  ff <- mpg ~ cyl
  environment(ff)
}
foo()
# <environment: 0x0000026172e505d8> private function environment (different each time)
Run Code Online (Sandbox Code Playgroud)

问题是lm会尝试使用创建公式的环境来查找变量而不是父框架。由于您在对 的调用中创建了公式,因此wt_reg该公式适用于全局范围。但wts只存在于函数作用域中。您可以更改函数以将公式上的环境更改为本地函数环境,然后一切正常

wt_reg <- function(form, data, wts) {
  ff <- as.formula(form)
  environment(ff) <- environment()
  lm(formula = ff, data = data,
     weights = wts)
}

wt_reg(mpg ~ cyl, data = mtcars, wts = 1:nrow(mtcars))
Run Code Online (Sandbox Code Playgroud)

eval(mf, parent.frame)你指的是在lm()呼唤model.frame()你的公式。从?model.frame帮助页面上的描述来看:“公式、子集和...中的所有变量首先在数据中查找,然后在公式环境中查找(有关详细信息,请参阅公式()的帮助)并收集到一个数据框”。所以它再次查看公式的环境,而不是调用框架。