Celeus

Repeated-measures ANOVA or a linear mixed model?

Repeated-measures ANOVA drops anyone with a missing visit; a linear mixed model keeps every observation. When each fits, shown on one dataset run both ways.

Updated . Written by Matt Gencer.

On this page

You measured the same people (or animals, plots, cultures) at several time points, and now you need a test. Two methods dominate: repeated-measures ANOVA and the linear mixed model, also called a mixed effects model. For complete, balanced data with one within-subject factor they give nearly the same answer. They part ways the moment a visit is missing, and in real studies a visit is almost always missing somewhere.

The deciding question is therefore not “which is more modern” but “does every subject have every measurement, and what do I want to estimate?”. If anything is missing or the design is unbalanced, a linear mixed model is the better default, because it uses every observation that exists. Repeated-measures ANOVA is acceptable when the data are complete, balanced, and have one within-subject factor, and your question is whether the means differ across its levels.

This guide explains how each method works, what it assumes about missing data, and how to choose. It then analyses one public dataset both ways: R’s ChickWeight data, 50 chicks weighed up to 12 times over three weeks, where five chicks have fewer weighings than the rest. Both analyses were run in R. You will see how many chicks each method keeps, what each one reports, and why the two answers are not answers to the same question.

Repeated-measures ANOVA or a linear mixed model: start with your missing visits

Both methods respect the fact that repeated measurements on one subject are correlated, which a plain one-way ANOVA ignores. They handle that correlation differently, and that difference is what produces the practical gap.

Repeated-measures ANOVA works on a table with one row per subject and one column per visit (the “wide” layout), so a subject with an empty cell has no usable row. A mixed model works on the “long” layout, one row per observation, with a column saying which subject each row belongs to. A missing visit removes only that observation, and the same subject’s other visits still contribute.

If you are comparing exactly two time points on the same units, you are in paired t-test territory, covered in paired t-test vs Wilcoxon. The methods below earn their keep at three or more visits.

Repeated-measures ANOVA

The null hypothesis is that the mean outcome is the same at every visit. The method needs one within-subject factor (time, condition) and a subject identifier, and it needs each subject measured at every level of that factor. It treats the visits as unordered categories: it does not know that day 10 comes between day 8 and day 12, and it does not use the spacing between visits. The alternative hypothesis is simply that at least one visit mean differs from another.

That framing makes it an omnibus test. A significant result says the means are not all equal. It does not say how fast the outcome changes, in which direction, or between which visits. You need follow-up comparisons or contrasts for that, with the multiplicity they bring (see multiple comparisons).

Sphericity and the Greenhouse-Geisser correction

Its main extra assumption is sphericity: the variances of the differences between every pair of visits are equal. Real longitudinal data often violate it. Measurements taken close together usually agree more than measurements taken far apart, and in anything that grows, the spread between subjects widens over time. A violated assumption inflates the false-positive rate of the uncorrected F test.

The standard remedy is a correction that multiplies both degrees of freedom by a factor epsilon, of which the Greenhouse-Geisser version (Greenhouse and Geisser, 1959) is the best known. An epsilon of 1 means no correction was needed. The smallest possible value is 1 divided by the number of visits minus one, which means the correction can shrink the degrees of freedom a long way when the violation is severe.

A common habit is to run Mauchly’s test first and apply the correction only if it is significant. That gate is weak. A non-significant Mauchly’s test means a violation was not detected, not that sphericity holds, and the test has little power in small samples. Applying the Greenhouse-Geisser correction every time costs little when sphericity holds and protects the error rate when it does not.

Effect size

For effect size, the classic options travel badly between designs. Classic eta-squared shrinks as other factors are added to the design, and partial eta-squared in a within-subject design leaves out the between-subject variation that a between-subject study of the same question would include. Generalized eta-squared was designed to make within-subject and between-subject effects comparable, and Bakeman (2005) recommends reporting it routinely where it applies.

The weakness: whole subjects are dropped

A subject with one missing visit is dropped entirely. That costs power, because good observations are thrown away with the missing one. It can also bias the result. If the subjects who miss visits differ from those who do not, the complete-case analysis describes a different group from the one you enrolled.

Linear mixed models (mixed effects models)

