AdvancedIndependently reviewed, not yet spot-checked by a human

Clustered and repeated-measures data

Four measurements on one patient, a hundred patients in one hospital: those rows are not independent. What treating them as independent actually does — between-subject standard errors come out too small, within-subject ones come out too large, and the two errors point in opposite directions. Mixed models, GEE and cluster-robust standard errors answer three different questions.

The assumption the output cannot show you

Regression diagnostics lists four assumptions, and three of them have a plot: residuals against fitted values, the QQ plot, influence. The fourth — observations are independent of one another — is where that page stops, with the remark that this one cannot be seen. Poisson regression twice says “use GEE or a mixed-effects model” and the site has never had that page. This page settles all three debts.

Independence cannot be seen because it is not a property of the data, it is a property of how the data came about. In the same CSV, a row that is one patient and a row that is the same patient’s third visit look identical. You have to know it from the study design; no model will tell you.

Violations are more common in clinical research than people expect:

  • Repeated measures: the same patient scored for pain at 30 minutes, 90 minutes, 4 hours and the next morning
  • Cluster randomisation: clinics or wards are randomised, and patients within a clinic share the same physicians, the same processes, the same case mix
  • Multicentre studies: patients from one hospital resemble each other in quality of care more than they resemble patients from another
  • Matched designs: left and right eye, twins, matched cases and controls
  • Multistage sampling: sample schools, then sample students within schools

The common thread is that the data has two levels: the patient (or clinic), and the measurements inside the patient. Every complication follows from one fact — observations within a cluster are more alike than observations from different clusters.

The example on this page

medicaldata::licorice_gargle is a randomised trial of a licorice gargle given before intubation to prevent post-operative sore throat. 235 patients were randomised, 117 to control and 118 to licorice, and sore throat was scored at four time points.

Reshaping wide to long gives 940 rows, of which 8 scores are missing.

Spaghetti plot of individual trajectories. The horizontal axis is the four time points (PACU 30 min, PACU 90 min, 4 h post-op, POD 1 morning); the vertical axis is the sore-throat score, observed range 0 to 7. In the background are 233 thin lines, one patient each, coloured by arm and given a small vertical offset so they do not overlap exactly; most of them sit in a low band near 0, and a handful swing between 4 and 7. In the foreground two thick lines are the group mean trajectories with 95% confidence interval bars: the control mean (blue) drifts down from 1.03 to 0.65 and lies above the licorice mean at every time point; the licorice mean (red) falls from 0.27 to a low of 0.14, rises to its highest value 0.35 at 4 hours post-op, and ends at 0.32. The two mean trajectories never cross.
Each thin line is one patient. The lines are not independent of one another — the four points on any one line come from the same person, which is precisely what the naive model pretends is not the case.Plotting script figures/scripts/B2-07-clustered.R

There are two things to read off this plot. First, a patient resembles himself — that is what clustering means. But this is not something to judge by eye, and this dataset happens to show why. Most of what fills the frame is the crowd sitting near 0: of 233 patients, 122 scored exactly the same value all four times, and 120 of those scored 0 every time, so of course their lines are flat. The high-scoring lines do swing violently, but there are only 8 patients whose within-patient range reaches 4 points. The impression that “the lines are mostly flat” is carried by the patients scoring zero; it is not that the data lacks movement. What actually supports the claim that a patient resembles himself is the intraclass correlation (ICC) of 0.540 computed later on this page, not the visual. A trajectory plot shows you the shape of the variation; quantifying it takes variance components.

Second, the individual lines are too crowded to reveal the group difference, which is why the mean trajectories are drawn on top — but the means are computed from all of the data, not from the lines you can pick out. The individual lines tell you how large the variation is; the mean trajectories tell you where the effect is. A plot with only the means invites the reader to assume everyone looks like the average.

Running it yourself

library(medicaldata)
library(nlme)

lg <- licorice_gargle
lg$id <- seq_len(nrow(lg))

