← Methods repository
concept

Cluster-Randomized Trial

An experimental design in which intact groups (clinics, practices, hospitals, communities) rather than individuals are randomly assigned to study arms, so that allocation is at the cluster level while outcomes are usually measured on individuals within clusters, inducing within-cluster outcome correlation that must be accounted for in both sample size and analysis.

Study_Designcluster-randomizationgroup-randomizedpragmatic-trialintracluster-correlationdesign-effectgeemixed-effectsrecruitment-bias
Methods reference only. Use primary source citations and local policy before applying this in a study protocol, regulatory submission, payer dossier, or clinical decision.

In plain language

A cluster-randomized trial assigns whole groups — such as clinics, hospital wards, or communities — to an intervention or to usual care, rather than assigning individual patients. Researchers then measure outcomes on the patients inside those groups. This design is used when the intervention is delivered to an entire group at once (for example, training all providers at a clinic), so you cannot give it to some patients but not others in the same setting. The catch is that patients at the same clinic tend to look more alike than patients drawn randomly from everywhere, and that similarity must be accounted for when calculating how many patients you need and when analyzing the results.

A cluster-randomized trial (CRT) — also called a group-randomized or cluster-randomised trial — randomizes intact groups (primary-care practices, hospital wards, dialysis units, nursing homes, geographic communities) to intervention or control, then ascertains outcomes on the individuals who belong to those groups. The defining feature is a mismatch between the unit of randomization (the cluster) and the unit of observation/analysis (the individual). Because people within a cluster share clinicians, protocols, local case-mix, and environment, their outcomes are positively correlated. That correlation, summarized by the intracluster correlation coefficient (ICC, ρ), is the single fact that governs everything downstream: it shrinks the effective sample size, inflates variance, and makes the naïve "treat every patient as independent" analysis anticonservative (too-narrow confidence intervals, inflated type-I error). In RWE, CRTs most often appear as pragmatic trials embedded in routine care — randomize clinics to a clinical-decision-support (CDS) alert, a care-pathway change, or an outreach program, and measure effectiveness using EHR or claims outcomes already being captured.

Core conceptual distinction (vs individually randomized trials)

An individually randomized trial balances confounders in expectation at the person level and yields independent observations. A CRT randomizes a handful of units — sometimes 6, 10, 20 clusters — so chance imbalance between arms is far more likely, and the observations are not independent. Two estimands must be kept straight. The cluster-level estimand treats each cluster as one data point (e.g., the mean of cluster-specific rates), is robust with few clusters, and weights clusters equally. The individual-level (population-average or cluster-specific) estimand uses every patient but must model the correlation — via generalized estimating equations (GEE, population-average) or a generalized linear mixed model (GLMM, cluster-specific/conditional). With a binary outcome and a non-identity link these two individual-level estimands are not equal (the marginal GEE odds ratio is attenuated relative to the conditional GLMM odds ratio); stating which you report is mandatory.

The design effect is not optional arithmetic

The variance inflation from clustering is the design effect, DEFF = 1 + (m̄ − 1)·ρ, where m̄ is the average cluster size. A trial that would need N individuals under simple randomization needs N·DEFF individuals under cluster randomization. With m̄ = 50 and a modest ρ = 0.02, DEFF ≈ 1.98 — the study needs roughly twice the patients. When cluster sizes vary, the effective DEFF rises further; Eldridge et al. showed it becomes 1 + ((1 + CV²)·m̄ − 1)·ρ, where CV is the coefficient of variation of cluster size. Powering a CRT with an individually-randomized sample-size formula is a classic, fatal error: the trial is underpowered before it enrolls a single patient.

Pros, cons, and trade-offs

- vs the individually randomized trial (RCT): CRTs are the right (often only) choice when the intervention is delivered to a group and cannot be withheld from individuals in the same setting — a clinician trained in a new protocol cannot un-know it for half their panel (treatment contamination), and ward-level infection-control or community health-promotion interventions are inherently group-level. CRTs also ease logistics (train one site, not one patient at a time) and reduce contamination. Cost: dramatically lower statistical efficiency (the design effect), far greater vulnerability to chance imbalance and to identification/recruitment bias (see below), and more complex analysis. Prefer individual randomization whenever contamination is implausible and individuals can be consented and randomized independently — it is strictly more efficient. - vs the stepped-wedge CRT: A parallel CRT randomizes clusters to fixed arms for the whole study. A stepped-wedge design rolls the intervention out to all clusters in randomized sequence, so every cluster eventually crosses over; it suits one-directional rollouts, gives every site the intervention (often required for adoption/ethics), and uses within-cluster contrasts. Cost: confounding of the treatment effect with secular time trends, a more demanding mixed model, and sensitivity to how the time effect is specified. Prefer parallel CRT for a clean concurrent contrast; prefer stepped-wedge when a phased rollout is unavoidable or when all clusters must receive the intervention. - vs observational comparative-effectiveness (e.g., active-comparator new-user) in the same RWD: randomization at the cluster level removes confounding by assignment (no confounding-by-indication, no healthy-user bias) — the core advantage over any observational design. Cost: you randomize few units, accept the design effect, and often cannot blind; an observational ACNU/PS analysis on the full database may have far more power and external validity for a patient-level drug-vs-drug question. Prefer a CRT for system/provider-level interventions; prefer observational CER for individual-level drug choices where assignment can be modeled. - vs target-trial emulation: a CRT is a trial, so it needs no emulation; but a well-specified CRT protocol is exactly the target trial that an observational study of a system-level intervention would try to emulate.

