Repeated Measures One-Way ANOVA Calculator

Subject

Understanding Repeated Measures One-Way ANOVA

The Repeated Measures One-Way ANOVA is a statistical test used to determine if there are statistically significant differences between the means of three or more related groups (such as measurements taken on the same subjects under different conditions). It is used when the same subjects are measured multiple times under different conditions or at different times.

Key Characteristics of Repeated Measures ANOVA

  • Within-subjects design: Since the same subjects are used across conditions, it removes the variability due to individual differences, resulting in greater statistical power.
  • Focus on mean differences: The test evaluates whether the mean differences across conditions are statistically significant.
  • Assumptions: Assumes that the data follows a normal distribution, variances are equal (sphericity), and there are no significant outliers.
  • Degrees of freedom: Calculated based on the number of conditions and the number of subjects.

Formula for Repeated Measures ANOVA

The ANOVA test statistic (F) is calculated by comparing the variance between conditions to the variance within conditions (error variance). The formula for the F-statistic is as follows:

\[ F = \frac{\text{Mean Square Between Treatments}}{\text{Mean Square Error}} \]

Where:

  • Mean Square Between Treatments (MSTreatment): Represents the variance between different treatment conditions and is calculated as:
    \[ \text{Mean Square Between Treatments} = \frac{\text{Sum of Squares Between Treatments (SS}_{\text{Treatment}}\text{)}}{\text{df}_{\text{Treatment}}} \]
    where:
    • \(\text{Sum of Squares Between Treatments (SS}_{\text{Treatment}}\text{)}\) is calculated as: \[ \text{SS}_{\text{Treatment}} = n \sum_{i=1}^k (\bar{X}_{i} - \bar{X}_{\text{grand}})^2 \] where:
      • \( n \): Number of subjects
      • \( k \): Number of treatments
      • \( \bar{X}_{i} \): Mean of each treatment
      • \( \bar{X}_{\text{grand}} \): Grand mean of all scores
    • \(\text{df}_{\text{Treatment}} = k - 1\), the degrees of freedom for treatments.
  • Mean Square Error (MSError): Represents the error variance within the conditions after accounting for subject variability. It is calculated as:
    \[ \text{Mean Square Error} = \frac{\text{Sum of Squares Error (SS}_{\text{Error}}\text{)}}{\text{df}_{\text{Error}}} \]
    where:
    • \(\text{Sum of Squares Error (SS}_{\text{Error}}\text{)}\) is the remaining variance not explained by the treatment or subject effects, calculated as: \[ \text{SS}_{\text{Error}} = \text{SS}_{\text{Total}} - \text{SS}_{\text{Treatment}} - \text{SS}_{\text{Subjects}} \] where \(\text{SS}_{\text{Total}}\) is the total sum of squares and \(\text{SS}_{\text{Subjects}}\) is the sum of squares for the subject effect.
    • \(\text{df}_{\text{Error}} = (k - 1)(n - 1)\), the degrees of freedom for error.

The F-statistic is then compared to the critical value from the F-distribution for the chosen significance level (e.g., 0.05) to determine if the differences between conditions are statistically significant.

Interpreting the Results

The null hypothesis for Repeated Measures ANOVA states that the means across all conditions are equal. If the p-value is less than the chosen significance level (e.g., 0.05), we reject the null hypothesis, indicating that there is a statistically significant difference between at least some conditions. If the p-value is greater than the significance level, we fail to reject the null hypothesis, suggesting that the differences between conditions are not statistically significant.

Programmatically Calculating Repeated Measures ANOVA

Below are examples of how to perform Repeated Measures ANOVA in different programming languages, using the treatments:

  • Treatment 1: [2.1, 1.2, 3.2, 2.8, 1.4]
  • Treatment 2: [7, 13, 12, 11, 10]
  • Treatment 3: [9.2, 15.1, 13.9, 13.3, 11.8]

1. Using Python (with Pingouin)

In Python, you can use the Pingouin library to perform Repeated Measures ANOVA:

