Lesson 5 of 11

Regression Discontinuity

In Lesson 4, the repair for a staggered rollout was a clean, never-treated group to compare against. Sometimes no such group exists. A scholarship goes to everyone above a score. A drug is prescribed to everyone above a risk threshold. A district gets extra funding whenever its poverty rate crosses a line. Everyone on one side is treated, everyone on the other is not, and the two sides look nothing alike.

Regression discontinuity turns that rigid rule into an opportunity. Right at the cutoff, a student who just cleared the line and one who just missed it are all but identical, except that one got treated. The jump in the outcome exactly at the line is the causal effect.

By the end of this lesson you will be able to:

  • Explain why comparing everyone above the cutoff to everyone below it overstates the effect
  • Write the sharp-RDD estimand as the jump in the outcome at the cutoff
  • Fit a regression discontinuity in R and read the effect off two local lines
  • Choose a bandwidth, trading the bias of looking too wide against the noise of looking too narrow

Prerequisites: Lesson 3 (the 2x2 DiD) and Lesson 4 (why a clean untreated group matters). You can fit lm, read its coefficients, and subset a data frame in base R.

The setup

A scholarship, and an unfair comparison

Meet the Dean's Merit Scholarship at a large university. Any applicant whose entrance-exam score is 80 or higher (out of 100) is awarded a $5,000 scholarship; anyone at 79.9 or below gets nothing. One clean rule, no committee, no appeals. Years later the university asks the obvious question: did the scholarship actually help? It has every student's entrance score, whether they won the money, and their first-year college GPA on the usual 0 to 4 scale.

We will build that data ourselves, so we know the true answer to check against. In our simulated university the scholarship really does lift first-year GPA by 0.30 points, and GPA also rises with entrance score on its own (stronger students earn higher grades, scholarship or not). Each lesson runs in a fresh R session, so we create everything here.

RInteractive R
set.seed(5) n <- 4000 score <- runif(n, 50, 100) # entrance-exam score, 50 to 100 cutoff <- 80 scholarship <- as.integer(score >= cutoff) # the sharp rule: awarded iff score >= 80 # first-year GPA rises with score AND gets a real +0.30 bump from the scholarship gpa <- 2.7 + 0.045 * (score - cutoff) - 0.0008 * (score - cutoff)^2 + 0.30 * scholarship + rnorm(n, 0, 0.22) college <- data.frame(score = round(score, 1), scholarship, gpa = round(gpa, 2)) head(college) #> score scholarship gpa #> 1 60.0 0 1.82 #> 2 84.3 1 3.03 #> 3 95.8 1 3.54 #> 4 64.2 0 1.60 #> 5 55.2 0 0.80 #> 6 85.1 1 2.86

  

The obvious way to measure the scholarship's effect is to compare the average GPA of the winners against the losers.

RInteractive R
winners <- mean(college$gpa[college$scholarship == 1]) losers <- mean(college$gpa[college$scholarship == 0]) round(c(winners = winners, losers = losers, gap = winners - losers), 2) #> winners losers gap #> 3.34 1.79 1.55

  

Winners average a 3.34 GPA, losers a 1.79: a gap of 1.55 grade points. That is more than five times the 0.30 the scholarship truly delivers. Take it at face value and you would credit a $5,000 cheque with turning a C student into an A student. Something is badly off.