Getting started
The estimand
The building block is the group-time average treatment effect ATT(g,t): the average effect, in period t, on the cohort first treated in period g.
A staggered design produces one of these for every cohort and every period,
which is more numbers than anyone reads directly. csdid estimates all of them
and leaves the aggregation to you. The cells themselves stay available for
inspection after estimation.
The three choices
The comparison group. Not-yet-treated units are the default, and
nevertreated restricts the comparison to units that are never treated.
Not-yet-treated gives you more comparisons and does not require a never-treated
group to exist. The cost is an extra assumption: later-treated cohorts’ untreated
paths have to be comparable over the periods they spend in the comparison group.
We would check that against the pre-treatment cells before leaning on it.
The 2×2 estimator. method(dr) (default) is doubly robust: consistent if
either the outcome model or the propensity score is right. method(reg) is
outcome regression, and method(ipw) is inverse probability weighting. We
recommend keeping the default unless you have a reason to trust one of the two
models over the other.
The aggregation. estat event (by time since treatment), estat group (by
cohort), estat calendar (by period), estat simple (one number).
Your first estimate
Let’s run one from the raw file to the event study, on county mortality data.
import delimited using ///
"https://raw.githubusercontent.com/pedrohcgs/JEL-DiD/50f4f18/data/county_mortality_data.csv", ///
clear varnames(1) bindquote(strict) stringcols(_all)
destring deaths population_20_64 year yaca county_code stfips unemp_rate poverty_rate, ///
replace force
generate double mrate = 100000 * deaths / population_20_64
drop if missing(mrate) | population_20_64 <= 0
generate int gvar = yaca
replace gvar = 0 if missing(gvar) | gvar > 2016
bysort county_code: generate byte nyears = _N
keep if nyears == 11
csdid mrate, ivar(county_code) time(year) gvar(gvar) rseed(20250101)
estat event
bindquote(strict) is not optional here: the file has quoted fields containing
newlines, and without it Stata splits them into extra observations. Several
columns carry "NA", hence the destring ... , force. The last two lines are
the whole estimation.
Two rules about the axis
gvar() is 0 for never-treated units and the first treated period otherwise;
time() is 1 or more. Cohorts and periods share one positive calendar-time
axis, and 0 is reserved for “never treated”. A zero or negative cohort code
has no consistent reading. If your data start at or below zero, shift both by
the same amount. A monotone relabeling of the periods leaves every estimate
unchanged.
Next: balanced panels.