# factorial ANOVA/multiple categorical predictors library(tidyverse) library(lmSupport) # read in data, explore its structure eysenck <- read.csv("http://whlevine.hosted.uark.edu/psyc5143/eysenck.csv") glimpse(eysenck) head(eysenck, 20) str(eysenck) # factorize variables, provide labels for levels eysenck$ageF <- factor(eysenck$age, labels = c("young", "old")) eysenck$processF <- factor(eysenck$process, labels = c("shallow", "deep")) glimpse(eysenck) head(eysenck, 20) # always check your work table(eysenck$ageF, eysenck$age) table(eysenck$process, eysenck$processF) table(eysenck$ageF, eysenck$processF) # summary data for cells aggregate(data = eysenck, recall ~ age*process, mean) aggregate(data = eysenck, recall ~ age*process, sd) # summary data for age effect aggregate(data = eysenck, recall ~ ageF, mean) # summary data for processing effect aggregate(data = eysenck, recall ~ processF, mean) # another quick-and-easy way to explore the data (not very visually-pleasing, # but easy!) interaction.plot(x.factor = eysenck$ageF, # x-axis factor trace.factor = eysenck$processF, # the other factor response = eysenck$recall) # the DV # the ANOVA table using the aov function (OG ANOVA) summary(aov(recall ~ ageF*processF, eysenck)) # exploring the default coding that R gives to factors contrasts(eysenck$ageF) contrasts(eysenck$processF) # create contrast codes (no worries about orthogonality with only two levels) eysenck <- eysenck %>% mutate(age.contrast = ifelse(ageF == "young", 0.5, -0.5), process.contrast = ifelse(processF == "deep", 0.5, -0.5)) # fit the model model.contrasts <- lm(recall ~ age.contrast * process.contrast, eysenck) # the summary summary(model.contrasts) # for comparison, back to the ANOVA summary(aov(recall ~ ageF*processF, eysenck)) # t^2 = F, p is the same, df is the same, etc. # testing simple effects (the effect of each factor at one level of the other) # requires dummy coding eysenck <- eysenck %>% mutate(age.young.dummy = ifelse(ageF == "young", 0, 1), age.old.dummy = ifelse(ageF == "old", 0, 1), process.shallow.dummy = ifelse(processF == "shallow", 0, 1), process.deep.dummy = ifelse(processF == "deep", 0, 1)) # reminder of cell means aggregate(data = eysenck, recall ~ ageF*processF, mean) aggregate(data = eysenck, recall ~ ageF, mean) aggregate(data = eysenck, recall ~ processF, mean) # the simple effect/slope of age when doing deep processing summary(lm(recall ~ age.contrast * process.deep.dummy, eysenck)) # the simple effect/slope of age when doing shallow processing summary(lm(recall ~ age.contrast * process.shallow.dummy, eysenck)) # the simple effect/slope of processing among the young summary(lm(recall ~ process.contrast * age.young.dummy, eysenck)) # the simple effect/slope of processing among the old summary(lm(recall ~ process.contrast * age.old.dummy, eysenck))