This example is taken from https://crumplab.github.io/statisticsLab/lab-10-factorial-anova.html#r-10. The data file is stroop_stand.csv
, and can be found here https://github.com/CrumpLab/statisticsLab/tree/master/data
library(data.table)
library(dplyr)
library(ggplot2)
all_data <- fread("data/stroop_stand.csv")
Pre-processing can include many steps. Here, we convert the data from wide to long format, and make a new data frame.
RTs <- c(as.numeric(unlist(all_data[,1])),
as.numeric(unlist(all_data[,2])),
as.numeric(unlist(all_data[,3])),
as.numeric(unlist(all_data[,4]))
)
Congruency <- rep(rep(c("Congruent","Incongruent"),each=50),2)
Posture <- rep(c("Stand","Sit"),each=100)
Subject <- rep(1:50,4)
stroop_df <- data.frame(Subject,Congruency,Posture,RTs)
It is important to check the data you are analyzing before you analyze. The checks you make depend on the questions you are trying to answer. Here we check the number of subjects in each condition.
This is a 2x2 repeated measures design, each subject should have 4 means
num_subjects <- stroop_df %>%
group_by(Subject) %>%
summarise(counts = length(Subject))
total_subjects <- length(num_subjects$Subject)
total_has_four <- num_subjects$counts == 4
sum(total_has_four) == total_subjects
## [1] TRUE
Are there any subjects with huge mean RTs? Could indicate something weird happened.
hist(stroop_df$RTs)
If you are going to exlcude subjects from analysis, then justify your exclusion criterion, and then eliminate subject data from the data frame. We will not exlcude any subjects here.
# no exclusions
Now you can begin analysis. This experiment asked whether the Stroop effect (difference between mean incongruent and mean congruent), depends on whether people are sitting or standing. Let’s get the means, make a tbale, then plot the data.
overall_means <- stroop_df %>%
group_by(Posture,Congruency) %>%
summarise(meanRT = mean(RTs),
SEMRT = (sd(RTs)/sqrt(length(RTs))))
# make a table of overall means
knitr::kable(overall_means)
Posture | Congruency | meanRT | SEMRT |
---|---|---|---|
Sit | Congruent | 821.9232 | 16.60384 |
Sit | Incongruent | 940.7855 | 17.91041 |
Stand | Congruent | 807.9599 | 14.93521 |
Stand | Incongruent | 903.9131 | 15.34939 |
ggplot(overall_means, aes(x=Posture,
y=meanRT,
group=Congruency,
fill=Congruency))+
geom_bar(stat="identity",position="dodge")+
theme_classic(base_size=12)+
ylab("Mean Reaction Time (ms)")+
geom_errorbar(aes(ymin=meanRT-SEMRT,
ymax=meanRT+SEMRT),
position=position_dodge(width=0.9),
width=.2,
color="black")+
coord_cartesian(ylim=c(750,1000))
# Make sure Subjecdt is a factor
stroop_df$Subject <- as.factor(stroop_df$Subject)
aov_out <- aov(RTs~Posture*Congruency + Error(Subject/(Posture*Congruency)), stroop_df)
#print summary of ANOVA table
summary(aov_out)
##
## Error: Subject
## Df Sum Sq Mean Sq F value Pr(>F)
## Residuals 49 2250739 45933
##
## Error: Subject:Posture
## Df Sum Sq Mean Sq F value Pr(>F)
## Posture 1 32303 32303 7.33 0.00931 **
## Residuals 49 215948 4407
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Error: Subject:Congruency
## Df Sum Sq Mean Sq F value Pr(>F)
## Congruency 1 576822 576822 342.5 <2e-16 ***
## Residuals 49 82535 1684
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Error: Subject:Posture:Congruency
## Df Sum Sq Mean Sq F value Pr(>F)
## Posture:Congruency 1 6560 6560 8.964 0.00431 **
## Residuals 49 35859 732
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# prints a nicer ANOVA table
summary_out <- summary(aov_out)
library(xtable)
knitr::kable(xtable(summary_out))
Df | Sum Sq | Mean Sq | F value | Pr(>F) | |
---|---|---|---|---|---|
Residuals | 49 | 2250738.636 | 45933.4416 | NA | NA |
Posture | 1 | 32303.453 | 32303.4534 | 7.329876 | 0.0093104 |
Residuals1 | 49 | 215947.614 | 4407.0942 | NA | NA |
Congruency | 1 | 576821.635 | 576821.6349 | 342.452244 | 0.0000000 |
Residuals | 49 | 82534.895 | 1684.3856 | NA | NA |
Posture:Congruency | 1 | 6560.339 | 6560.3389 | 8.964444 | 0.0043060 |
Residuals | 49 | 35859.069 | 731.8177 | NA | NA |
# prints means for each effect
print(model.tables(aov_out,"means"), format="markdown")
## Tables of means
## Grand mean
##
## 868.6454
##
## Posture
## Posture
## Sit Stand
## 881.4 855.9
##
## Congruency
## Congruency
## Congruent Incongruent
## 814.9 922.3
##
## Posture:Congruency
## Congruency
## Posture Congruent Incongruent
## Sit 821.9 940.8
## Stand 808.0 903.9
We submitted the mean reaction times for each subject in each condition to a 2 (Congruency: congruecnt vs. incongruent) x 2 (Posture: Standing vs. Sitting) repeated measures ANOVA.
There was a main effect of Congruency, F (1, 49) = 342.45, MSE = 1684.39, p < 0.001. Mean reaction times were slower for incongruent (922 ms) than congruent groups (815 ms).
There main effect of Posture was significant, F (1, 49) = 7.33, MSE = 4407.09, p =.009. Mean reaction times were slower for sitting (881 ms) than standing groups (855 ms).
The two-way interaction between Congruency and Posture was significant, F (1, 49) = 8.96, MSE = 731.82, p < 0.004. The Stroop effect was 23 ms smaller in the standing than sitting conditions.