为什么替代公式适用于 lm 和 oneway.test,但不适用于 aov?

Why does a substituted formula work for lm and oneway.test, but not aov?

 example <- data.frame(
   var1 = c(1, 2, 3, 4, 5, 6, 7, 8),
   class = c(rep(1, 4), rep(2, 4))
 )
 example$class <- as.factor(example$class)

This question 提供了使用替代和 as.name 为 aov 创建公式的修复,但我不明白为什么该公式适用于 oneway.testlm。有人可以解释一下吗?

 fm <- substitute(i ~ class, list(i = as.name('var1')))
 oneway.test(fm, example)

    One-way analysis of means (not assuming equal variances)

data:  var1 and class
F = 19.2, num df = 1, denom df = 6, p-value = 0.004659

 lm(fm, example)

Call:
lm(formula = fm, data = example)

Coefficients:
(Intercept)       class2  
        2.5          4.0  

 aov(fm, example)
Error in terms.default(formula, "Error", data = data) : 
  no terms component nor attribute

问题是 substitute 正在返回一个未评估的调用,而不是一个公式。比较

class(substitute(a~b))
# [1] "call"
class(a~b)
# [1] "formula"

如果你评估它(就像在另一个答案中所做的那样),两者都会起作用

fm <- eval(substitute(i ~ class, list(i = as.name('var1'))))
oneway.test(fm, example)
aov(fm, example)

您收到的错误消息来自 terms 函数,该函数由 aov() 调用。此函数需要对公式进行操作,而不是调用。这基本上就是正在发生的事情

# ok
terms(a~b)

# doesn't work
unf <- quote(a~b)  #same as substitute(a~b)
terms(unf)
# Error in terms.default(unf) : no terms component nor attribute

# ok
terms(eval(unf))

差异的一个可能来源是 fm 实际上是 call 而不是 formula 并且显然某些函数进行转换而其他函数不进行转换。

如果你这样做:

fm <- as.formula(fm)

然后对 aov 的调用将起作用。