← Methods repository
concept

Regression Discontinuity Design

A quasi-experimental design that estimates a local causal effect at a known assignment threshold on a continuous running variable, comparing units just above and just below the cutoff where treatment status changes discontinuously but other determinants of the outcome vary smoothly.

Causal_Inference_Methodregression-discontinuityrunning-variablelocal-linear-regressionbandwidth-selectionmccrary-density-testsharp-and-fuzzylocal-average-treatment-effectquasi-experiment
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

Regression discontinuity design (RDD) is a method for estimating a causal treatment effect when patients are assigned to treatment based on whether a continuous measurement crosses a fixed threshold. The core idea is that patients just barely above the threshold and patients just barely below it are nearly identical in every way except their treatment status, so comparing their outcomes is close to a randomized experiment. For example, if guidelines say to prescribe a drug when LDL cholesterol reaches 190 mg/dL, a patient measured at 191 is almost the same person as one measured at 189 — the small gap in their LDL values is essentially random, so any jump in health outcomes right at that 190 cutoff can be attributed to the treatment rather than to pre-existing differences between the groups.

A regression discontinuity design (RDD) identifies a causal effect from a deterministic (sharp) or probabilistic (fuzzy) rule that assigns treatment when a continuous running variable (also called the forcing or assignment variable) crosses a known cutoff c. Healthcare examples are abundant because eligibility and clinical action are routinely threshold-driven: an age cutoff for screening recommendations or Medicare eligibility (65), a risk-score or eligibility-score threshold for a disease-management program, a lab-value threshold that triggers treatment (HbA1c, eGFR, LDL, gestational age, APGAR/birthweight cutoffs). The core identifying assumption is continuity of potential outcomes at the cutoff: absent the treatment rule, the expected outcome would be a smooth function of the running variable through c, so units just below the cutoff are a valid counterfactual for units just above. The estimand is the local average treatment effect at the cutoff (the LATE for units at X = c), computed as the jump in the conditional expectation of the outcome at c: τ = lim(x→c+) E[Y|X=x] − lim(x→c−) E[Y|X=x] for the sharp design. RDD is widely regarded as the quasi-experiment with the strongest internal validity short of randomization, because near the cutoff the only thing that changes discontinuously is treatment status — confounders are, by construction, continuous through c.

Core conceptual distinction

Three things must be specified and they are separable. (1) Sharp vs fuzzy: in a sharp RDD crossing the cutoff changes treatment with probability 1 (the rule is deterministic, e.g., automatic enrollment at age 65); in a fuzzy RDD the cutoff changes only the probability of treatment (a guideline threshold that clinicians follow imperfectly), and the effect is the jump in outcome divided by the jump in treatment probability — algebraically a Wald instrumental-variables estimator where "above the cutoff" is the instrument. (2) Estimation near the cutoff: the modern standard is local linear (or local polynomial) regression within a data-driven bandwidth h around c, fit separately on each side, rather than a global high-order polynomial over the whole range (which Gelman and Imbens show produces noisy, overfit, misleading estimates). Bandwidth selection (e.g., the Calonico-Cattaneo-Titiunik MSE-optimal bandwidth with robust bias-corrected inference) is the central tuning decision, and results must be shown across a sensible range of bandwidths. (3) Validation: because the entire design rests on no one being able to precisely position themselves relative to the cutoff, the McCrary density test (a discontinuity in the density of the running variable at c) screens for manipulation/sorting, and covariates measured pre-treatment should show no discontinuity at c (a placebo/balance check) — if they jump, the continuity assumption is violated.

Pros, cons, and trade-offs

