One-Way Repeated Measures ANOVA
The engine for Pure Temporal Discovery. This model audits how a single group evolves across multiple timepoints, using each participant as their own baseline control.
What is it?
One-Way Repeated Measures ANOVA compares means across three or more conditions where the same subjects are tested at every condition.
When to use it
- 1 Within Factor: Same subjects under 3+ conditions/timepoints.
- 1 Outcome: Continuous scale variable.
- No Between-Subjects Factor: Single cohort design.
Core Idea
Each participant acts as their own control. By subtracting subject-to-subject baseline variance from the error term, statistical power increases dramatically:
Even if subjects vary widely in baseline scores, the trend (slope) remains clear. Repeated measures ANOVA isolates and removes this baseline spread.
Hypotheses
How it works
Subtracts **Between-Subjects Variance** (SS_Subjects) from the denominator of the F-ratio: F = MS_Conditions / MS_Residual_Error
Assumptions
Important Note
If sphericity fails, we adjust using the Greenhouse-Geisser epsilon. Alternatively, pivot to a Multivariate ANOVA (MANOVA) approach.
Quick Example
| Subject | Baseline | 3 Months | 6 Months |
|---|---|---|---|
| Subj 1 | 45.0 | 62.1 | 74.5 |
| Subj 2 | 21.4 | 38.0 | 52.3 |
One-Way RM ANOVA Live Laboratory
Change condition means and baseline subject spread to visualize the power of removing individual intercepts.
| Source | SS | df | MS | F | p-value |
|---|---|---|---|---|---|
| Conditions (Within) | 1280.7 | 2 | 640.4 | 26.10 | < 0.001 |
| Subjects (Removed) | 3502.0 | 9 | 389.1 | - | - |
| Residual Error | 441.7 | 18 | 24.5 | - | - |
Hypotheses
Pragmatic null and alternative hypotheses defined in mathematical notation.
H₀: μ₁ = μ₂ = μ₃ = ... = μₖ (all repeated measure means are equal)
Hₐ: At least one time point/condition mean differs (∃ i,j: μᵢ ≠ μⱼ)
Tests within-subjects effects across conditions/time. Violation of sphericity affects F-test validity; use Greenhouse-Geisser (ε < .75) or Huynh-Feldt (ε > .75) correction when Mauchly's test p < .05.
Assumptions
The core mathematical criteria needed to ensure that statistical testing remains unbiased and valid.
Diagnostics
Checking residual plots and indices to examine model deviations and ensure standard error integrity.
- Mauchly's test of sphericity (p > .05 indicates sphericity met)
- Greenhouse-Geisser epsilon (ε) value to quantify sphericity violation
- Q-Q plots of difference scores to assess normality
- Boxplots at each timepoint to identify outliers
- Shapiro-Wilk test on difference scores (if n < 50)
- Profile plot (means across time/conditions) to visualize trends
- Within-subject variability plot
- Variance-covariance matrix inspection
- Intraclass correlation coefficient (ICC) to quantify within-subject correlation
- Residual vs fitted plot
- Descriptive statistics (M, SD, n) per condition/timepoint
Applied Minds
Review concrete study examples, data layout guidelines, and copy executable syntax scripts.
Mindfulness Meditation and Cortisol Levels Across Day (4 Timepoints)
Research question: Does mindfulness meditation training affect diurnal cortisol rhythm? Design: 8-week mindfulness intervention (n=40 adults with chronic stress). Outcome: Salivary cortisol (μg/dL) measured at 4 timepoints (awakening, +30min, noon, bedtime) pre-intervention and post-intervention. We analyze POST-intervention data only (4 within-subject timepoints).
# One-way Repeated Measures ANOVA: Cortisol across 4 daily timepoints
# Based on diurnal cortisol patterns in mindfulness research
library(tidyverse) # Data manipulation
library(ez) # For ezANOVA (comprehensive RM-ANOVA)
library(rstatix) # For get_summary_stats, anova_test
library(effectsize) # For effect sizes
library(ggpubr) # For ggqqplot
# Simulate realistic cortisol data (or load: data <- read.csv("cortisol.csv"))
set.seed(2025)
subject_ids <- rep(1:40, each=4)
timepoint <- rep(c("Awakening", "30min", "Noon", "Bedtime"), 40)
# Realistic cortisol pattern: high at awakening, peak at +30min, decline by bedtime
data_wide <- data.frame(
subject = 1:40,
Awakening = rnorm(40, mean=0.52, sd=0.12),
ThirtyMin = rnorm(40, mean=0.68, sd=0.15), # +30% awakening response
Noon = rnorm(40, mean=0.24, sd=0.08),
Bedtime = rnorm(40, mean=0.08, sd=0.04)
)
# Convert to long format (required for RM-ANOVA)
data_long <- data_wide %>%
pivot_longer(cols = c(Awakening, ThirtyMin, Noon, Bedtime),
names_to = "timepoint",
values_to = "cortisol") %>%
mutate(timepoint = factor(timepoint,
levels=c("Awakening", "ThirtyMin", "Noon", "Bedtime")))
# === STEP 1: Check Assumptions ===
# 1. Descriptive statistics per timepoint
data_long %>%
group_by(timepoint) %>%
get_summary_stats(cortisol, type = "mean_sd")
# 2. Visualize: Profile plot (means across time)
data_long %>%
group_by(timepoint) %>%
summarise(M = mean(cortisol), SE = sd(cortisol)/sqrt(n())) %>%
ggplot(aes(x=timepoint, y=M, group=1)) +
geom_line(color="steelblue", size=1.2) +
geom_point(size=3) +
geom_errorbar(aes(ymin=M-SE, ymax=M+SE), width=0.2) +
labs(title="Diurnal Cortisol Pattern(Post-Intervention)",
x="Time of Day", y="Mean Cortisol(μg/dL) ± SE") +
theme_classic()
# 3. Check outliers (boxplots per timepoint)
ggboxplot(data_long, x="timepoint", y="cortisol", add="jitter",
title="Cortisol by Timepoint", xlab="Time", ylab="Cortisol(μg/dL)")
# 4. Check normality of DIFFERENCE SCORES
diff_data <- data_wide %>%
mutate(
diff_Awk_30min = ThirtyMin - Awakening,
diff_Awk_Noon = Noon - Awakening,
diff_Awk_Bed = Bedtime - Awakening,
diff_30min_Noon = Noon - ThirtyMin,
diff_30min_Bed = Bedtime - ThirtyMin,
diff_Noon_Bed = Bedtime - Noon
)
# Q-Q plots for key differences
par(mfrow=c(2,3))
for (diff_var in c("diff_Awk_30min", "diff_Awk_Noon", "diff_Awk_Bed",
"diff_30min_Noon", "diff_30min_Bed", "diff_Noon_Bed")) {
qqnorm(diff_data[[diff_var]], main=diff_var)
qqline(diff_data[[diff_var]])
}
# Shapiro-Wilk on difference scores
shapiro.test(diff_data$diff_Awk_30min) # p > .05 OK
shapiro.test(diff_data$diff_Awk_Noon) # p > .05 OK
# === STEP 2: Run One-way RM-ANOVA ===
# Method 1: Using ez::ezANOVA (comprehensive output)
rm_anova <- ezANOVA(
data = data_long,
dv = cortisol,
wid = subject,
within = timepoint,
detailed = TRUE,
type = 3
)
print(rm_anova)
# Output includes:
# - ANOVA table with F, p-value, generalized eta squared (ges)
# - Mauchly's test of sphericity
# - Greenhouse-Geisser and Huynh-Feldt corrections (if sphericity violated)
# Method 2: Using rstatix (tidy output)
rm_anova2 <- anova_test(
data = data_long,
dv = cortisol,
wid = subject,
within = timepoint
)
get_anova_table(rm_anova2)
# === STEP 3: Check Sphericity ===
cat("\n=== Mauchly's Test of Sphericity ===")
print(rm_anova$`Mauchly's Test for Sphericity`)
# If p < .05 (sphericity violated), use corrected results:
cat("\n=== Sphericity Corrections ===")
print(rm_anova$`Sphericity Corrections`)
# Interpretation:
# - If Mauchly's p > .05: use uncorrected ANOVA results
# - If Mauchly's p < .05 and GG epsilon < .75: use Greenhouse-Geisser correction
# - If Mauchly's p < .05 and GG epsilon > .75: use Huynh-Feldt correction
# === STEP 4: Effect Size ===
eta_squared(rm_anova2$ANOVA, partial=TRUE)
# partial η² for within-subjects factor
# === STEP 5: Post-hoc Pairwise Comparisons (if p < .05) ===
posthoc <- data_long %>%
pairwise_t_test(
cortisol ~ timepoint,
paired = TRUE,
p.adjust.method = "bonferroni" # or "holm"
)
print(posthoc)
# Compact display
posthoc %>%
select(group1, group2, p.adj, p.adj.signif) %>%
arrange(p.adj)
# === STEP 6: Visualize Results ===
# Bar plot with error bars
data_summary <- data_long %>%
group_by(timepoint) %>%
summarise(
M = mean(cortisol),
SE = sd(cortisol)/sqrt(n())
)
ggplot(data_summary, aes(x=timepoint, y=M, fill=timepoint)) +
geom_bar(stat="identity", width=0.6, alpha=0.8) +
geom_errorbar(aes(ymin=M-1.96*SE, ymax=M+1.96*SE), width=0.2) +
labs(title="Diurnal Cortisol Pattern After Mindfulness Training",
x="Time of Day", y="Mean Cortisol(μg/dL) ± 95% CI") +
scale_fill_brewer(palette="Blues") +
theme_classic() +
theme(legend.position="none")
# === APA-Style Reporting ===
cat("\n=== APA Results ===")
cat("
A one-way repeated measures ANOVA was conducted to examine diurnal cortisol
patterns following 8 weeks of mindfulness training(N=40). Mauchly's test
indicated that the assumption of sphericity was met, χ²(5) = 8.32, p = .14.
There was a significant effect of time of day on cortisol levels,
F(3, 117) = 287.45, p < .001, partial η² = .88 (large effect).
Post-hoc pairwise comparisons with Bonferroni correction revealed:
- Cortisol significantly increased from awakening(M=0.52, SD=0.12) to
+30 minutes(M=0.68, SD=0.15), p < .001 (cortisol awakening response).
- Cortisol then declined significantly from +30min to noon(M=0.24, SD=0.08),
p < .001.
- Bedtime cortisol(M=0.08, SD=0.04) was significantly lower than all other
timepoints, all p < .001.
These results demonstrate a normal diurnal cortisol rhythm with expected
awakening response and evening nadir, consistent with healthy HPA axis
function following mindfulness training.
")F(3, 117) = 287.45, p < .001, partial η² = .88 (very large effect). Significant main effect of time of day on cortisol. Post-hoc tests show classic diurnal pattern: awakening response (+31% from awakening to +30min, p < .001), then progressive decline to bedtime nadir (p < .001 for all comparisons). Results consistent with Matousek et al. (2010) showing mindfulness preserves healthy HPA axis function.
Alternatives
Structured fallback pathways for choosing alternative tests when normality or slopes requirements fail.
- Greenhouse-Geisser Correction — The mandatory safeguard when Mauchly's strike is significant.
- MANOVA Profile Analysis — Treat timepoints as independent outcomes to bypass the sphericity mandate.
- Friedman Test — The rank-based equivalent for non-normal temporal distributions.
- Bootstrap RM Strike — Generate robust CIs for the temporal mean-shift.
Post-hoc
Group mean comparisons and correction controls (e.g. Tukey HSD, Bonferroni) to protect against Family-Wise Error Rates.
Post-hoc pairwise tests defined for this model.
No specific guidelines provided.
Effect Size
Understanding effect sizes (e.g., Cohen's d, Partial Eta-Squared) and clinical impact benchmarks.
Proportion of variance in DV explained by IV after removing variance from other factors. Small: .01, Medium: .06, Large: .14 (Cohen, 1988)
Comparable across different designs (within vs between). Small: .02, Medium: .13, Large: .26 (Bakeman, 2005)
For pairwise comparisons. Calculated on difference scores. Small: 0.2, Medium: 0.5, Large: 0.8
Coefficient of concordance (0-1). Measures effect size for Friedman test (non-parametric alternative)
0.2
0.5
0.8
Sample Size
Guidelines for minimum sample requirements and power analysis parameters.
The 'Self-Control' Minimum: A minimum of 15 participants is required for a pure within-subjects discovery, provided the temporal measurements are highly reliable.
| Effect Size | Parameters | Required n |
|---|---|---|
| Small Effect | f=.10 (Small) | n ≈ 120 total |
| Medium Effect | f=.25 (Medium) | n ≈ 28 total |
| Large Effect | f=.40 (Large) | n ≈ 15 total |
Sphericity is the gatekeeper. If the correlation between timepoints is not uniform, the Greenhouse-Geisser correction will 'deflate' your power. Always recruit 20% more than the power target to account for 'Drop-out' at late-stage timepoints.
Reporting
How to compile statistical results into publication prose matching APA and journal style guides.
A one-way repeated measures ANOVA was conducted to examine brief description, e.g., 'changes in anxiety across 5 CBT sessions'. State sample: 'N = X participants completed assessments at k timepoints'. Assumption checks: 'Mauchly's test indicated that the assumption of sphericity was [met/violated, χ²(df) = X.XX, p = .XXX. If violated: Therefore, Greenhouse-Geisser/Huynh-Feldt corrected results are reported (ε = X.XX)'.] There was a significant/non-significant effect of IV on DV, F(df1, df2) = X.XX, p = .XXX, partial η² = .XX interpret: small/medium/large effect. If significant: Post-hoc pairwise comparisons using Bonferroni/Holm correction indicated describe key differences with means, SDs, and p-values. Conclude with interpretation in context.
- F-statistic with degrees of freedom (report corrected df if sphericity violated)
- p-value (corrected if sphericity violated)
- Effect size (partial η² or generalized η²)
- Mauchly's test result (W statistic, df, p-value)
- Greenhouse-Geisser or Huynh-Feldt epsilon if sphericity violated
- Descriptive statistics per condition/timepoint (M, SD, n)
- Post-hoc pairwise results if significant (p-values, effect sizes)
- Statement about assumption checks
Manuscript Lab
Copy standard summary tables and forensic reporting grids to outline analysis details.
| Source | SS | df | MS | F | p | ηp² |
|---|---|---|---|---|---|---|
| Time (Within) | 112.4 | 1.42 | 79.15 | 18.45 | < .001 | .19 |
| Error (Within) | 654.2 | 112.18 | 5.83 | — | — | — |
| Total | 766.6 | 113.6 | — | — | — | — |
The primary factor auditing internal change within the same subjects over multiple intervals.
Adjusted degrees of freedom. In RM-ANOVA, we reduce the df (using GG or HF) to penalize the model for correlated errors across time.
Purified Variance. Standardized estimate of signal strength per temporal unit.
The Temporal Pulse. Measures how much stronger the 'Recovery Signal' is than random internal variation.
The Chance Probability. Likelihood that the observed trajectory occurred by fluke. Target < .05.
Trajectory Ownership. The percentage of internal variance accounted for solely by the passage of time.
Command Center
Syntax libraries and function parameters for executing calculations in stats packages.
# 1. Execute RM-ANOVA with automatic Sphericity checks
model <- afex::aov_ez(id = 'subject_id', dv = 'score', data = df, within = 'timepoint')
summary(model)
# 2. Extract Pairwise Temporal Contrasts
emmeans(model, pairwise ~ timepoint, adjust = 'bonferroni')Instantly identify if your temporal data requires a Greenhouse-Geisser shield or a pivot to LMM.
# Execute Sphericity and Variance Audit
performance::check_sphericity(model)
# Generate APA Narrative including GG epsilon values
report::report(model)Common Mistakes
Analytical caveats and corrections to maintain modeling integrity.
References
Scholarly lineage and citation keys grounding the statistical framework.