When to use

The intervention acts at the group level (provider training, CDS/EHR alerts, care pathways, ward protocols, community programs); individual randomization would cause contamination or is logistically impossible; and you can recruit/enumerate participants before clusters are revealed to be intervention or control. Pragmatic, embedded CRTs that read endpoints from routine EHR/claims data are a natural RWE application and are explicitly recognized in regulatory real-world-evidence and pragmatic-trial guidance.

When NOT to use — and when it is actively misleading or dangerous

- Few clusters. With fewer than ~15–20 clusters per arm, GEE and model-based GLMM standard errors are biased downward — confidence intervals too narrow, type-I error inflated. If you must use few clusters, switch to a cluster-level summary analysis (a t-test on cluster means) or apply a small-sample correction (Mancl–DeRouen / Kauermann–Carroll for GEE; Satterthwaite/Kenward–Roger denominator df for mixed models). A "significant" individual- level GEE result from 8 clusters is often an artifact, not an effect. - Post-randomization recruitment with knowledge of allocation (identification/recruitment bias). This is the signature CRT failure. If patients are enrolled after a cluster is known to be intervention vs control, recruiters (or patients) behave differently by arm — sicker patients are preferentially enrolled in the intervention clinic, healthier ones in control — and the arms are no longer comparable despite "randomization." Puffer et al. documented this in published CRTs. The fix is structural: identify and consent the cohort, or define the closed population, before allocation is disclosed; if outcomes come from a fixed, pre-existing roster (a true RWE strength), this bias is largely defused. - Ignoring clustering in the analysis. Running ordinary logistic/Cox/linear regression on individual rows as if independent is not conservative — it is wrong in the dangerous direction, manufacturing false precision. - Adjusting for post-randomization, cluster-level variables that are affected by the intervention re-introduces confounding and can reverse the sign of the effect; baseline-only, pre-randomization adjustment is the safe rule. - An intervention with no plausible group-level mechanism gains nothing from cluster randomization and simply pays the design-effect penalty for no reason — use individual randomization.

Data-source operational depth (RWE / routinely-collected data)

- Claims: Strong for hard, well-coded endpoints (hospitalization, ED visits, dispensings, death via linkage) on a closed, enumerable denominator — ideal for an embedded CRT where practices/health-plan regions are randomized and outcomes are read from claims. Failure modes: the cluster (e.g., a practice) must be unambiguously linkable to the plan's members and stable over follow-up; member churn / disenrollment silently changes cluster composition and cluster size (CV inflation in the design effect) — require continuous enrollment across the measurement window. Medicare Advantage encounter data are incomplete vs fee-for-service claims, so a cluster's apparent event rate can reflect MA penetration, not the intervention; restrict to a consistent benefit type or model it. Attribution of a patient to exactly one cluster (which practice "owns" a patient seen at several) must be defined a priori. - EHR: Best for the intervention itself (the CDS alert, order set, problem list) and for clinical granularity (labs, vitals, BP, HbA1c) needed for both outcomes and ICC estimation. Failure modes: visit-driven capture means a patient who stops visiting an intervention clinic is differentially lost; the ICC is often larger in EHR data because shared clinicians and local documentation habits cluster outcomes more tightly — using a too-small ICC from a different setting under-powers the trial. Cross-coverage and patients seen at multiple sites blur cluster membership. - Registry: Useful when the cluster is a center already contributing to a disease registry (adjudicated outcomes, disease severity); typically weak for complete medication exposure — link to claims for fills and to a death index for censoring. Centers that join/leave the registry change the cluster set mid-study. - Linked claims–EHR–vital records: The ideal embedded-CRT substrate — EHR captures the intervention and severity, claims complete the utilization picture, vital records fix mortality. Cost: linkage selects the linkable subset (potential generalizability loss) and introduces order/fill/service-date discrepancies; reconcile dates before defining the outcome window, and confirm linkage rates are balanced across arms.