- vs instrumental variables (`instrumental-variables-pharmacoepi-rwe`): A fuzzy RDD is an IV using the cutoff as the instrument, with unusually transparent and defensible instrument validity (the threshold is institutionally fixed and its relevance is visible as a first-stage jump in treatment probability). General IV (e.g., physician prescribing preference, distance to facility) buys a population-level effect but rests on harder-to-verify exclusion restrictions. Prefer RDD when a genuine threshold rule exists, because the instrument's validity is so much easier to argue and test; prefer general IV when no threshold exists but a credible instrument does, and when an effect away from a single cutoff is needed. - vs difference-in-differences (`difference-in-differences-staggered-adoption-rwe`): RDD exploits a cross-sectional threshold and needs no pre/post panel or parallel-trends assumption; DiD exploits timing and a comparison group. Prefer RDD when assignment is threshold-driven at a point in time; prefer DiD when an intervention turns on at a date and a parallel comparison group exists. - vs target trial emulation / PS designs (`target-trial-emulation`, `propensity-score-methods-psm-iptw`): PS/target-trial methods estimate an average effect over the whole confounder-balanced population but require measuring the confounders; RDD needs no confounder measurement at all near the cutoff but pays for it with an effect that is local to the threshold and not necessarily generalizable to units far from c, plus a steep cost in statistical efficiency (only units near c carry information, so power is low and large samples are required). Prefer PS/target-trial when external validity across the full population matters and confounders are well measured; prefer RDD when unmeasured confounding is the dominant threat and a clean threshold rule exists.

When to use

A continuous running variable with a known, externally fixed cutoff that drives treatment (age-based eligibility, a risk/eligibility score, a lab or clinical threshold); enough observations near the cutoff to fit local regressions with usable precision; a plausible argument that units cannot precisely manipulate their position relative to c; a setting where unmeasured confounding makes covariate-adjustment designs unconvincing. RDD is especially valuable for evaluating coverage/eligibility policies and threshold-based clinical guidelines where randomization is impossible.

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

- The running variable can be manipulated. If patients, clinicians, or coders can nudge a value across the cutoff to obtain (or avoid) treatment — rounding a lab to qualify, mis-dating to clear an age threshold — units sort around c, the density jumps (McCrary test fails), and the estimate is confounded by who chose which side. This is the most dangerous RDD failure and a failed density test should halt the analysis. - No true discontinuity in treatment. If crossing the cutoff does not actually change treatment status or probability (a guideline nobody follows), the first stage is flat and a fuzzy-RDD estimate explodes from dividing by a near-zero denominator. Verify and report the first-stage jump. - Other things change at the same cutoff. If a different program or rule shares the threshold (turning 65 changes both Medicare eligibility and the program under study), the jump conflates them; the effect is not attributable to the studied treatment. Check that covariates and competing policies are continuous at c. - Effect extrapolated away from the cutoff. The RDD estimate is local to X = c. Reporting it as the average effect for the whole population — including those far from the threshold where the effect may differ — overstates external validity. - A global high-order polynomial is used. Fitting a quartic/quintic over the full range manufactures spurious discontinuities at the boundary (Gelman-Imbens); use local linear/quadratic within a data-driven bandwidth instead.

Data-source operational depth

- Claims (FFS vs MA): The running variable is often age (clean, from enrollment files) or a constructed risk/eligibility score; the treatment is an enrollment, coverage, or service indicator that switches at the cutoff. A standing failure mode at the age-65 Medicare threshold: cohort composition changes because people shift from commercial to Medicare coverage at exactly 65, so the observed population and its data capture change discontinuously — restrict to a consistent, continuously observable population (or model the coverage transition explicitly) so the outcome jump is not a data-capture artifact. Lab-threshold RDDs require the lab value itself, which fee-for-service claims usually lack; these need linked EHR/lab data. - EHR: Best substrate for lab/clinical-threshold RDDs because the running variable (HbA1c, eGFR, blood pressure) is recorded directly. But values are measured with error and may be re-tested when near a clinical threshold (a borderline value triggers a repeat that crosses c), inducing exactly the manipulation/sorting RDD forbids — examine the density and test for heaping at round numbers, and consider the measured running variable's noise. - Registry / linked: Birth/perinatal registries provide near-canonical RDD running variables (gestational age, birthweight at NICU-admission thresholds) with adjudicated outcomes; linkage to claims supplies follow-up and cost outcomes. Watch for heaping at reported round values (e.g., birthweight at 1500 g, 2500 g) which biases the local fit.

Worked claims/linked example

