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 ddd and 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_resultDDDMultiPeriodResult

Result from ddd_mp containing 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_eint, 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_efloat, default=-inf

Minimum event time to include in eventstudy aggregation.

max_efloat, 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.

bitersint, default=1000

Number of bootstrap iterations.

cbandbool, default=True

Whether to compute uniform confidence bands. Requires boot=True.

alphafloat, default=0.05

Significance level for confidence intervals.

random_stateint, Generator, optional

Controls randomness of the bootstrap.

Returns:
DDDAggResult

Aggregated 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

ddd

Compute 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 ddd function 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.