Worked claims/EHR example

Question: does a practice-level EHR clinical-decision-support alert that flags overdue statin therapy reduce 12-month cardiovascular hospitalization among adults with type 2 diabetes, evaluated as a pragmatic CRT in a claims-linked EHR network? (1) Unit of randomization = the practice (say 24 practices, 12 per arm); unit of analysis = the patient. (2) Define the closed cohort before allocation is revealed: adults ≥40 with ≥2 diabetes diagnoses and ≥365 days of continuous enrollment ending at the index quarter, attributed to exactly one practice by plurality of primary-care visits in the prior year — enumerate this roster first to prevent identification bias. (3) Randomize the 24 practices, ideally with restricted/covariate-constrained randomization on baseline practice-level statin rate and panel size to curb chance imbalance with few clusters. (4) Outcome: first CV hospitalization (inpatient claim with a qualifying primary diagnosis) over the 12 months after activation; censor at disenrollment, death, or data end. (5) Power the trial with the design effect: with m̄ ≈ 300 patients per practice and an EHR-plausible ICC ρ = 0.01, DEFF = 1 + (300 − 1)·0.01 ≈ 4.0 — the effective sample size is one quarter of the head count, and unequal practice sizes (CV of cluster size) push it higher. (6) Analysis: report a pre-specified primary estimand — a population-average risk difference via GEE with an exchangeable working correlation and cluster-robust (sandwich) variance with a small-sample correction given only 24 clusters, or a cluster-level comparison of practice-specific rates as the robust primary, with the patient-level GLMM as secondary. Adjust only for baseline, pre-randomization covariates (age, sex, prior CV history, baseline statin use). (7) Sensitivity: re-estimate ICC from the observed data, vary the cluster-attribution rule, and restrict to a single benefit type to rule out MA encounter-completeness artifacts.

Worked example

Scenario

A health system wants to test whether placing an automated reminder in the clinic electronic health record reduces 90-day hospital readmission among adults with heart failure. They cannot give the reminder to only some patients at a clinic because every provider at that clinic sees it. So they randomize six clinics as whole units: three get the reminder turned on (intervention), three do not (control). All heart-failure patients at each clinic are followed for 90 days and their readmission status is recorded.

Dataset

Each row is one clinic. Patients are nested inside their clinic and cannot move between groups.

clinic_idarmpatients_nreadmissions_nreadmission_rate
Clinic AIntervention20315.0%
Clinic BIntervention25416.0%
Clinic CIntervention15213.3%
Clinic DControl20735.0%
Clinic EControl25832.0%
Clinic FControl15533.3%

Steps

  • Because whole clinics were randomized, the correct comparison starts at the clinic level. Compute each clinic's readmission rate (readmissions divided by patients): Clinic A = 3/20 = 15.0%, B = 4/25 = 16.0%, C = 2/15 = 13.3%, D = 7/20 = 35.0%, E = 8/25 = 32.0%, F = 5/15 = 33.3%.

  • Average the three intervention clinic rates: (15.0 + 16.0 + 13.3) / 3 = 14.8%. Average the three control clinic rates: (35.0 + 32.0 + 33.3) / 3 = 33.4%. The cluster-level risk difference is 14.8% minus 33.4% = -18.6 percentage points.

  • Now ask: did the sample size calculation account for within-clinic correlation? Patients at the same clinic share a care team, documentation habits, and local case mix, so their outcomes are more alike than two patients from different clinics. The ICC captures that similarity.

  • Calculate the design effect: average cluster size m = 120 patients divided by 6 clinics = 20 patients per clinic. With an ICC of 0.05, design effect = 1 + (20 - 1) x 0.05 = 1 + 0.95 = 1.95. The trial effectively has only about half the statistical information of a 120-patient individually randomized trial.

  • If the sample size was calculated assuming independent individuals (no clustering), the trial is underpowered by roughly a factor of 2.0 before a single patient was enrolled. This is the classic error in cluster-randomized trials.

Result

Intervention clinics averaged a 14.8% readmission rate versus 33.4% in control clinics, a cluster-level risk difference of -18.6 percentage points. However, with only 3 clinics per arm and a design effect of 1.95 (ICC 0.05, 20 patients per clinic), the effective sample is roughly 62 independent observations rather than 120 — the confidence interval around that difference is wide, and any significance test must use cluster-level or clustering-adjusted methods, not a simple chi-square on pooled patient counts.

Runnable example

python implementation

Sample-size and clustered-analysis core for a CRT with a binary outcome. Two required inputs: design params : average cluster size (m_bar), ICC (rho), coefficient of variation of cluster size (cv), and the simple-randomization N from a standard...