import pandas as pd
import pingouin as pg

# Define data in a long format
data = pd.DataFrame({
    'Subject': ['S1', 'S2', 'S3', 'S4', 'S5'] * 3,
    'Treatment': ['T1']*5 + ['T2']*5 + ['T3']*5,
    'Score': [2.1, 1.2, 3.2, 2.8, 1.4, 7, 13, 12, 11, 10, 9.2, 15.1, 13.9, 13.3, 11.8]
})

# Perform Repeated Measures ANOVA
anova = pg.rm_anova(data=data, dv='Score', within='Treatment', subject='Subject')
print(anova)

2. Using R

In R, you can use the aov function to perform Repeated Measures ANOVA:

# Define data
subject <- factor(rep(1:5, times=3))
treatment <- factor(rep(c("T1", "T2", "T3"), each=5))
score <- c(2.1, 1.2, 3.2, 2.8, 1.4, 7, 13, 12, 11, 10, 9.2, 15.1, 13.9, 13.3, 11.8)
data <- data.frame(subject, treatment, score)

# Perform Repeated Measures ANOVA
result <- aov(score ~ treatment + Error(subject/treatment), data=data)
summary(result)

3. Using JavaScript (with jStat)

In JavaScript, you can use the jStat library to help calculate the necessary statistics, although you will need to write custom code for repeated measures ANOVA:

// Define treatment data
const treatment1 = [2.1, 1.2, 3.2, 2.8, 1.4];
const treatment2 = [7, 13, 12, 11, 10];
const treatment3 = [9.2, 15.1, 13.9, 13.3, 11.8];
const treatments = [treatment1, treatment2, treatment3];

function calculateGrandMean(data) {
    const allScores = data.flat();
    return allScores.reduce((sum, score) => sum + score, 0) / allScores.length;
}

function calculateMean(arr) {
    return arr.reduce((sum, val) => sum + val, 0) / arr.length;
}

function repeatedMeasuresANOVA(treatments) {
    const n = treatments[0].length; // number of subjects
    const k = treatments.length;    // number of treatments
    const grandMean = calculateGrandMean(treatments);

    // Calculate treatment means
    const treatmentMeans = treatments.map(calculateMean);

    // Sum of squares between treatments
    const SST = n * treatmentMeans.reduce((sum, mean) => sum + Math.pow(mean - grandMean, 2), 0);

    // Sum of squares for subjects
    const subjectMeans = Array.from({ length: n }, (_, i) =>
        calculateMean(treatments.map(treatment => treatment[i]))
    );
    const SSS = k * subjectMeans.reduce((sum, mean) => sum + Math.pow(mean - grandMean, 2), 0);

    // Total sum of squares
    const SS_Total = treatments.flat().reduce((sum, score) => sum + Math.pow(score - grandMean, 2), 0);

    // Error sum of squares
    const SSE = SS_Total - SST - SSS;

    // Degrees of freedom
    const dfTreatment = k - 1;
    const dfError = (k - 1) * (n - 1);

    // Mean squares
    const MST = SST / dfTreatment;
    const MSE = SSE / dfError;

    // F-statistic
    const F = MST / MSE;

    // p-value using jStat for F-distribution
    const pValue = 1 - jStat.centralF.cdf(F, dfTreatment, dfError);

    return { F, pValue, MST, MSE, dfTreatment, dfError };
}

// Calculate and log results
const results = repeatedMeasuresANOVA(treatments);
console.log(`F: ${results.F.toFixed(4)}, p-value: ${results.pValue.toFixed(8)}`);

Further Reading

Profile Picture
Senior Advisor, Data Science | [email protected] | + posts

Suf is a senior advisor in data science with deep expertise in Natural Language Processing, Complex Networks, and Anomaly Detection. Formerly a postdoctoral research fellow, he applied advanced physics techniques to tackle real-world, data-heavy industry challenges. Before that, he was a particle physicist at the ATLAS Experiment of the Large Hadron Collider. Now, he’s focused on bringing more fun and curiosity to the world of science and research online.