chc.did¶
Stability tier: evolving.
Callaway-Sant'Anna staggered-adoption difference-in-differences.
Group-time average treatment effects ATT(g, t) -- the effect at period t on the cohort
first treated at period g -- from clean 2x2 DiD comparisons against never- or not-yet-treated
units. Under staggered adoption with dynamic/heterogeneous effects, two-way fixed effects is biased:
already-treated units enter as controls with negative weights (Goodman-Bacon decomposition), so a
single TWFE coefficient is a contaminated weighted average. These cohort-specific comparisons never
use an already-treated unit as a control, so they are not.
A statistical estimator, so NumPy float64 throughout (like chc.independence) -- independent
of the JAX x64 flag, which must not change an estimate.
callaway_santanna_inference adds the estimates' uncertainty through diff-diff, the
did extra, whose Callaway-Sant'Anna reproduces these estimates.
GroupTimeATT
dataclass
¶
Callaway-Sant'Anna output: cohort ATT(g,t), the event-study curve, and overall ATT.
pretrend()
¶
Pre-treatment ATT(g,t) for t < g -- a placebo; ~0 supports parallel trends.
EventStudyInference
dataclass
¶
callaway_santanna's estimates, with their uncertainty. Experimental.
estimate is callaway_santanna's own. The rest is diff-diff's multiplier bootstrap,
which draws whole units, so it holds however a unit's errors are correlated over time. se
and band are by relative time e, without the base period e = -1, where the event
study is zero by construction. band holds every e at once with probability
1 - alpha: the bootstrap's sup-t band, where a pointwise interval is
event_study[e] +- z se[e]. overall_interval is the overall ATT's.
robust_interval(m)
¶
The average effect after treatment, robust to trends that part smoothly.
Rambachan and Roth's smoothness restriction: the treated units' trend may differ from the
comparison's by a line whose slope changes by at most m a period, before treatment and
after. m = 0 allows exactly the linear difference the periods before treatment can
show. The target is the event study's effects after treatment averaged with equal weights,
which is not estimate.overall's weighting. The interval is its optimal fixed-length
interval at level 1 - alpha, from diff-diff's HonestDiD on the event study's analytic
covariance; it agrees with R's HonestDiD to 1e-3. At m = 0, with trends parallel or
apart by a line, it covered 0.95 at 300 units, 0.92 at 100 and 0.78-0.79 at 30.
Raises:
| Type | Description |
|---|---|
ValueError
|
for a negative |
callaway_santanna(outcomes, group, *, control='notyet', never_treated=-1)
¶
Group-time ATT(g,t) for a balanced panel via never-/not-yet-treated 2x2 DiD.
outcomes is (N, T) with outcomes[i, t] unit i's outcome at period t;
group is (N,) with each unit's first-treated period (0-indexed) or never_treated.
control="notyet" compares against units not yet treated by t (never-treated included --
more controls, de Chaisemartin-d'Haultfoeuille-robust); "never" uses only never-treated.
Universal base period g - 1:
ATT(g,t) = E[Y_t - Y_{g-1} | G=g] - E[Y_t - Y_{g-1} | control]. event_study aggregates
by relative time e = t - g; overall is the size-weighted mean of post-treatment effects.
callaway_santanna_inference(outcomes, group, *, control='notyet', never_treated=-1, alpha=0.05, draws=999, seed=0)
¶
callaway_santanna with standard errors, intervals and a uniform band.
Experimental: it may change or be withdrawn in any release.
Takes callaway_santanna's arguments, and computes its estimates. diff-diff's
Callaway-Sant'Anna, at the same comparison and base period g - 1, reproduces them; they
are checked to agree before its bootstrap is read, so every interval is centred on this
library's estimate. draws bootstrap draws are taken with seed.
The levels hold with enough units, and not below. On panels of ten periods, three cohorts and never-treated units, with errors correlated within a unit, at 5%: the overall ATT's interval rejected a true null 5.7-6.6% of the time from 100 units, and 6.9-7.8% at 30; the band 6.4-7.2% at 300 units, 7.9-8.7% at 100, and 21-24% at 30.
Needs the did extra (pip install 'causal-hybrid-control[did]').
Raises:
| Type | Description |
|---|---|
ValueError
|
on |
RuntimeError
|
when diff-diff's estimates do not reproduce these, which would put the intervals around another estimate. |
twoway_fixed_effects_att(outcomes, group, *, never_treated=-1)
¶
The single two-way fixed-effects treatment coefficient -- the biased baseline CS beats.
Regresses the twice-demeaned outcome on the twice-demeaned treatment indicator
D[i,t] = 1{t >= group[i]}. Under staggered timing with dynamic effects this is a
negative-weighted average of the ATT(g,t) (Goodman-Bacon), not the average effect.
de_chaisemartin(outcomes, group, *, never_treated=-1)
¶
de Chaisemartin-d'Haultfoeuille DID_M -- the average instantaneous (first-exposure) effect.
A switcher-count-weighted average, over consecutive-period 2x2 DiDs, of the outcome change of
units first treated at t minus that of units still untreated at t (untreated stayers).
Like callaway_santanna it is heterogeneity-robust where TWFE is not, but its estimand is
the effect at the moment of switching (relative time e = 0), not the size-weighted average
over post periods -- a growing effect yields the first-period impact, not the overall ATT.