I’ve been analysing some future thinking data and playing around with packages that can do repeated ANOVA (I know, I should do LMM). There is more than one way to skin a cat and the differences come down to two things.
Some checks to do before you start
This code comes from the ANOVA cookbook
For a mixed RM with 1 between and 2 within you would use…
# for mixed RM with 1 between and 2 within aov1 <- aov(outcome ~ b1 * w1 * w2 + Error(participant/(w1 *w2)) + b1, data = data_long)
The output from
aov() is an object that you then run
summary() on. Its a good idea to use
options(scipen = 999) to get nonscientific notation, and
options(digits = 4) to get fewer dps in that chunk.
aov() output isnt that pretty but you can use the
broom package to pull the output into a tidy df.
ezANOVA easy wrapper for car package aov function
The ezANOVA() function asks you to specify…
ez1 <- ezANOVA(data = data_long, dv = outcome, wid = participant, within = .(w1, w2), between = b1, type = 2, detailed = TRUE, return_aov = TRUE)
The output is a list, which include a dataframe of ANOVA details. It gives a nice warning if your design is unbalanced and uses type 2 sums of squares by default (recommended for unbalanced).
You can call ez1$ANOVA to have it print the ANOVA dataframe and write_csv() to save it.
Including return_aov = TRUE also gives an aov object which might be useful in getting partial eta squared from the etasquared() function from the
For some reason, when I tried using tidy() from broom on the ez1 object, it didn’t work.
afex = Analysis of Factorial Experiments
afex is nice because it includes generalised eta sq in output table. It also has plotting of ANOVA analysis embedded in the package via the afex_plot() function
afex1 <- aov_ez("participant", "outcome", data_long, between = "b1", within = c("w1", "w2")) afex1
You can print the output by simply typing afex1, or get a “nice” table using nice(afex1), you can also turn that nice table into a df, and them use kable to make it really nice :)
nice(afex1) #make a nice table niceafex <- nice(afex1) #make it a dataframe kable(niceafex) %>% kable_styling() #print it in table format
emmeans (estimated marginal means) package is useful for following up effects with planned constrasts.
Get marginal means for a main effect by running the
emmeans function on your anova object and specifying the effect with a tilde. Then get paired contrasts by running the
pairs function on the emms
emm <- emmeans(afex1, ~ maineffect) pairs(emmm)
emm2 <- emmeans(afex1, "effect1", by = "effect2") pairs(emm2)
Find more complex interaction contrasts in the emmeans vignette
afex package also allows for ANOVA plotting
Need to specify…
afex_plot(afex1, x = "b1", trace= "b1", panel= "w2")
aov1 <- aov(outcome ~ b1 * w1 * w2 + Error(participant/(w1 *w2)) + b1, data = data_long) ez1 <- ezANOVA(data = data_long, dv = outcome, wid = participant, within = .(w1, w2), between = b1, type = 2, detailed = TRUE, return_aov = TRUE) afex1 <- aov_ez("participant", "outcome", data_long, between = "b1", within = c("w1", "w2"))
The old school aov() is best if you want to be consistent in the way formulas are set up for linear models, but for new users it is not very intuiative. I like ezANOVA, especially because it makes the user specify everything and it includes generalised eta sq in the output by default. It does move away from the standard linear model function construction, which might may it hard for new learners to transfer R skills across methods, but it emulates SPSS more closely, asking for within, between etc which is probably good for students new to R.
afex also doesn’t adhere to the lm formula style, but it is really simple. The output is the same as ezANOVA but additional plotting functionality embedded is definitely helpful. I REALLY like the nice() function for formatting things.
take home: afex is the favourite :)