Question: does initiating a lipid-lowering management program at a guideline LDL threshold of 190 mg/dL reduce 1-year cardiovascular hospitalization, using linked EHR-lab + claims data? (1) Running variable and cutoff: index LDL value X; cutoff c = 190 mg/dL; treatment = program enrollment, which clinicians follow imperfectly (a fuzzy RDD). (2) First stage: program enrollment probability jumps from ~0.20 just below 190 to ~0.65 just above — a visible, statistically significant discontinuity, confirming relevance. (3) Validation: the McCrary density test shows no discontinuity in the LDL distribution at 190 (p = 0.41), and pre-treatment covariates (age, prior CV history, baseline comorbidity index) are continuous through 190 — supporting the continuity assumption; a heaping check finds no excess mass at round LDL values near the cutoff. (4) Estimation: local linear regression on each side within the MSE-optimal bandwidth (h ≈ 22 mg/dL by Calonico-Cattaneo-Titiunik), with robust bias-corrected confidence intervals. The reduced-form outcome jump is −2.1 hospitalizations per 100 patients; dividing by the first-stage jump (0.45) gives a fuzzy-RDD local effect of −4.7 per 100 (95% robust CI −8.2 to −1.2) for compliers at the threshold. (5) Sensitivity: re-estimate across bandwidths (0.5h, h, 2h) and with local quadratic fits, confirm the effect is stable and not an artifact of bandwidth or polynomial order, and state clearly that the effect is local to LDL ≈ 190 and does not license claims about patients far from the cutoff.

Interpreting the output

Using the worked example: average hospitalization rate just below LDL 190 is 29.0 per 100 patients and just above is 24.0, giving a sharp-RDD discontinuity of 24.0 − 29.0 = −5.0 per 100. Adjusting for imperfect enrollment (fuzzy RDD) yields ≈ −11.1 per 100 enrollees at the threshold (−5.0 ÷ 0.45).

Formal interpretation: The RDD estimate of −5.0 hospitalizations per 100 patients (sharp design) is the local average treatment effect at LDL = 190 mg/dL — the causal effect of crossing the program eligibility threshold for patients whose LDL lands precisely at that cutoff. This estimate is local: it applies only to the threshold neighborhood, and extrapolating it to patients with LDL well above or below 190 is not supported by the design. In the fuzzy RDD, the ≈ −11.1 estimate is the LATE for program enrollees at the threshold, derived by dividing the reduced-form outcome jump by the jump in enrollment probability (≈ 0.45). The key identification assumption is that no other determinant of hospitalization risk jumps discontinuously at LDL 190 — tested by verifying smooth patient density (McCrary test) and smooth pre-determined covariates through the cutoff.

Practical interpretation: Patients just above the 190 mg/dL eligibility line who entered the lipid program had approximately 5 fewer cardiovascular hospitalizations per 100 patients per year than similar patients just below the line who did not qualify. This is a credible local causal estimate because the two groups are near-identical in every measured characteristic except which side of the threshold they fell on; the estimate does not speak to patients with much higher or lower LDL values.

Worked example

Scenario

A health plan wants to know whether a lipid-management program reduces cardiovascular hospitalizations. The program is offered when a patient's index LDL measurement is at or above 190 mg/dL. We look at patients whose LDL was measured within a narrow window of 10 mg/dL on either side of that cutoff (180-199 mg/dL) and compare 1-year hospitalization rates just below versus just above 190. Because those patients are nearly identical except for which side of the line they fell on, any jump in hospitalization rates at 190 estimates the program's causal effect.

Dataset

