Skip to main content
5 of 15
Addressed OP's comment
Stefan
  • 6.6k
  • 1
  • 24
  • 45

Don't use integers when specifying factors when you use aov() (even if you explicitly changed to a factor). For some reason this will not work well.

So instead of:

p <- sort(rep(1:20,8))
y <- rep(rep(1:2,4),20)
z <- rep(rep(c(1,1,2,2),2),20)
w <- rep(c(1,1,1,1,2,2,2,2),20)
x <- rnorm(160,10,2)

d0 <- data.frame(x,p=factor(p),y=factor(y),z=factor(z),w=factor(w))

ex.aov0<- aov(x ~ y*z*w + Error(p/(y*z*w)), d0)

Edit (to address OP's comment):

You can also keep integers but then you have to make them as.character first and then turn them into a factor:

d1 <- data.frame(x,p=p,y=as.character(y),z=as.character(z),w=as.character(w))
d1$y <- factor(d1$y, levels=c(1,2), labels=c("A","B"))
d1$z <- factor(d1$z, levels=c(1,2), labels=c("A","B"))
d1$w <- factor(d1$w, levels=c(1,2), labels=c("A","B"))

ex.aov1<- aov(x ~ y*z*w + Error(p/(y*z*w)), d1)

Edit end.

use:

# I used "_f" to designate the change to a factor
p <- sort(rep(1:20,8))
y_f <- rep(rep(c("A","B"),4),20)
z_f <- rep(rep(c("A","A","B","B"),2),20)
w_f <- rep(c("A","A","A","A","B","B","B","B"),20)
x <- rnorm(160,10,2)

d2 <- data.frame(x,p,y_f,z_f,w_f)

ex.aov2 <- aov(x ~ y_f * z_f * w_f + Error(p / (y_f * z_f * w_f)), d2)

Now compare: summary(ex.aov0) vs. summary(ex.aov1) vs. summary(ex.aov2)

ex.aov2 will also now give you the error : within part of the output which you didn't get before.

Regarding your plots, why did you choose p:y:z and not y:z:w as these are your independent variables? I am just curious. In any case, if you change it, it will not work:

plot(residuals(ex.aov2[["y_f : z_f : w_f"]]) ~ fitted(ex.aov2[["y_f : z_f : w_f"]]))

However, the reason why aov() objects fitted with the Error() function are not working in plot() commands, I don't know.

My alternative suggestion:

First, I changed your dataset slightly and set a seed to make it reproducible (might be handy for some problems you have in the future):

# Set seed to make it reproducible
set.seed(12)

# I changed the names of your variables to make them easier to remember
# I also deleted a few nested `rep()` commands. Have a look at the `each=` argument.
subj <- sort(rep(1:20,8))
x1 <- rep(c('A','B'),160)
x2 <- rep(c('A','B'),40,each=2)
x3 <- rep(c('A','B'),20, each=4)
outcome <- rnorm(160,10,2)

d3 <- data.frame(outcome,subj,x1,x2,x3)

Second, I used a linear mixed-effects model instead since you have repeated measures and hence a random term you can use:

require(lme4)
# I specified `subj` as random term to account for the repeated measurements on subject.
m.lmer<-lmer(outcome ~ x1*x2*x3 + (1|subj), data = d3)
summary(m.lmer)

# Check for heteroscedasticity
plot(m.lmer)

enter image description here

# or
boxplot(residuals(m.lmer) ~ d3$x1 + d3$x2 + d3$x3)

enter image description here

# Check for normality
qqnorm(residuals(m.lmer))

enter image description here

Using the afex package you can also get the fixed effects in ANOVA table format (you can also use the Anova() function from the car package as another option):

require(afex)
mixed(outcome ~ x1*x2*x3 + (1|subj), data = d3, method="LRT")

Fitting 8 (g)lmer() models:
[........]
    Effect df     Chisq p.value
1       x1  1      0.66     .42
2       x2  1      0.22     .64
3       x3  1 21.16 ***  <.0001
4    x1:x2  1    3.40 +     .07
5    x1:x3  1    3.99 *     .05
6    x2:x3  1    2.83 +     .09
7 x1:x2:x3  1      0.00     .97

Check ?mixed for the various options you can choose. Also regarding mixed models, there is a lot of information here on Cross Validated.

Stefan
  • 6.6k
  • 1
  • 24
  • 45