moderndid.agg_ddd#
- moderndid.agg_ddd(ddd_result, type='eventstudy', balance_e=None, min_e=-inf, max_e=inf, dropna=False, boot=True, biters=1000, cband=True, alpha=0.05, random_state=None) DDDAggResult[source]#
Aggregate group-time average treatment effects for triple differences.
Takes the full set of group-time average treatment effects from
dddand aggregates them into interpretable summary measures, following [1] and [2]. Different aggregation schemes answer different policy questions about treatment effect heterogeneity.Let \(\mathcal{G}_{\mathrm{trt}}\) denote the set of treatment cohorts, \(T\) the final time period, and \(ATT(g,t)\) the group-time average treatment effect for cohort \(g\) at time \(t\).
The event-study aggregation reveals how effects evolve with exposure time \(e = t - g\)
\[ES(e) = \sum_{g \in \mathcal{G}_{\mathrm{trt}}} \mathbb{P}(G=g \mid G+e \in [2, T]) \, ATT(g, g+e).\]The simple aggregation computes an overall summary by averaging event-study coefficients across post-treatment periods
\[ES_{\mathrm{avg}} = \frac{1}{|\mathcal{E}|} \sum_{e \in \mathcal{E}} ES(e),\]where \(\mathcal{E}\) is the support of post-treatment event times.
Group-specific aggregation averages effects over time for each treatment cohort \(g\)
\[\theta_g = \frac{1}{T - g + 1} \sum_{t=g}^{T} ATT(g, t).\]Calendar-time aggregation averages across treated cohorts within each period \(t\)
\[\theta_t = \sum_{g \leq t} \mathbb{P}(G=g \mid G \leq t) \, ATT(g, t).\]- Parameters:
- ddd_result
DDDMultiPeriodResult Result from
ddd_mpcontaining group-time ATTs.- type{“simple”, “eventstudy”, “group”, “calendar”}, default=”eventstudy”
Type of aggregation to perform:
‘simple’: Weighted average of all post-treatment ATT(g,t) with weights proportional to group size.
‘eventstudy’: Event-study aggregation showing effects at different lengths of exposure to treatment.
‘group’: Average treatment effects across different treatment cohorts.
‘calendar’: Average treatment effects across different calendar time periods.
- balance_e
int, optional If set (and type=”eventstudy”), balances the sample with respect to event time. For example, if balance_e=2, groups not exposed for at least 3 periods (e=0, 1, 2) are dropped.
- min_e
float, default=-inf Minimum event time to include in eventstudy aggregation.
- max_e
float, default=inf Maximum event time to include in aggregation.
- dropnabool, default=False
Whether to remove NA values before aggregation.
- bootbool, default=True
Whether to compute standard errors using the multiplier bootstrap.
- biters
int, default=1000 Number of bootstrap iterations.
- cbandbool, default=True
Whether to compute uniform confidence bands. Requires boot=True.
- alpha
float, default=0.05 Significance level for confidence intervals.
- random_state
int,Generator, optional Controls randomness of the bootstrap.
- ddd_result
- Returns:
DDDAggResultAggregated treatment effect results containing:
overall_att: Overall aggregated ATT
overall_se: Standard error for overall ATT
aggregation_type: Type of aggregation performed
egt: Event times, groups, or calendar times
att_egt: ATT estimates for each element in egt
se_egt: Standard errors for each element in egt
crit_val: Critical value for confidence intervals
inf_func: Influence function matrix
inf_func_overall: Influence function for overall ATT
See also
dddCompute group-time average treatment effects for triple differences.
References
[1]Callaway, B., & Sant’Anna, P. H. C. (2021). Difference-in-differences with multiple time periods. Journal of Econometrics, 225(2), 200-230. https://doi.org/10.1016/j.jeconom.2020.12.001
[2]Ortiz-Villavicencio, M., & Sant’Anna, P. H. C. (2025). Better Understanding Triple Differences Estimators. arXiv preprint arXiv:2505.09942. https://arxiv.org/abs/2505.09942
Examples
First, we compute group-time average treatment effects using the
dddfunction on multi-period data with staggered treatment adoption:In [1]: import numpy as np ...: from moderndid import ddd, agg_ddd, gen_ddd_mult_periods ...: ...: dgp = gen_ddd_mult_periods(n=500, dgp_type=1, random_state=42) ...: df = dgp["data"] ...: ...: ddd_result = ddd( ...: data=df, ...: yname="y", ...: tname="time", ...: idname="id", ...: gname="group", ...: pname="partition", ...: control_group="nevertreated", ...: est_method="dr", ...: ) ...: ddd_result ...: Out[1]: ============================================================================== Triple Difference-in-Differences (DDD) Estimation Multi-Period / Staggered Treatment Adoption ============================================================================== DR-DDD estimation for ATT(g,t): ┌───────┬──────┬──────────┬────────────┬───────────────────────┐ │ Group │ Time │ ATT(g,t) │ Std. Error │ [95% Conf. Int.] │ ├───────┼──────┼──────────┼────────────┼───────────────────────┤ │ 2 │ 1 │ 0.0000 │ NA │ NA │ │ 2 │ 2 │ -6.5255 │ 10.4750 │ [-27.0561, 14.0050] │ │ 2 │ 3 │ -14.0093 │ 20.9401 │ [-55.0512, 27.0325] │ │ 3 │ 1 │ -0.9262 │ 10.8543 │ [-22.2001, 20.3478] │ │ 3 │ 2 │ 0.0000 │ NA │ NA │ │ 3 │ 3 │ 25.0984 │ 10.8614 │ [ 3.8105, 46.3864] * │ └───────┴──────┴──────────┴────────────┴───────────────────────┘ ------------------------------------------------------------------------------ Signif. codes: '*' confidence interval does not cover 0 ------------------------------------------------------------------------------ Data Info ------------------------------------------------------------------------------ Panel Data Outcome variable: y Qualification variable: partition Control group: Never Treated Base period: universal No. of units per treatment group: Units never enabling treatment: 97 Units enabling treatment at period 2: 173 Units enabling treatment at period 3: 230 ------------------------------------------------------------------------------ Estimation Details ------------------------------------------------------------------------------ Outcome regression: OLS Propensity score: Logistic regression (MLE) ------------------------------------------------------------------------------ Inference ------------------------------------------------------------------------------ Significance level: 0.05 Analytical standard errors ============================================================================== See Ortiz-Villavicencio and Sant'Anna (2025) for details.
Now we can aggregate these group-time effects in different ways. The “simple” aggregation computes an overall ATT by taking a weighted average of all post-treatment group-time ATTs:
In [2]: simple_agg = agg_ddd(ddd_result, type="simple") ...: print(simple_agg) ...: ============================================================================== Aggregate DDD Treatment Effects ============================================================================== Overall ATT: ┌────────┬────────────┬────────────────────────┐ │ ATT │ Std. Error │ [95% Conf. Interval] │ ├────────┼────────────┼────────────────────────┤ │ 3.8544 │ 12.0220 │ [-19.7082, 27.4170] │ └────────┴────────────┴────────────────────────┘ ------------------------------------------------------------------------------ Signif. codes: '*' confidence band does not cover 0 ------------------------------------------------------------------------------ Data Info ------------------------------------------------------------------------------ Panel Data Outcome variable: y Qualification variable: partition Control group: Never Treated Base period: universal ------------------------------------------------------------------------------ Estimation Details ------------------------------------------------------------------------------ Outcome regression: OLS Propensity score: Logistic regression (MLE) ------------------------------------------------------------------------------ Inference ------------------------------------------------------------------------------ Significance level: 0.05 Bootstrap standard errors ============================================================================== See Ortiz-Villavicencio and Sant'Anna (2025) for details.
The “group” aggregation computes average treatment effects separately for each treatment cohort (units first treated in the same period):
In [3]: group_agg = agg_ddd(ddd_result, type="group") ...: print(group_agg) ...: ============================================================================== Aggregate DDD Treatment Effects (Group/Cohort) ============================================================================== Overall summary of ATT's based on group/cohort aggregation: ┌────────┬────────────┬────────────────────────┐ │ ATT │ Std. Error │ [95% Conf. Interval] │ ├────────┼────────────┼────────────────────────┤ │ 9.9166 │ 10.4133 │ [-10.4930, 30.3262] │ └────────┴────────────┴────────────────────────┘ Group Effects: ┌───────┬──────────┬────────────┬──────────────────────────┐ │ Group │ Estimate │ Std. Error │ [95% Simult. Conf. Band] │ ├───────┼──────────┼────────────┼──────────────────────────┤ │ 2 │ -10.2674 │ 16.1895 │ [-46.6447, 26.1098] │ │ 3 │ 25.0984 │ 10.0904 │ [ 2.4256, 47.7712] * │ └───────┴──────────┴────────────┴──────────────────────────┘ ------------------------------------------------------------------------------ Signif. codes: '*' confidence band does not cover 0 ------------------------------------------------------------------------------ Data Info ------------------------------------------------------------------------------ Panel Data Outcome variable: y Qualification variable: partition Control group: Never Treated Base period: universal ------------------------------------------------------------------------------ Estimation Details ------------------------------------------------------------------------------ Outcome regression: OLS Propensity score: Logistic regression (MLE) ------------------------------------------------------------------------------ Inference ------------------------------------------------------------------------------ Significance level: 0.05 Bootstrap standard errors ============================================================================== See Ortiz-Villavicencio and Sant'Anna (2025) for details.
The “eventstudy” aggregation (default) creates an event study, showing how treatment effects evolve relative to the treatment start date:
In [4]: es_agg = agg_ddd(ddd_result, type="eventstudy") ...: print(es_agg) ...: ============================================================================== Aggregate DDD Treatment Effects (Event Study) ============================================================================== Overall summary of ATT's based on event-study aggregation: ┌─────────┬────────────┬────────────────────────┐ │ ATT │ Std. Error │ [95% Conf. Interval] │ ├─────────┼────────────┼────────────────────────┤ │ -1.2432 │ 14.2568 │ [-29.1861, 26.6996] │ └─────────┴────────────┴────────────────────────┘ Dynamic Effects: ┌────────────┬──────────┬────────────┬──────────────────────────┐ │ Event time │ Estimate │ Std. Error │ [95% Simult. Conf. Band] │ ├────────────┼──────────┼────────────┼──────────────────────────┤ │ -2 │ -0.9262 │ 11.0537 │ [-25.5692, 23.7168] │ │ -1 │ 0.0000 │ NA │ NA │ │ 0 │ 11.5229 │ 8.9970 │ [-8.5349, 31.5807] │ │ 1 │ -14.0093 │ 21.1189 │ [-61.0917, 33.0730] │ └────────────┴──────────┴────────────┴──────────────────────────┘ ------------------------------------------------------------------------------ Signif. codes: '*' confidence band does not cover 0 ------------------------------------------------------------------------------ Data Info ------------------------------------------------------------------------------ Panel Data Outcome variable: y Qualification variable: partition Control group: Never Treated Base period: universal ------------------------------------------------------------------------------ Estimation Details ------------------------------------------------------------------------------ Outcome regression: OLS Propensity score: Logistic regression (MLE) ------------------------------------------------------------------------------ Inference ------------------------------------------------------------------------------ Significance level: 0.05 Bootstrap standard errors ============================================================================== See Ortiz-Villavicencio and Sant'Anna (2025) for details.
We can also limit the event study to specific event times:
In [5]: es_limited = agg_ddd( ...: ddd_result, ...: type="eventstudy", ...: min_e=-2, ...: max_e=2 ...: ) ...: print(es_limited) ...: ============================================================================== Aggregate DDD Treatment Effects (Event Study) ============================================================================== Overall summary of ATT's based on event-study aggregation: ┌─────────┬────────────┬────────────────────────┐ │ ATT │ Std. Error │ [95% Conf. Interval] │ ├─────────┼────────────┼────────────────────────┤ │ -1.2432 │ 14.0846 │ [-28.8486, 26.3621] │ └─────────┴────────────┴────────────────────────┘ Dynamic Effects: ┌────────────┬──────────┬────────────┬──────────────────────────┐ │ Event time │ Estimate │ Std. Error │ [95% Simult. Conf. Band] │ ├────────────┼──────────┼────────────┼──────────────────────────┤ │ -2 │ -0.9262 │ 11.0096 │ [-26.5568, 24.7045] │ │ -1 │ 0.0000 │ NA │ NA │ │ 0 │ 11.5229 │ 9.0928 │ [-9.6454, 32.6912] │ │ 1 │ -14.0093 │ 20.8152 │ [-62.4678, 34.4492] │ └────────────┴──────────┴────────────┴──────────────────────────┘ ------------------------------------------------------------------------------ Signif. codes: '*' confidence band does not cover 0 ------------------------------------------------------------------------------ Data Info ------------------------------------------------------------------------------ Panel Data Outcome variable: y Qualification variable: partition Control group: Never Treated Base period: universal ------------------------------------------------------------------------------ Estimation Details ------------------------------------------------------------------------------ Outcome regression: OLS Propensity score: Logistic regression (MLE) ------------------------------------------------------------------------------ Inference ------------------------------------------------------------------------------ Significance level: 0.05 Bootstrap standard errors ============================================================================== See Ortiz-Villavicencio and Sant'Anna (2025) for details.
The “calendar” aggregation computes average treatment effects by calendar time period:
In [6]: calendar_agg = agg_ddd(ddd_result, type="calendar") ...: print(calendar_agg) ...: ============================================================================== Aggregate DDD Treatment Effects (Calendar Time) ============================================================================== Overall summary of ATT's based on calendar time aggregation: ┌────────┬────────────┬────────────────────────┐ │ ATT │ Std. Error │ [95% Conf. Interval] │ ├────────┼────────────┼────────────────────────┤ │ 0.8924 │ 11.9021 │ [-22.4354, 24.2201] │ └────────┴────────────┴────────────────────────┘ Time Effects: ┌──────┬──────────┬────────────┬──────────────────────────┐ │ Time │ Estimate │ Std. Error │ [95% Simult. Conf. Band] │ ├──────┼──────────┼────────────┼──────────────────────────┤ │ 2 │ -6.5255 │ 10.8960 │ [-29.0532, 16.0021] │ │ 3 │ 8.3102 │ 13.5490 │ [-19.7026, 36.3230] │ └──────┴──────────┴────────────┴──────────────────────────┘ ------------------------------------------------------------------------------ Signif. codes: '*' confidence band does not cover 0 ------------------------------------------------------------------------------ Data Info ------------------------------------------------------------------------------ Panel Data Outcome variable: y Qualification variable: partition Control group: Never Treated Base period: universal ------------------------------------------------------------------------------ Estimation Details ------------------------------------------------------------------------------ Outcome regression: OLS Propensity score: Logistic regression (MLE) ------------------------------------------------------------------------------ Inference ------------------------------------------------------------------------------ Significance level: 0.05 Bootstrap standard errors ============================================================================== See Ortiz-Villavicencio and Sant'Anna (2025) for details.