A cohort-time contrast compares the change for branches first treated in period g with the change for branches still untreated at the comparison period t.
Cohort-time difference-in-differences for staggered adoption
State which effect is requested
For branches first using triage in month three, ask how their month-four breach rate changed relative to month two, beyond the change among branches untreated through month four. This is a cohort-three, time-four contrast. Its population is branches that adopted in month three, not every branch that will ever adopt. The causal estimand fixes whose effect is under discussion.
Use a clean comparison pool
A never-treated branch can serve as a control. A branch scheduled to adopt in month five can also serve at month four if it has not anticipated treatment and is otherwise comparable. A branch already treated in month two cannot be a month-four untreated control. The code deliberately forms the control set with first use after the post month or no use at all. With a month-two baseline and month-four outcome, treated branches improved four percentage points more than their controls in the fixture.
Do not let the formula supply assumptions
The observed difference equals a causal effect only under a defendable parallel-trends condition for the untreated potential outcome, along with no anticipation, stable measurement and no relevant spillovers. Pre-period similarities help assess plausibility but cannot prove the unobserved counterfactual. The rollout may target branches whose breach rate was already improving or worsening. Record assignment rules and branch staffing changes before fitting.
Avoid one pooled coefficient by habit
When adoption dates differ and effects vary by cohort or time since adoption, a simple two-way fixed-effects treatment coefficient can mix comparisons that use already-treated branches as controls. Compute supported cohort-time effects first, inspect them, then specify how to average them using transparent weights. Do not average estimates from different months without stating whether each branch or each eligible case gets equal weight. Event-time audits display how support changes across lags.
Treat this code as a ledger calculation
The function needs a complete, already validated panel and returns a simple difference of branch means. It does not adjust for covariates, compute standard errors or establish parallel trends. A release analysis needs a maintained staggered-adoption method and uncertainty at the assignment unit. Cluster resampling illustrates why branch-level dependence must be respected.
Implementation
def cohort_time_change(panel, adoption_month, cohort_month, before_month, after_month):
if not before_month < cohort_month <= after_month:
raise ValueError("invalid comparison months")
treated = [branch for branch, month in adoption_month.items()
if month == cohort_month]
controls = [branch for branch, month in adoption_month.items()
if month is None or month > after_month]
if not treated or not controls:
raise ValueError("no supported treated or control group")
def average_change(branches):
changes = []
for branch in branches:
changes.append(panel[(branch, after_month)] - panel[(branch, before_month)])
return sum(changes) / len(changes)
return average_change(treated) - average_change(controls)
first_use = {"North": 3, "East": 3, "West": None, "South": 5}
breaches = {("North", 2): .21, ("North", 4): .16,
("East", 2): .19, ("East", 4): .15,
("West", 2): .17, ("West", 4): .18,
("South", 2): .14, ("South", 4): .15}
estimate = cohort_time_change(breaches, first_use, 3, 2, 4)
assert abs(estimate - (-.055)) < 1e-12Performance and operating cost
For B branches, selecting groups and computing mean changes is O(B) time and O(B) temporary space. Indexing a raw R-row panel into the dictionary first costs O(R) expected time and space. Statistical uncertainty and assumptions are outside this arithmetic check.
Common Mistakes
- Do not use an already-treated branch as an untreated comparison.
- Do not present a cohort-time calculation as causal without examining trends and selection.
- Do not collapse heterogeneous cohort effects into one coefficient without explicit weights.
Read next
- Branch-month panels and the rollout clock
- Event-time pre-trends and support for a staggered rollout
- Spillover-aware comparison pools for branch rollouts
- Branch-cluster bootstrap for a rollout contrast
- Project: audit a staggered support-branch rollout
Continue the workflow: Leave-one-branch-out stability for rollout effects.
Continue the workflow: Segmented regression for level and slope changes.
Continue the workflow: Differential outcome-label error in group contrasts.