A linear mixed model writes the outcome as a fixed part, which is what you report, plus random parts that describe how subjects differ from one another (Laird and Ware, 1982). The fixed part is a regression: an intercept and the effects of your predictors, read much as you would read ordinary regression output. The random parts absorb the correlation between repeated measurements on one subject, so the standard errors of the fixed effects account for it.

The workhorse implementation in R is lme4 (Bates et al., 2015). Its formula notation makes the structure explicit: weight ~ Time + (Time | Chick) means a fixed intercept and slope for time, plus an intercept and a slope that vary from chick to chick.

Random intercepts

The simplest version adds a random intercept for each subject: each subject gets their own baseline level, and the fixed effects are estimated on top of it. This is the mixed-model counterpart of repeated-measures ANOVA, and with complete, balanced data and time as a factor the two agree closely.

A random-intercept model yields the intraclass correlation (ICC): the share of the total variance that sits between subjects rather than within them. An ICC near 0 says repeated measurements on one subject are no more alike than measurements on different subjects, so the repeated-measures structure hardly matters. A high ICC says it matters a great deal.

Random slopes

A random intercept assumes every subject changes at the same rate, with only their starting level differing. That is rarely true of growth, decline or recovery. When subjects change at different rates, their trajectories fan out, and a model that forces one common slope on everyone treats that fanning as noise.

The fix is a random slope: each subject also gets their own rate of change, drawn from a distribution whose average is the fixed slope you report. Barr and colleagues (2013) argued, and showed by simulation, that mixed models generalize best when they include the random effects the design justifies, and that random-intercept-only models fitted to within-subject data generalize worse than the older by-subject and by-item analyses they were meant to improve on, when subjects differ in how strongly they respond. The reason, in short, is that such a model understates how much the effect varies between subjects, so its standard error is too small. Once the model has a random slope, the share of variance between subjects depends on the time point, so there is no longer a single ICC: the variance components are reported separately.

Time as a number

A mixed model can treat time as a number rather than as a set of categories. The fixed effect of time is then a rate: the average change in the outcome per unit of time. That answers a question repeated-measures ANOVA cannot ask, and it copes naturally with unequal spacing between visits or subjects measured at different times. The price is an assumption about the shape of change. A single time term assumes a straight line, and if change is curved you need a curve, for example a squared time term or a transformed outcome. Treating time as a factor instead makes no shape assumption and reproduces the ANOVA’s omnibus question inside the mixed model.

Small-sample inference

The p-values need care with few subjects. A Kenward-Roger adjustment (Kenward and Roger, 1997) gives an F test with adjusted denominator degrees of freedom and a corrected standard error, which is more honest than treating the test statistic as a large-sample normal. The model is fitted by restricted maximum likelihood (REML), which reduces the downward bias of variance estimates that ordinary maximum likelihood shows in small samples.

This is also why lme4’s own summary prints t values for the fixed effects but no p-values: in finite samples the null distributions of those tests are not exactly t or F, and its authors chose not to build in one of the approximate degrees-of-freedom methods, pointing users to other packages instead (Bates et al., 2015). Kenward-Roger is one approximation; Satterthwaite’s is another, cheaper to compute on large data (Kuznetsova et al., 2017). Whichever you use, name it in the methods section.

Random effects are not the only way to model the correlation. A mixed model can instead give the residuals a covariance structure directly: compound symmetry (one shared correlation between any two visits, the structure sphericity is built on), first-order autoregressive (correlation decays with the gap between visits), or unstructured (every pair of visits has its own correlation). That route suits fixed visit schedules with time as a factor. An unstructured matrix has the fewest assumptions but needs a number of parameters that grows quickly with the number of visits, so it is a poor fit for small samples or many visits. Candidates fitted to the same data and fixed effects can be compared with an information criterion such as AIC, and the choice should be named in the methods section. This guide sticks with random effects, which describe how subjects differ and handle irregular timing naturally.

Unequal timing and changing covariates

Two situations break repeated-measures ANOVA outright and are routine for a mixed model. The first is unequal timing: subjects measured on different days, or visits spaced unevenly, such as weeks 1, 2, 4 and 12. With time as a number, the mixed model uses each observation’s actual time, and the slope is still the change per unit of time. The ANOVA can only treat each scheduled visit as a category, and a subject seen on a different day either has to be forced into the nearest slot or dropped.

