Parallel Trends Assumption: Intuition, Testing, and Visualization
An in-depth understanding of the core assumption of DID—parallel trends. Explains the meaning of the assumption, visualization testing methods, and pre-trend tests, with accompanying Stata code.
Structure of This Article
- Principle: The precise meaning of the parallel trends assumption
- Intuition: Why parallel trends are so critical
- Code: Visualization tests + statistical pre-trend tests
Layer 1: Principle
Precise Statement of the Parallel Trends Assumption
The identification of DID relies on the parallel trends assumption:
In words: in the counterfactual world (i.e., assuming no treatment), the outcome variables of the treatment group and the control group follow the same trend.
Untestability
The parallel trends assumption involves the counterfactual , so it cannot be directly tested in principle. We can only examine:
- Whether the pre-treatment trends of the two groups are parallel (necessary but not sufficient)
- Pre-trend tests
Event Study Framework for Pre-trend Tests
where is the policy implementation time and is the base period.
Testing logic: If for all (pre-treatment periods), then the parallel trends assumption is supported.
Layer 2: Intuition
Imagine two parallel railroad tracks:
- Pre-treatment: the two groups change at the same rate, like parallel tracks
- After policy implementation: the treatment group's track deviates, and the magnitude of the deviation is the treatment effect
If the two tracks were not parallel before treatment (for example, the treatment group was already accelerating), then DID would mistakenly attribute this "pre-existing differential trend" to the treatment effect.
Layer 3: Stata Code
// ═══════════════════════════════════════════════
// Parallel Trends Test
// ═══════════════════════════════════════════════
clear all
set seed 54321
set obs 500
gen id = _n
expand 10
bysort id: gen t = _n
gen treat = (id > 250)
gen post = (t > 5)
// Simulate data: parallel pre-treatment trends
gen y = 1 + 0.3*treat + 0.5*t + 2*treat*post + rnormal(0, 1)
// ═══ Visualization Test ═══════════════════════════════
preserve
collapse (mean) y, by(treat t)
twoway (connected y t if treat==0, lcolor(blue) mcolor(blue)) ///
(connected y t if treat==1, lcolor(red) mcolor(red)), ///
xline(5.5, lpattern(dash)) ///
legend(order(1 "Control group" 2 "Treatment group")) ///
title("Parallel Trends Visualization Test")
restore
// ═══ Statistical Pre-trend Test ═══════════════════════════
gen rel_t = t - 6
forval k = -5/4 {
gen D`k' = (rel_t == `k') * treat
}
drop D-1 // Base period
reghdfe y D*, absorb(id t) cluster(id)
// Joint test: whether pre-treatment coefficients are jointly zero
test D-5 D-4 D-3 D-2
// p > 0.05 → cannot reject parallel trendsReferences
- Roth, J. (2022). Pretest with Caution: Event-Study Estimates after Testing for Parallel Trends. AER: Insights, 4(3), 305-322.
- Kahn-Lang, A., & Lang, K. (2020). The Promise and Pitfalls of Differences-in-Differences. Journal of Economic Perspectives, 34(3), 203-220.