Observed 1-year cardiovascular hospitalization rates for patients near the LDL 190 mg/dL cutoff (synthetic illustration using proportions from the source file's worked example).

ldl_band_mg_dLside_of_cutoffn_patientshospitalizations_per_100
180-184below21030
185-189below19828
190-194above20525
195-199above19223

Steps

  • Average hospitalization rate just below the cutoff (bands 180-184 and 185-189): (30 + 28) / 2 = 29.0 per 100 patients.

  • Average hospitalization rate just above the cutoff (bands 190-194 and 195-199): (25 + 23) / 2 = 24.0 per 100 patients.

  • The discontinuity (jump) at the cutoff = 24.0 - 29.0 = -5.0 per 100 patients.

  • This -5.0 figure is the estimated causal effect: being on the treatment side of the 190 mg/dL line is associated with 5 fewer hospitalizations per 100 patients per year.

  • Because the program is not followed perfectly by every clinician (some patients above 190 are not enrolled; a few below 190 are enrolled anyway), this is a fuzzy RDD — the true per-program-enrollee effect is larger: the -5.0 jump in outcomes divided by the jump in enrollment probability (about 0.45, from 20% below to 65% above the cutoff) gives approximately -11.1 per 100 enrollees at the threshold.

Result

Reduced-form discontinuity: -5.0 hospitalizations per 100 patients (24.0 above minus 29.0 below). Fuzzy-RDD local effect for program enrollees at the threshold: -5.0 / 0.45 = approximately -11.1 per 100 enrollees. This effect is local to patients near LDL 190 and does not necessarily apply to patients with much higher or lower LDL values.

Runnable example

python implementation

Sharp and fuzzy RDD with the rdrobust package (Calonico, Cattaneo, Titiunik): MSE-optimal bandwidth, local linear estimation, and robust bias-corrected inference. rddensity supplies the McCrary-style manipulation (density) test. Inputs: the outcome y, the...

import numpy as np
from rdrobust import rdrobust          # local-poly RDD with robust bias-corrected CIs
from rddensity import rddensity        # manipulation (density) test at the cutoff

rng = np.random.default_rng(11)
n = 4000
x = rng.uniform(150, 230, n)           # running variable: index LDL (mg/dL)
c = 190.0                              # guideline cutoff
# Fuzzy assignment: probability of program enrollment jumps at the cutoff.
p = np.where(x >= c, 0.65, 0.20)
d = (rng.uniform(size=n) < p).astype(int)
# Smooth potential outcome + a true local treatment effect (-4.7 per 100 -> -0.047).
y = 0.30 - 0.0008 * (x - c) - 0.047 * d + rng.normal(0, 0.10, n)

# 1) Manipulation check: no discontinuity in the density of x at c.
dens = rddensity(X=x, c=c)
print("McCrary-type density test p:", dens.test["p_jk"])

# 2) Fuzzy RDD: supply the treatment vector `fuzzy=d`. Local linear (p=1), MSE-optimal bandwidth.
est = rdrobust(y=y, x=x, c=c, fuzzy=d, p=1)
print(est)   # Coef = local complier effect at the cutoff; CI is robust bias-corrected.

# 3) Sharp RDD reduced form (outcome jump) for comparison: omit `fuzzy`.
rf = rdrobust(y=y, x=x, c=c, p=1)
print("Reduced-form jump:", rf.coef.iloc[0])
r implementation

Sharp and fuzzy RDD in R using the canonical rdrobust + rddensity packages (Calonico, Cattaneo, Titiunik). rdbwselect gives the MSE-optimal bandwidth; rdrobust fits local linear regressions with robust bias-corrected inference; rddensity runs the...

library(rdrobust)
library(rddensity)

set.seed(11)
n <- 4000
x <- runif(n, 150, 230)               # running variable: index LDL (mg/dL)
c <- 190                              # guideline cutoff
p <- ifelse(x >= c, 0.65, 0.20)       # fuzzy first stage
d <- as.integer(runif(n) < p)
y <- 0.30 - 0.0008 * (x - c) - 0.047 * d + rnorm(n, 0, 0.10)

# 1) Manipulation (density) test at the cutoff.
dens <- rddensity(X = x, c = c)
summary(dens)

# 2) MSE-optimal bandwidth, then fuzzy RDD with robust bias-corrected inference.
bw  <- rdbwselect(y = y, x = x, c = c, p = 1)
fit <- rdrobust(y = y, x = x, c = c, fuzzy = d, p = 1)   # local complier effect at c
summary(fit)

# 3) Visualize: binned means with local-linear fits on each side.
rdplot(y = y, x = x, c = c, p = 1)