The second is a covariate that changes over time, such as a dose adjusted between visits or a reading taken at each visit alongside the outcome. In the long layout it is simply another column, and the model estimates its association with the outcome within and across subjects. The wide layout has no place for it beyond one value per subject, which is why ANCOVA-style adjustment in repeated-measures ANOVA is limited to covariates measured once.

Missing data: what each method actually assumes

Statisticians sort missingness into three kinds. Data are missing completely at random when the chance of a value being missing has nothing to do with the data. They are missing at random when that chance depends only on things you observed, such as a subject’s earlier measurements. They are missing not at random when it depends on the missing value itself, such as a subject skipping a visit because they were doing badly that week.

Rubin (1976) gave the conditions under which the missing-data process can be ignored. For likelihood-based inference, which is how a mixed model is fitted, data missing at random are enough, provided the parameters of the missingness process are separate from those of the model. In practice this means a mixed model fitted to every observed value can give valid estimates when, for example, subjects with low early scores are more likely to skip later visits, because those early scores are in the data. That protection assumes the model itself is right: if the shape of change is misspecified, missing-at-random dropout can still bias the estimates.

Repeated-measures ANOVA, as a complete-case analysis, is safe only under the stronger condition of missing completely at random. Under that condition, dropping incomplete subjects loses power but not validity. Under missing at random, it can bias the estimates, because the dropped subjects are systematically different in a way the analysis has thrown away.

Neither method rescues data missing not at random, and nothing in the observed data can prove which of the three kinds you have. That is a judgement about how the data were collected, and it belongs in your methods section. What you can always do is report how many subjects and observations each analysis used, and how many measurements were missing at each visit.

Before either analysis: plot the trajectories

Whichever method you choose, draw one line per subject before you fit anything: the outcome on the vertical axis, time on the horizontal, and a thin line joining each subject’s measurements. That one picture answers most of the design questions this guide raises. You can see whether trajectories run roughly parallel (a random intercept may be enough) or fan out (they need a random slope), whether change is straight or curved (whether a single time term is enough), and where the missing measurements are (whether incomplete subjects stop early or skip visits in the middle).

It also shows outliers in context: a value that looks extreme in a histogram can be unremarkable on its own subject’s line. Check such points against the source records rather than removing them on sight. Finally, colour the lines of incomplete subjects differently. If their early measurements sit systematically above or below the others, the complete-case analysis is describing a selected group, and that is worth saying whatever method you report.

Worked example: chick growth analysed both ways

ChickWeight ships with R. It comes from an experiment on the effect of diet on early growth (Crowder and Hand, 1990): chicks were weighed at hatching, every second day until day 20, and again on day 21, giving up to 12 weighings per chick. The data have 578 rows. Most chicks have all 12 weighings. Five have fewer, with as few as 2. The documentation does not record why those weighings are missing, so this example makes no assumption about it.

The experiment also assigned chicks to four diets. Both analyses below set diet aside and ask only how weight changes over time, because the point is to compare the two methods on one within-subject question. The diet question needs a model with a diet-by-time interaction, which is a different analysis.

Repeated-measures ANOVA on the weighing days

The first run treats the 12 weighing days as the levels of a within-subject factor, with the chick as the subject. The method needs every chick weighed on every day, so the engine dropped the 5 chicks with a missing weighing and analysed the remaining 45, which is 540 rows.

With the Greenhouse-Geisser correction applied, the test gave F(1.22, 53.75) = 231.6, p < 0.001. Generalized eta-squared was 0.7108 (95% CI 0.6707 to 0.7416), and partial eta-squared was 0.8403. The engine notes that the effect-size intervals are computed from the uncorrected degrees of freedom, while the F test uses the corrected ones.

Look at the numerator degrees of freedom. With 12 levels, the uncorrected value would be 11. The correction shrank it to 1.22, close to the smallest value the correction allows. That is a severe sphericity violation, and it is what growth data typically produce: chicks start at similar weights and spread out as they grow, so differences between distant weighing days vary far more than differences between neighbouring ones. An uncorrected test here would have been badly miscalibrated.

What the result says is narrow: among the 45 chicks weighed on every day, mean weight is not the same on all 12 days. For growing chicks that was never in doubt. The test does not say how fast they grew.

