2
 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 provides a fix for using substitute and as.name to create a formula for aov, but I don't understand why the formula works for oneway.test and lm. Can someone explain?

 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
Community
  • 1
  • 1
jayelm
  • 7,236
  • 5
  • 43
  • 61

2 Answers2

3

The problem is that substitute is returning an unevaluated call, not a formula. Compare

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

If you evaluate it (as was done in the other answer), both will work

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

The error message you were getting was from the terms function which is called by aov(). This function needs to operate on a formula, not a call. This is basically what was happening

# 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))
MrFlick
  • 195,160
  • 17
  • 277
  • 295
0

One possible source of the difference is that fm is actually a call not a formula and apparently some functions do the conversion while others do not.

If you do:

fm <- as.formula(fm)

Then the call to aov will work.

Greg Snow
  • 48,497
  • 6
  • 83
  • 110