import numpy as np
import pandas as pd
import statsmodels.api as sm
import statsmodels.formula.api as smf

# ---- Step 1: required sample size under cluster randomization -------------------------
def crt_sample_size(n_simple: int, m_bar: float, rho: float, cv: float = 0.0):
    """Inflate a simple-randomization individual N by the (variable cluster size) design effect.
    DEFF = 1 + ((1 + cv**2) * m_bar - 1) * rho   (cv=0 -> classic 1 + (m_bar - 1)*rho)."""
    deff = 1.0 + ((1.0 + cv ** 2) * m_bar - 1.0) * rho
    n_individuals = int(np.ceil(n_simple * deff))
    n_clusters = int(np.ceil(n_individuals / m_bar))
    return {"deff": deff, "n_individuals": n_individuals, "n_clusters": n_clusters}

# Example: 788 needed under simple randomization, mean 300/practice, ICC 0.01, CV 0.6.
print(crt_sample_size(n_simple=788, m_bar=300, rho=0.01, cv=0.6))

# ---- Step 2: individual-level population-average estimand via GEE ---------------------
# df columns: outcome (0/1), arm (0/1), cluster_id, and baseline covariates only.
def fit_gee(df: pd.DataFrame, covars: list[str]) -> sm.GEE:
    rhs = " + ".join(["arm"] + covars)
    model = smf.gee(
        f"outcome ~ {rhs}", groups="cluster_id", data=df,
        family=sm.families.Binomial(),                 # logit link -> marginal OR
        cov_struct=sm.cov_struct.Exchangeable(),       # one within-cluster correlation
    )
    # cov_type='bias_reduced' applies the Kauermann-Carroll small-sample sandwich correction,
    # essential when the number of clusters is small (anticonservative otherwise).
    return model.fit(cov_type="bias_reduced")

# ---- Step 3: robust cluster-level summary analysis (few clusters) ---------------------
def cluster_level_test(df: pd.DataFrame):
    """Reduce each cluster to its event rate, then compare arm means (Welch t-test)."""
    from scipy import stats
    rates = df.groupby(["cluster_id", "arm"])["outcome"].mean().reset_index()
    a = rates.loc[rates["arm"] == 1, "outcome"]
    b = rates.loc[rates["arm"] == 0, "outcome"]
    t, p = stats.ttest_ind(a, b, equal_var=False)
    return {"risk_diff_cluster_means": a.mean() - b.mean(), "t": t, "p": p}
r implementation

CRT sample size and analysis in R. Inputs mirror the Python version: patient data.frame: person_id, cluster_id, arm (0/1), outcome (0/1), baseline covariates. Uses geepack for the population-average GEE and lme4 for the cluster-specific GLMM; the...

library(geepack)
library(lme4)

## ---- Sample size: variable-cluster-size design effect (Eldridge 2006) ----------------
crt_sample_size <- function(n_simple, m_bar, rho, cv = 0) {
  deff <- 1 + ((1 + cv^2) * m_bar - 1) * rho
  n_ind <- ceiling(n_simple * deff)
  list(deff = deff, n_individuals = n_ind, n_clusters = ceiling(n_ind / m_bar))
}
crt_sample_size(n_simple = 788, m_bar = 300, rho = 0.01, cv = 0.6)

## ---- Population-average (marginal) estimand: GEE with exchangeable correlation --------
## geeglm uses the cluster-robust sandwich variance by default; cluster_id MUST be a factor
## and rows sorted within cluster.
dat <- dat[order(dat$cluster_id), ]
dat$cluster_id <- factor(dat$cluster_id)
fit_gee <- geeglm(outcome ~ arm + age + prior_cvd + baseline_statin,
                  id = cluster_id, data = dat,
                  family = binomial("logit"), corstr = "exchangeable")
summary(fit_gee)   # arm coefficient = marginal log-OR; SE is sandwich-based

## ---- Cluster-specific (conditional) estimand: random-intercept GLMM -------------------
fit_glmm <- glmer(outcome ~ arm + age + prior_cvd + baseline_statin + (1 | cluster_id),
                  data = dat, family = binomial("logit"))
## ICC on the latent scale: tau2 / (tau2 + pi^2/3)
tau2 <- as.numeric(VarCorr(fit_glmm)$cluster_id)
icc  <- tau2 / (tau2 + pi^2 / 3)

## ---- Robust cluster-level summary t-test (few clusters) ------------------------------
rates <- aggregate(outcome ~ cluster_id + arm, data = dat, FUN = mean)
t.test(outcome ~ arm, data = rates, var.equal = FALSE)