Linear mixed model on every weighing

The second run fits a linear mixed model to all 578 weighings from all 50 chicks. Weight is the outcome, time in days is a numeric predictor, and each chick has its own intercept and its own slope. The random slope is there because the growth curves fan out: plotted one line per chick, the lines spread apart as the days pass, so chicks gain weight at different rates, and a random intercept alone would impose one rate on every chick. The engine kept chicks with as few as 2 weighings; the median chick contributed 12.

The fixed effect of time, the average daily gain under a straight-line trend, was 8.453 grams per day (95% CI 7.366 to 9.54). The Kenward-Roger test for the time effect gave F(1, 48.74) = 244.2, p < 0.001.

The random effects describe how chicks differ. The standard deviation of the chick-specific slopes was 3.761 grams per day, a sizeable spread around an average of 8.453, which is the fanning-out the random slope was added to capture. The standard deviation of the chick-specific intercepts was 11.85 grams, and the residual standard deviation, the scatter of individual weighings around each chick’s own line, was 12.79 grams. The estimated correlation between a chick’s intercept and its slope was -0.9508.

That correlation needs care. A value so close to -1 puts the model near the edge of what it can estimate: the two random effects move almost in lockstep. Here it largely reflects the straight line itself: when a line is forced through growth that speeds up, a chick with a steeper fitted slope gets a lower fitted day-0 value, even though the chicks started at similar weights. The value also depends on where time zero sits; measuring time from the middle of the study would change it. Treat it as a sign that the straight-line model is a simplification, not as a finding about the chicks.

The fixed intercept, 29.18 grams, is the straight line’s value at day 0. It is not an estimate of hatching weight, for the same reason.

Side by side

Repeated-measures ANOVA Linear mixed model
Chicks analysed 45 of 50 50 of 50
Rows analysed 540 578
Time treated as 12 categories a number (days)
Question answered Do mean weights differ across the 12 days? How much weight is gained per day, on average?
Test of time F(1.22, 53.75) = 231.6 F(1, 48.74) = 244.2
Main estimate generalized eta-squared 0.7108 (95% CI 0.6707 to 0.7416) 8.453 g/day (95% CI 7.366 to 9.54)

What the comparison shows

Both tests find a clear time effect, and with chicks growing for three weeks it would have been strange if either had not. The difference that matters is in the other rows of the table.

The ANOVA threw away 5 of 50 chicks and 38 weighings that were perfectly usable. It assumed nothing about why those chicks were incomplete, which means its result is only safe if their missing weighings were unrelated to how they were growing. The mixed model kept every weighing, and its estimates stay valid under the weaker missing-at-random condition, provided its straight-line form is adequate. Nothing in these data says which condition holds.

The two methods also answer different questions. The ANOVA answers an omnibus question across days and returns a proportion of variance. The mixed model answers a linear-trend question and returns a rate in grams per day with a confidence interval, plus an estimate of how much that rate varies between chicks. Neither is wrong; they are not interchangeable. Choose the method by the question before you look at results.

Reading the assumption checks

The mixed model’s checks came back mixed. Shapiro-Wilk on the residuals detected non-normality (W = 0.9891, p < 0.001). With 578 observations the test detects even small departures, and the fixed-effect estimates are fairly robust to non-normal residuals at this sample size. The likelier problem is the one the residuals are pointing at: growth is curved, and a straight line leaves a curved pattern in the residuals. The engine also counted 9 weights beyond the usual outlier fence and changed nothing, as it should.

The normality checks on the chick-specific intercepts and slopes did not detect a departure (p = 0.8704 and p = 0.9599). As always, that means a problem was not detected, not that the random effects are normal.

The repeated-measures ANOVA reports no sphericity test; the Greenhouse-Geisser correction is applied every time, and the size of the correction is itself the most useful diagnostic.

What this example does not answer

The straight-line slope is an average rate over 21 days. If the question were the shape of growth, the model would need a curve. If the question were which diet grows chicks fastest, it would need a diet-by-time interaction, with diet as a between-subject factor. For between-subject factors in an ANOVA setting, see two-way ANOVA; for adjusting a comparison for a baseline measurement, see ANCOVA. Neither analysis here says anything about diets, and neither says anything about why some chicks have fewer weighings.