tp <- c("pacu30min_throatPain", "pacu90min_throatPain",
        "postOp4hour_throatPain", "pod1am_throatPain")

# Wide to long: one row per patient-by-time-point
long <- do.call(rbind, lapply(seq_along(tp), function(i)
  data.frame(id = lg$id, treat = lg$treat, t = i, pain = lg[[tp[i]]])))
L <- long[!is.na(long$pain), ]
L$idf <- factor(L$id)

# Look at the missingness pattern BEFORE analysing
table(rowSums(is.na(lg[, tp])))

# Naive model: 932 rows treated as 932 independent observations
summary(lm(pain ~ treat, data = L))

# Mixed model: one random intercept per patient
m <- lme(pain ~ treat, random = ~ 1 | idf, data = L, method = "REML")
summary(m)
VarCorr(m)                      # variance components; the ICC comes from here

# A third estimator: average each patient, then do a two-sample comparison
pm <- aggregate(pain ~ id + treat, data = L, FUN = mean)
summary(lm(pain ~ treat, data = pm))

# Within-subject contrasts: time
summary(lm(pain ~ factor(t) * treat, data = L))                    # naive
summary(lme(pain ~ factor(t) * treat, random = ~ 1 | idf, data = L))

# Cluster-robust (sandwich) standard errors, written out:
#   (X'X)^-1 [ sum_g X_g' u_g u_g' X_g ] (X'X)^-1
# one cluster per patient, times the CR1 small-sample factor.
cluster_robust_se <- function(fit, cluster) {
  X  <- model.matrix(fit)
  u  <- as.numeric(residuals(fit))
  cl <- factor(cluster)
  G <- nlevels(cl); N <- nrow(X); K <- ncol(X)
  bread <- solve(crossprod(X))
  meat  <- matrix(0, K, K)
  for (g in levels(cl)) {
    idx <- which(cl == g)
    sg  <- crossprod(X[idx, , drop = FALSE], u[idx])   # this cluster's score vector
    meat <- meat + tcrossprod(sg)
  }
  adj <- (G / (G - 1)) * ((N - 1) / (N - K))           # CR1
  setNames(sqrt(diag(bread %*% meat %*% bread * adj)), colnames(X))
}

cluster_robust_se(lm(pain ~ treat, data = L), L$id)
cluster_robust_se(lm(pain ~ factor(t) * treat, data = L), L$id)
# In practice: sandwich::vcovCL(fit, cluster = L$id, type = "HC1").
# This site installs no extra packages, hence the hand-written version.

Verified on R 4.6.0 with nlme 3.1.169 and medicaldata 0.2.0. nlme ships with R itself, so nothing needs installing; lme4's lmer() uses different syntax but gives the same fit.

Direction one: the BETWEEN-subject standard error comes out too small

Start with the simplest question. How much lower is the sore-throat score in the licorice arm?

The naive approach throws all 932 rows into lm(). The point estimate is -0.582 points (lower under licorice), with a standard error of 0.0686, t = -8.48, p < 0.001, on 930 residual degrees of freedom.

The mixed model gives exactly the same point estimate, but a standard error of 0.1113, t = -5.23, p < 0.001, and the degrees of freedom for treat drop to 231.

The naive standard error is 38.3% smaller than the correct one.

Two bar panels side by side sharing one vertical axis (standard error, 0 to 0.20). The left panel, between-subject treatment effect, has three bars: naive lm is the shortest at 0.0686, while cluster-robust (0.1115) and the mixed model (0.1113) are almost the same height, roughly 62% taller than the naive bar. The right panel, within-subject time contrasts, has three groups of three bars; in every group the naive lm bar is the tallest (0.137) and the mixed-model bar is 0.092, clearly shorter than naive — the opposite direction from the left panel. The cluster-robust bars vary a lot between the three groups on the right, and in the first group (PACU 90 min) the cluster-robust bar is even shorter than the mixed-model one.
One dataset, one clustering structure. On the left the between-subject standard error is understated; on the right the within-subject ones are overstated. The two errors point in opposite directions.Plotting script figures/scripts/B2-07-clustered.R

