RM_ANOVA

Repeated-measures ANOVA evaluates mean differences across within-subject conditions while accounting for subject-level dependence.

It partitions variability into within-condition effects and residual error after controlling for subject effects. Pingouin can also report sphericity corrections and effect sizes for the repeated effect.

This wrapper accepts long-format table data and returns the repeated-measures ANOVA results table.

Excel Usage

=RM_ANOVA(data, dv, within, subject, correction, detailed, effsize)
  • data (list[list], required): Input table where the first row contains column names.
  • dv (str, required): Name of the dependent-variable column.
  • within (str, required): Name of the within-subject factor column.
  • subject (str, required): Name of the subject identifier column.
  • correction (str, optional, default: “auto”): Sphericity correction option (for example auto, True, False).
  • detailed (bool, optional, default: false): Whether to return a detailed ANOVA table.
  • effsize (str, optional, default: “ng2”): Effect size metric (for example, ng2, np2).

Returns (list[list]): 2D table containing repeated-measures ANOVA results.

Example 1: Repeated measures with three time points

Inputs:

data dv within subject
subject time score score time subject
S1 T1 5.2
S1 T2 5.8
S1 T3 6.1
S2 T1 4.9
S2 T2 5.3
S2 T3 5.7
S3 T1 5.4
S3 T2 5.9
S3 T3 6.4

Excel formula:

=RM_ANOVA({"subject","time","score";"S1","T1",5.2;"S1","T2",5.8;"S1","T3",6.1;"S2","T1",4.9;"S2","T2",5.3;"S2","T3",5.7;"S3","T1",5.4;"S3","T2",5.9;"S3","T3",6.4}, "score", "time", "subject")

Expected output:

Source ddof1 ddof2 F p_unc ng2 eps
time 2 4 122 0.000260146 0.677778 1
Example 2: Detailed repeated measures output

Inputs:

data dv within subject detailed
subject phase value value phase subject true
A pre 10.1
A post 11.2
B pre 9.8
B post 10.5
C pre 11
C post 12.3

Excel formula:

=RM_ANOVA({"subject","phase","value";"A","pre",10.1;"A","post",11.2;"B","pre",9.8;"B","post",10.5;"C","pre",11;"C","post",12.3}, "value", "phase", "subject", TRUE)

Expected output:

Source SS DF MS F p_unc ng2 eps
phase 1.60167 1 1.60167 34.3214 0.0279218 0.3976 1
Error 0.0933333 2 0.0466667
Example 3: Apply sphericity correction flag true

Inputs:

data dv within subject correction
subject cond y y cond subject true
P1 C1 2.1
P1 C2 2.4
P1 C3 2.9
P2 C1 1.9
P2 C2 2.2
P2 C3 2.8
P3 C1 2.3
P3 C2 2.6
P3 C3 3

Excel formula:

=RM_ANOVA({"subject","cond","y";"P1","C1",2.1;"P1","C2",2.4;"P1","C3",2.9;"P2","C1",1.9;"P2","C2",2.2;"P2","C3",2.8;"P3","C1",2.3;"P3","C2",2.6;"P3","C3",3}, "y", "cond", "subject", TRUE)

Expected output:

Source ddof1 ddof2 F p_unc p_GG_corr ng2 eps sphericity W_spher p_spher
cond 2 4 147 0.000180172 0.00673408 0.844828 0.5 true 600 1
Example 4: Partial eta squared effect size

Inputs:

data dv within subject effsize
id trial response response trial id np2
U1 A 3
U1 B 3.4
U2 A 2.8
U2 B 3.2
U3 A 3.1
U3 B 3.6

Excel formula:

=RM_ANOVA({"id","trial","response";"U1","A",3;"U1","B",3.4;"U2","A",2.8;"U2","B",3.2;"U3","A",3.1;"U3","B",3.6}, "response", "trial", "id", "np2")

Expected output:

Source ddof1 ddof2 F p_unc np2 eps
trial 1 2 169 0.00586515 0.988304 1

Python Code

import pandas as pd
from pingouin import rm_anova as pg_rm_anova

def rm_anova(data, dv, within, subject, correction='auto', detailed=False, effsize='ng2'):
    """
    Perform repeated-measures ANOVA on tabular data using Pingouin.

    See: https://pingouin-stats.org/build/html/generated/pingouin.rm_anova.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        data (list[list]): Input table where the first row contains column names.
        dv (str): Name of the dependent-variable column.
        within (str): Name of the within-subject factor column.
        subject (str): Name of the subject identifier column.
        correction (str, optional): Sphericity correction option (for example auto, True, False). Default is 'auto'.
        detailed (bool, optional): Whether to return a detailed ANOVA table. Default is False.
        effsize (str, optional): Effect size metric (for example, ng2, np2). Default is 'ng2'.

    Returns:
        list[list]: 2D table containing repeated-measures ANOVA results.
    """
    try:
        def to2d(x):
            return [[x]] if not isinstance(x, list) else x

        def build_dataframe(table):
            table = to2d(table)
            if not isinstance(table, list) or not table or not all(isinstance(row, list) for row in table):
                return None, "Error: data must be a non-empty 2D list"
            if len(table) < 2:
                return None, "Error: data must include a header row and at least one data row"

            headers = [str(h).strip() for h in table[0]]
            if any(h == "" for h in headers):
                return None, "Error: header row contains empty column names"
            if len(set(headers)) != len(headers):
                return None, "Error: header row contains duplicate column names"

            rows = []
            for row in table[1:]:
                if len(row) != len(headers):
                    return None, "Error: all data rows must match header width"
                rows.append([None if cell == "" else cell for cell in row])

            return pd.DataFrame(rows, columns=headers), None

        def dataframe_to_2d(df):
            out = [list(df.columns)]
            for values in df.itertuples(index=False, name=None):
                row = []
                for value in values:
                    if pd.isna(value):
                        row.append("")
                    elif isinstance(value, bool):
                        row.append(value)
                    elif isinstance(value, (int, float)):
                        row.append(float(value))
                    else:
                        row.append(str(value))
                out.append(row)
            return out

        frame, error = build_dataframe(data)
        if error:
            return error

        for col_name, col_label in [(dv, "dv"), (within, "within"), (subject, "subject")]:
            if col_name not in frame.columns:
                return f"Error: {col_label} column '{col_name}' not found"

        corr_value = correction
        if isinstance(correction, str):
            lower = correction.lower()
            if lower == "true":
                corr_value = True
            elif lower == "false":
                corr_value = False

        result = pg_rm_anova(
            data=frame,
            dv=dv,
            within=within,
            subject=subject,
            correction=corr_value,
            detailed=bool(detailed),
            effsize=effsize,
        )

        return dataframe_to_2d(result)
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

Input table where the first row contains column names.
Name of the dependent-variable column.
Name of the within-subject factor column.
Name of the subject identifier column.
Sphericity correction option (for example auto, True, False).
Whether to return a detailed ANOVA table.
Effect size metric (for example, ng2, np2).