Running both in R

The analyses above can be reproduced with a few lines of R. The mixed model uses lme4 with Kenward-Roger inference from the pbkrtest package. The repeated-measures ANOVA uses afex, with the Greenhouse-Geisser correction and generalized eta-squared requested explicitly in the call.

data(ChickWeight)
d <- as.data.frame(ChickWeight)
d$Chick <- factor(d$Chick, ordered = FALSE)

# Linear mixed model: every weighing, a random intercept and slope per chick
fit <- lme4::lmer(weight ~ Time + (Time | Chick), data = d, REML = TRUE)
summary(fit)

# Kenward-Roger F test for the time effect
reduced <- lme4::lmer(weight ~ 1 + (Time | Chick), data = d, REML = TRUE)
pbkrtest::KRmodcomp(fit, reduced)

# Repeated-measures ANOVA: time as a factor, complete chicks only
d$TimeF <- factor(d$Time)
afex::aov_ez(id = "Chick", dv = "weight", within = "TimeF", data = d,
       anova_table = list(correction = "GG", es = "ges"))

As described above, summary(fit) shows t values without p-values; the Kenward-Roger line supplies the test. aov_ez should warn that it removed the chicks with missing cells and name them. Read that warning rather than suppressing it: it is the complete-case cost, stated in plain text.

How to report each

For the mixed model, report the model structure, the estimate with its interval, the inference method, and how many subjects and observations entered. From this example: “A linear mixed model with a random intercept and a random slope for time per chick, fitted by REML to all 578 weighings from 50 chicks, estimated an average weight gain of 8.453 g per day (95% CI 7.366 to 9.54; Kenward-Roger F(1, 48.74) = 244.2, p < 0.001). The standard deviation of chick-specific slopes was 3.761 g per day.”

For repeated-measures ANOVA, report the correction, the corrected degrees of freedom, generalized eta-squared with its interval, and the number of subjects analysed and excluded: “A repeated-measures ANOVA with Greenhouse-Geisser correction on the 45 chicks weighed on all 12 days (5 chicks with a missing weighing excluded) found that mean weight differed across days, F(1.22, 53.75) = 231.6, p < 0.001, generalized eta-squared 0.7108 (95% CI 0.6707 to 0.7416).”

In either case, avoid “proves”, avoid reading a p-value as the probability that the null hypothesis is true, and never describe a non-significant time effect as evidence that nothing changed.

When repeated-measures ANOVA is still fine

If every subject has every measurement, the design is balanced, and there is a single within-subject factor with a few levels, repeated-measures ANOVA and a random-intercept mixed model with time as a factor agree closely, and the ANOVA is simpler to explain to a reviewer who expects it. The agreement is with the uncorrected test: a random-intercept model assumes compound symmetry, so if sphericity is doubtful, use the Greenhouse-Geisser-corrected ANOVA or give the mixed model an unstructured or autoregressive covariance. Reach for the mixed model anyway if you have more than one level of clustering (several samples per subject at each visit, or subjects grouped within clinics or litters, for example), unequal spacing of visits, a continuous time variable, a question about rates of change, or a covariate that changes over time. None of these fit the one-row-per-subject table that repeated-measures ANOVA needs.

When the repeated outcome is not continuous

Everything above assumes a continuous outcome such as a weight, a score or a concentration. Repeated binary outcomes (whether a symptom is present at each visit) and repeated counts (how many events occurred in each period) need a generalized linear mixed model instead: a mixed logistic model for the binary case and a mixed Poisson model for counts. The idea carries over directly. Each subject gets a random intercept, every observed measurement is used, and the fixed effects are reported as subject-specific odds ratios or rate ratios rather than differences in means.

Repeated-measures ANOVA has no counterpart for these outcomes. Running it on a 0/1 outcome or on small counts treats them as continuous and normally distributed, which they are not. For the single-measurement versions of these models, see logistic regression and Poisson vs negative binomial regression.