Direction two: the WITHIN-subject standard errors come out too large

Most textbooks stop after the previous section, which leaves a rule that is easy to misremember: “ignoring clustering makes standard errors too small.” That sentence is only half true, and the half it omits is the more useful one.

Refit as pain ~ factor(time) * treat and look at the contrasts between time points:

TermKindEstimateNaive SECluster-robust SEMixed-model SEMixed / naive
Baseline: control at PACU 30 minintercept1.0260.0970.1440.0971.000
PACU 90 min vs PACU 30 minwithin-subject (time)-0.2070.1370.0640.0920.673
4 h post-op vs PACU 30 minwithin-subject (time)-0.1120.1370.1330.0920.673
POD 1 morning vs PACU 30 minwithin-subject (time)-0.3790.1370.1270.0920.673
Licorice vs control at PACU 30 minbetween-subject-0.7520.1370.1570.1371.000
Treatment x PACU 90 minwithin-subject (time x treat)0.0700.1940.0760.1300.673
Treatment x 4 h post-opwithin-subject (time x treat)0.1890.1940.1590.1300.673
Treatment x POD 1 morningwithin-subject (time x treat)0.4220.1940.1550.1300.673

The last column says what happened. The ratio is 1 for the intercept and for treat — the mixed model and the naive model return identical standard errors there, because in this interaction model treat is the between-subject contrast at the PACU 30 min time point alone, where each patient contributes exactly one row and clustering has nothing to act on. For every other row the ratio is 0.673 — the mixed-model standard error is 32.7% smaller than the naive one.

What the mixed model is doing

lme(pain ~ treat, random = ~ 1 | patient) adds one term: each patient gets his own intercept bib_i, and those bib_i are assumed to be drawn from a normal distribution with mean zero. The model becomes

yij=β0+β1treati+bi+εij,biN(0,σb2),εijN(0,σe2)y_{ij} = \beta_0 + \beta_1 \, \text{treat}_i + b_i + \varepsilon_{ij}, \qquad b_i \sim N(0, \sigma^2_b), \quad \varepsilon_{ij} \sim N(0, \sigma^2_e)

bib_i is a random effect: it is not a parameter to be estimated but a distribution to be estimated. That is what separates it from treating the patient id as a fixed-effect factor with 233 levels — the latter would burn 232 degrees of freedom, and would swallow the between-subject effect entirely, since treat is constant within a patient and therefore perfectly collinear with the patient id.

That standard error is just “average each patient, then compare”

Collapse each patient’s four scores to a single mean, which leaves 233 rows, and run the most ordinary two-sample comparison there is. The standard error is 0.1113 — equal to the mixed model’s 0.1113 to nine decimal places. The two differ by 2.4e-10, which is the REML optimiser’s convergence tolerance, not a difference between the estimators.

ICC: how much of the variation is “people differ”

The mixed model splits the variation in two. The between-patient variance is 0.5947 and the within-patient variance is 0.5068. The intraclass correlation coefficient (ICC) is the first as a share of the total:

ICC=σb2σb2+σe2\mathrm{ICC} = \frac{\sigma^2_b}{\sigma^2_b + \sigma^2_e}

which comes to 0.540.

There is a qualifier here that is easy to drop. Those two variances come from lme(pain ~ treat, random = ~1 | patient), a model that already contains treat, so what they partition is the variation that remains once the group difference is taken out, not the total variation in the raw scores. The correct reading is: within a single arm, the differences between patients are slightly larger than one patient’s fluctuation over time (0.540 against 0.460). The qualifier carries weight here, because 0.540 is only just above one half and a different model specification could put it on the other side. Always report which model, and which variance decomposition, an ICC came from.

