R 何时将操作数计算为 ~

Ale*_*rtt 0 r

R 何时评估formula传递给lm(). 例如:

tmp <- rnorm(1000)
y <- rnorm(1000) + tmp
df = data.frame(x=tmp)
lm(y~x, data=df)$coefficients
Run Code Online (Sandbox Code Playgroud)

回报

(Intercept)           x 
 0.01713098  0.98073687 
Run Code Online (Sandbox Code Playgroud)

这表明在控制权传递y~x进行评估,因为调用上下文中没有变量。但是,它还建议在控制权传递给之前对其进行评估,因为 中没有列。lm()xlm()ydf

在大多数语言中,参数在向下传递到堆栈之前会被完全评估。我可能在这里遗漏了一些微妙的东西。任何帮助,将不胜感激。

MrF*_*ick 5

公式指示器~实际上只是一个捕获未评估符号的函数。这很像quote()您可以运行quote(f(x)+1)并返回您传入的语法的未计算的 R 表达式。主要区别在于,它~允许您拥有两组未计算的表达式,并且公式将跟踪它所在的环境创建的。所以这些都是一样的

a ~ b
`~`(a, b)
Run Code Online (Sandbox Code Playgroud)

因此,您可以将任何有效的 R 语法传递到公式中,它不必是变量名称。这些值存储为未评估的符号或调用。因此,公式调用本身会被求值,但其参数不会。

其他函数可以随意使用这些公式。lm()例如,该函数会将公式传递给model.matrix. 然后model.matrix将尝试评估传递给函数的 data.frame 中公式中找到的变量,以及创建公式的环境(如果不存在)。不同的函数可能会选择以不同的方式评估公式,因此实际上无法确定何时进行评估。

通常会发生这样的事情

myformula <- a~b
b <- 4
dd <- data.frame(a=1:3)
eval(myformula[[2]], dd, environment(myformula)) +    # a
  eval(myformula[[3]], dd, environment(myformula))    # b
# [1] 5 6 7
Run Code Online (Sandbox Code Playgroud)

在传递给评估器的环境/列表中查找符号。

environment部分也相关,因为您也可能遇到这样的情况

b <- 10
foo <- function(myformula = a~b) {
  b <- 4
  dd <- data.frame(a=1:3)
  eval(myformula[[2]], dd, environment(myformula)) + 
    eval(myformula[[3]], dd, environment(myformula))  
}
foo()
# [1] 5 6 7
foo(a~b)
# [1] 11 12 13
Run Code Online (Sandbox Code Playgroud)

如果您在不带参数的情况下调用 foo,则默认情况下会在函数体内创建公式,因此它将在其中查找值bb但是,如果您使用公式调用 foo,则该公式将在调用环境中求值,因此 R 将为大多数建模函数查找函数外部的值。再次强调,这只是一个约定,非基础 R 包可能会选择做其他事情。