Common mistakes

  • Dropping incomplete subjects silently. Repeated-measures software does this for you. Always report how many subjects were excluded and why.
  • Gating the sphericity correction on Mauchly’s test. Apply the Greenhouse-Geisser correction every time.
  • Running separate one-way ANOVAs or t-tests at each visit. That ignores the pairing and multiplies the number of tests.
  • Using a random intercept when subjects change at different rates. The time effect’s standard error comes out too small. Add a random slope, or say why the data cannot support one.
  • Treating time as a number without checking the shape. A straight line through curved change gives an average rate that may describe no subject well. Plot the trajectories first.
  • Reading the mixed model’s intercept as a baseline. It is the fitted value where time is 0 under the model’s shape, which may not match any observed baseline.
  • Running both methods and reporting the more flattering p-value. Decide from the design and the question before looking at results. That is the same mistake as in any other choice of test; for the wider decision tree, see how to choose a statistical test.

Which one to report

  • Any visit is missing, or the design is unbalanced: the linear mixed model. Report the fixed-effect estimates with confidence intervals, the method used for the p-value, the random-effects structure, and how many observations and subjects entered.
  • Your question is about a rate of change: the linear mixed model with time as a number, with a random slope when subjects plausibly change at different rates.
  • Complete, balanced, one within factor, and the question is whether means differ across levels: repeated-measures ANOVA is acceptable. Report the Greenhouse-Geisser corrected degrees of freedom and a generalized eta-squared.
  • Whichever you choose: say how many subjects and observations were analysed, and do not drop incomplete subjects silently.

Rerunning the example

The script attached to the worked example below reproduces the linear mixed model: it reloads the ChickWeight data, fits the same model with the same settings, and recomputes the Kenward-Roger test, the time estimate and its interval. It does not include the repeated-measures ANOVA; that was a second run on the same data, and the R code in the section above shows how to run it yourself. For what it takes to make an analysis like this repeatable, see what makes a statistical analysis reproducible.

How Celeus handles this

Celeus offers both methods; see the method reference pages for repeated-measures ANOVA and the linear mixed model. For repeated-measures ANOVA it always applies the Greenhouse-Geisser correction and reports generalized eta-squared, and when subjects with a missing visit had to be dropped it says so and recommends the linear mixed model. The mixed model takes an optional random slope, uses Kenward-Roger inference when the data are small enough for it and Satterthwaite’s above that size, reports the ICC for a random-intercept model and the variance components for every model, and checks the normality of the residuals and of the subject-level effects.

Worked example

Data: Crowder MJ, Hand DJ (1990). Analysis of Repeated Measures. Chapman and Hall, London (reissued by Routledge, 2017). Example 5.3, pages 74-78. https://doi.org/10.1201/9781315137421. Seed: 20261022.

Run on Celeus engine 0.31.1, seed 20261022, public data.

Output

# Results

- Test: Linear mixed-effects model (random intercept and slope)
- n: 578
- statistic: 244.2
- p-value: < 0.001
- effect size: NA
- 95% CI: [7.366, 9.54]
- seed: 20261022

## Assumption checks
- normality (Shapiro-Wilk): passed=FALSE (evidence of non-normality)
- random-intercept normality (Shapiro-Wilk on BLUPs): passed=TRUE (no evidence against normality)
- random-slope normality (Shapiro-Wilk on BLUPs): passed=TRUE (no evidence against normality)

## Term tests
| Term | Test | Statistic | df | Residual df | p-value |
|---|---|---|---|---|---|
| Time | F | 244.2 | 1 | 48.74 | < 0.001 |

## Random effects
- degrees of freedom: Kenward-Roger
- cluster sizes: 2 to 12 rows (median 12); 0 cluster(s) with a single row
- predictors: Time (within cluster)
| Group | Term | With | Variance | SD or correlation | 95% CI |
|---|---|---|---|---|---|
| Chick | (Intercept) | - | 140.5 | 11.85 | - |
| Chick | Time | - | 14.14 | 3.761 | - |
| Chick | (Intercept) | Time | - | -0.9508 | - |
| Residual | - | - | 163.5 | 12.79 | - |
- variance component intervals: not computed for a random-slope model (too costly to profile on every run)

## Power
- Power is not calculated for this test.
R script
# Celeus - reproduce.R  (run from this package folder; bundled data in data/)
# Test: Linear mixed-effects model (random intercept and slope)  |  engine 0.31.1  |  catalog c39-d3cd
# Research context: not provided for this run.
# Reproduces the recorded result deterministically.