The same formula has a second use, and it is the one most papers mean by “ICC = 0.85”. The ICC on this page asks how alike two people in the same cluster are — it measures structure. The reliability ICC asks how alike two measurements of the same subject are — it measures the instrument or the rater. The variance decomposition is identical; the question is not, and the reliability side splits further into six forms (single vs average measurement, consistency vs absolute agreement, raters treated as random vs fixed), none of which can be interpreted without being named. See measurement reliability and the ICC.

An ICC can equally be read as the correlation between any two measurements on the same patient; under a random-intercept model those are the same statement.

Design effect: turning an ICC into “how much sample was wasted”

Sample size and power notes that cluster-randomised trials must be inflated by a design effect 1+(m1)×ICC1 + (m-1)\times \mathrm{ICC}, where mm is the number of individuals per cluster. On this page the “cluster” is the patient, and mm is the number of measurements per patient, 4.

That gives a design effect of 2.620, so the 932 rows are worth roughly 356 independent observations for the between-subject comparison.

Read that number in both directions, or it looks like pure loss. Downward, 932 rows shrink to 356, which is the price of treating repeated measurements as independent. Upward, 356 is more than the 233 patients, and that surplus is exactly the point made in the previous section: repeated measurement did buy something, it just has a ceiling.

Mixed models, GEE and cluster-robust: three different questions

There are three mainstream routes for handling clustering — a mixed model, GEE (generalised estimating equations) and cluster-robust standard errors. They are not three algorithms for the same thing; they answer three different questions. This is the section most often skipped and most often misused.

ApproachHow the clustering is usedWhat effect it estimatesBetween-subject SE here
Naive lm()Ignored entirelyMarginal, but with the wrong variance0.0686
Cluster-robust (sandwich) SEOnly in the variance; the point estimate stays OLSMarginal (population-average)0.1115
GEE (exchangeable working correlation)In the variance and in the weighting of the estimating equationMarginal (population-average)Same order as cluster-robust
Mixed-effects model (random intercept)Written into the model itselfConditional (subject-specific)0.1113

The conditional-versus-marginal distinction, in one question each:

  • The mixed model’s coefficient answers “if this same person had been in the other arm, how different would his score be?” — it is defined holding that patient’s random intercept bib_i fixed.
  • The GEE and cluster-robust coefficients answer “if the whole population switched to licorice, how much would the average score change?”

In the linear model on this page the two have the same point estimate (-0.582), so the distinction is invisible. That is a special property of linear models. Once the effect measure is non-collapsible — the odds ratio above all — conditional and marginal effects differ numerically, and the conditional OR is always further from 1; this is the non-collapsibility discussed on logistic regression. Not every non-linear link behaves this way: the log link is collapsible, so a Poisson mixed model and a Poisson GEE estimate the same rate ratio and differ only in the intercept. On one dataset a mixed logistic model and a GEE will report different-sized ORs; both are correct, and they answer different questions.

Choosing between them:

  • To say “what would happen to this patient on treatment” (clinical decisions, individual prediction) → mixed model
  • To say “what would happen if this policy went population-wide” (public health, policy evaluation) → GEE or cluster-robust
  • When the clustering is a nuisance rather than the object of interest (centre effects in a multicentre trial, say) → cluster-robust is the least work, because it does not require you to guess the correlation structure correctly

Cluster-robust is not “multiply by a fixed factor”

In the table above, the cluster-robust column is worth a look on its own. For the between-subject effect the cluster-robust standard error 0.1115 and the mixed model’s 0.1113 very nearly coincide. But the three time-point contrasts have cluster-robust standard errors of 0.064, 0.133 and 0.127 — very different from one another, and the first (PACU 90 min versus PACU 30 min) is even smaller than the mixed model’s 0.092.

The reason is that a sandwich estimator imposes no correlation structure at all. The random-intercept model assumes any two measurements on a patient are equally correlated (exchangeable), so every within-subject contrast shares the one correction factor 0.673. The sandwich estimates each contrast’s actual variance from the residuals, so contrasts between adjacent, strongly correlated time points come out more precise and distant ones less so.

Common misuses

MisuseWhy it is wrong
Feeding repeated-measures data straight into lm() / glm()The between-subject SE comes out too small; degrees of freedom are the fastest tell
Remembering it as “ignoring clustering always makes SEs too small”Within-subject contrasts run the other way and come out too large
Plotting only the mean trajectories, never the individual linesThe reader cannot judge how large the variation is, or whether a few lines are dragging the mean
Treating patient id as a fixed-effect factorBurns a large number of degrees of freedom, and the between-subject effect is collinear with it and inestimable
Comparing a mixed model’s OR with a GEE’s OR by sizeOne is conditional and one is marginal; under a non-collapsible link such as the logit they differ by construction
Applying cluster-robust SEs with very few clustersThe sandwich approximates using the number of clusters; too few and it understates the variance
Applying the design effect to within-subject contrastsRepetition is a gain there, not a loss
Fitting a model before looking at the missingness patternBalanced and unbalanced data behave differently; some shortcuts are equivalent only under balance
Using “average each patient” as a substitute for a mixed modelEquivalent only under exact balance; otherwise it weights patients wrongly
Not reporting the ICCReaders cannot judge how severe the clustering is, and later studies cannot use it for sample size
Assuming a random intercept is the whole jobIf the effect itself varies between people (different time trends, say), a random slope is needed
Crediting a smaller p value to “using a better model”Say instead that the within-subject contrast recovered variation the naive model had charged to error

Reproducing every number on this page

/opt/homebrew/bin/Rscript figures/scripts/B2-07-clustered.R

Read the figure

The answer comes from the same statistical output that produced this page's figures, not from a number typed in beside them.

Treating all 932 rows as independent gives a standard error of 0.069 for the treatment effect. What does the random-intercept model's standard error show?

Show the answer and why

Correct answer: 0.111 - about sixty percent larger than the naive one, so repeated measures carry less information than the row count implies

The mixed model gives 0.111 against the naive 0.069. One patient's four measurements are strongly correlated, so together they carry far less information than four independent observations - the naive calculation treats the two as equivalent, understating the standard error, narrowing the interval and shrinking the p-value, while the point estimate is identical in all three, so nothing in that column looks wrong. 0.138 is the standard error had each patient been measured once: the mixed model does not fall that far, because the repeats do contribute, just not as much as the row count suggests.

The ICC is 0.540, each patient is measured four times, and there are 932 rows. Which number converts that into an effective number of independent observations?

Show the answer and why

Correct answer: Divide the row count by the design effect, 2.62

The design effect is 2.62, one plus (measurements minus one) times the ICC; dividing 932 by it leaves an effective sample in the three hundreds. 0.54 is the ICC itself, a strength of correlation rather than a discount factor; 4.00 is the number of measurements, and dividing by it outright would assume a patient's four measurements are literally identical, which is the opposite extreme. This is why "nearly a thousand observations" is a sentence that misleads the person saying it in a repeated-measures study.

Of 233 patients, 122 score exactly the same at all four time points. How does that bear on the ICC?

Show the answer and why

Correct answer: 122 patients have zero within-person variance, so between-person differences make up most of the total

The ICC is the share of total variance that lies between people, and more than half the patients never move, contributing zero within-person variance - with that piece missing from the denominator the share is bound to be high. 120 is how many scored zero at every visit, a subset of the first group: a flat trajectory at any value zeroes the within-person variance, and it need not be at zero. 233 is simply how many patients were analysed; sample size on its own does not move the ICC.

Sources and licences

This page is original writing

Report a content problem

The statistics on this site are written by AI and reviewed by AI; a human only spot-checks. What you can see may be what we cannot.

The more specific, the more fixable — e.g. which sentence disagrees with which textbook or paper.

Needed only if you want a reply; reports without it are still read.

Sent along with your report

These are attached automatically. You can drop any of them.