set.seed(20261022)
.data_path <- "data/repeated-measures-anova-vs-mixed-model.csv"
if (!file.exists(.data_path)) stop("Run reproduce.R from the package folder (the bundled data is in data/).")
data <- readr::read_csv(.data_path, show_col_types = FALSE)  # needs the readr package
clean_cells <- function (df) 
{
    ctrl_collapse <- "[\r\n\t\v\f]+"
    zero_width_chars <- intToUtf8(c(8203L, 65279L), multiple = TRUE)
    uni_space_chars <- intToUtf8(c(160L, 8239L, 8199L), multiple = TRUE)
    clean_text <- function(x) {
        out <- x
        for (ch in zero_width_chars) out <- gsub(ch, "", out, 
            fixed = TRUE)
        out <- gsub(ctrl_collapse, " ", out)
        for (ch in uni_space_chars) out <- gsub(ch, " ", out, 
            fixed = TRUE)
        trimws(gsub(" +", " ", out))
    }
    changed_cols <- character(0)
    cells_cleaned <- 0L
    retyped <- character(0)
    for (j in seq_along(df)) {
        col <- df[[j]]
        if (!is.character(col)) 
            next
        cleaned <- clean_text(col)
        n_changed <- sum(!is.na(col) & !is.na(cleaned) & col != 
            cleaned, na.rm = TRUE)
        if (n_changed > 0L) {
            changed_cols <- c(changed_cols, names(df)[j])
            cells_cleaned <- cells_cleaned + n_changed
        }
        df[[j]] <- cleaned
        non_blank <- cleaned[!is.na(cleaned) & nzchar(cleaned)]
        if (length(non_blank) && all(grepl("^[+-]?(0|[1-9][0-9]*)([.][0-9]+)?$", 
            non_blank))) {
            parsed <- suppressWarnings(as.numeric(cleaned))
            was_blank <- is.na(cleaned) | !nzchar(cleaned)
            lost <- (is.na(parsed) | is.infinite(parsed)) & !was_blank
            if (!any(lost)) {
                finite <- parsed[!is.na(parsed)]
                all_whole <- all(finite == floor(finite))
                in_range <- all(abs(finite) <= .Machine$integer.max)
                df[[j]] <- if (all_whole && in_range) 
                  as.integer(parsed)
                else parsed
                retyped <- c(retyped, names(df)[j])
            }
        }
    }
    names(df) <- clean_text(names(df))
    if (length(changed_cols)) {
        attr(df, "ingest_clean_columns") <- changed_cols
        attr(df, "ingest_clean_cells_cleaned") <- cells_cleaned
    }
    if (length(retyped)) 
        attr(df, "ingest_clean_retyped") <- retyped
    df
}
data <- clean_cells(data)
# Complete-case analysis: drop rows missing any analysis value.
.acols <- c("weight", "Time", "Chick")
data <- data[stats::complete.cases(data[, .acols, drop = FALSE]), , drop = FALSE]
result <- { .full <- lme4::lmer(`weight` ~ `Time` + (1 + `Time` | `Chick`), data = data, REML = TRUE); .tt <- { .X <- lme4::getME(.full, "X"); .asg <- attr(.X, "assign"); .I <- diag(ncol(.X)); t(vapply(sort(unique(.asg[.asg > 0L])), function(j) unlist(pbkrtest::KRmodcomp(.full, .I[.asg == j, , drop = FALSE])$test["Ftest", c("stat", "ndf", "ddf", "p.value")]), numeric(4L))) }; .p <- .tt[1L, "p.value"]; .ct <- { .V <- pbkrtest::vcovAdj(.full); .V0 <- as.matrix(stats::vcov(.full)); .L <- diag(ncol(.V0)); .b <- lme4::fixef(.full); .se <- sqrt(diag(as.matrix(.V))); .df <- vapply(seq_len(ncol(.V0)), function(i) pbkrtest::Lb_ddf(L = .L[i, , drop = FALSE], V0 = .V0, Vadj = .V), numeric(1L)); .tv <- .b / .se; .q <- stats::qt(1 - (1 - 0.95) / 2, .df); cbind(Estimate = .b, `Std. Error` = .se, df = .df, `t value` = .tv, `Pr(>|t|)` = 2 * stats::pt(abs(.tv), .df, lower.tail = FALSE), conf.low = .b - .q * .se, conf.high = .b + .q * .se) }; list(model = summary(.full), p_value = unname(.p), estimate = unname(.ct[2L, "Estimate"]), conf_int = unname(.ct[2L, c("conf.low", "conf.high")]), coefficients = .ct, term_tests = .tt) }
print(result)

Common questions

What is the difference between repeated-measures ANOVA and a linear mixed model?

Both analyse several measurements on the same subjects. Repeated-measures ANOVA needs one row per subject with every measurement present and tests whether the means differ across occasions. A linear mixed model works on one row per observation, keeps subjects with missing measurements, and can treat time as a number with subject-specific trends.

Does a linear mixed model handle missing data?

It uses every observed measurement, so a subject with one missed visit still contributes the others. Its estimates stay valid when the chance of a value being missing depends only on data you observed, provided the model itself is correctly specified. It does not fix missingness caused by the unobserved values themselves, and nothing in the data can show which case you are in.

When is repeated-measures ANOVA still fine?

When every subject has every measurement, the design is balanced, there is one within-subject factor with a few levels, and your question is whether the means differ across those levels. In that setting it gives the same F as a random-intercept mixed model before any correction, and is familiar to reviewers. Apply the Greenhouse-Geisser correction, which the random-intercept model does not do.

Do I need Mauchly's test before a repeated-measures ANOVA?

No. A non-significant Mauchly's test means a sphericity violation was not detected, not that sphericity holds, and the test has little power in small samples. Applying the Greenhouse-Geisser correction every time costs little when sphericity holds and protects you when it does not.

Should a linear mixed model include a random slope?

Include a random slope for time when subjects can plausibly change at different rates, which is the usual situation with growth or decline. Leaving it out forces one common rate on everyone and makes the standard error of the time effect too small. Drop it only when the data cannot support it, and say so.

Which covariance structure should I choose for a repeated-measures mixed model?

Match it to the design. Compound symmetry is the simplest and is the structure sphericity is built on, first-order autoregressive suits evenly spaced visits where nearby visits agree more, and unstructured makes the fewest assumptions but needs many parameters. Compare candidates on the same data with an information criterion such as AIC, and name the choice in your methods.

Can I use a linear mixed model if my repeated outcome is binary or a count?

Not the linear one. Repeated binary outcomes need a mixed logistic model and repeated counts a mixed Poisson model, each with a random intercept per subject. Repeated-measures ANOVA has no counterpart for these outcomes, and fitting it to 0/1 data or small counts treats them as normally distributed.

Sources

  1. Greenhouse SW, Geisser S (1959). On methods in the analysis of profile data. Psychometrika 24(2):95-112. doi:10.1007/BF02289823
  2. Laird NM, Ware JH (1982). Random-effects models for longitudinal data. Biometrics 38(4):963-974. doi:10.2307/2529876
  3. Kenward MG, Roger JH (1997). Small sample inference for fixed effects from restricted maximum likelihood. Biometrics 53(3):983-997. doi:10.2307/2533558
  4. Bates D, Maechler M, Bolker B, Walker S (2015). Fitting linear mixed-effects models using lme4. Journal of Statistical Software 67(1). doi:10.18637/jss.v067.i01
  5. Bakeman R (2005). Recommended effect size statistics for repeated measures designs. Behavior Research Methods 37(3):379-384. doi:10.3758/BF03192707
  6. Rubin DB (1976). Inference and missing data. Biometrika 63(3):581-592. doi:10.1093/biomet/63.3.581
  7. Barr DJ, Levy R, Scheepers C, Tily HJ (2013). Random effects structure for confirmatory hypothesis testing: keep it maximal. Journal of Memory and Language 68(3):255-278. doi:10.1016/j.jml.2012.11.001
  8. Kuznetsova A, Brockhoff PB, Christensen RHB (2017). lmerTest package: tests in linear mixed effects models. Journal of Statistical Software 82(13):1-26. doi:10.18637/jss.v082.i13

Methods discussed

Try it on your own data

Upload a dataset and Celeus suggests a method, checks its assumptions, runs it in R, and gives you the script to rerun it.

Try it in Celeus