moderndid.att_gt#
- moderndid.att_gt(data, yname, tname, idname=None, gname=None, xformla=None, weightsname=None, alp=0.05, cband=True, boot=False, biters=1000, clustervars=None, est_method='dr', panel=True, allow_unbalanced_panel=False, control_group='nevertreated', anticipation=0, base_period='varying', random_state=None, n_jobs=1, n_partitions=None, max_cohorts=None, backend=None)[source]#
Compute group-time average treatment effects.
Implements difference-in-differences estimation for staggered adoption designs where treatment timing varies across units, following [1]. This approach addresses the challenges of standard two-way fixed-effects regressions by providing flexible estimators that allow for treatment effect heterogeneity across groups and over time.
Let \(G_i\) denote the time period when unit \(i\) is first treated, with \(G_i = \infty\) for never-treated units, and let \(C_i\) be an indicator for never-treated status. The fundamental parameter of interest is the group-time average treatment effect, \(ATT(g,t)\), which measures the average effect for units first treated in period \(g\) as of time \(t\)
\[ATT(g,t) = \mathbb{E}[Y_t(g) - Y_t(0) \mid G = g].\]Identification relies on a conditional parallel trends assumption. When using never-treated units as the comparison group, the assumption requires that trends in untreated potential outcomes are the same for the treatment group and never-treated units conditional on covariates \(X\)
\[\mathbb{E}[Y_t(0) - Y_{t-1}(0) \mid X, G = g] = \mathbb{E}[Y_t(0) - Y_{t-1}(0) \mid X, C = 1],\]where \(C = 1\) indicates never-treated units. The doubly robust estimand combines inverse probability weighting and outcome regression, providing consistency if either the propensity score or outcome model is correctly specified
\[ATT_{dr}(g,t) = \mathbb{E}\left[\left(\frac{G_g}{\mathbb{E}[G_g]} - \frac{\frac{p_g(X) C}{1 - p_g(X)}} {\mathbb{E}\left[\frac{p_g(X) C}{1 - p_g(X)}\right]}\right) \left(\Delta Y_t - m_{g,t}(X)\right)\right],\]where \(p_g(X)\) is the propensity score, \(\Delta Y_t\) is the change in outcomes, and \(m_{g,t}(X)\) is the expected outcome change for the comparison group.
- Parameters:
- data
DataFrame Panel data in long format. Accepts any object implementing the Arrow PyCapsule Interface (
__arrow_c_stream__), including polars, pandas, pyarrow Table, and cudf DataFrames.- yname
str The name of the outcome variable.
- tname
str The name of the column containing the time periods.
- idname
str, optional The individual (cross-sectional unit) id name. Required for panel data.
- gname
str The name of the variable that contains the first period when a particular observation is treated. This should be a positive number for all observations in treated groups. It defines which “group” a unit belongs to. It should be 0 for units in the untreated group.
- xformla
str, optional A formula for the covariates to include in the model. It should be of the form “~ X1 + X2”. Default is None which is equivalent to xformla=”~1”.
- weightsname
str, optional The name of the column containing the sampling weights. If not set, all observations have same weight.
- alp
float, default=0.05 The significance level.
- cbandbool, default=True
Whether or not to compute a uniform confidence band that covers all of the group-time average treatment effects with fixed probability 1-alp.
- bootbool, default=False
Whether or not to compute standard errors using the multiplier bootstrap. If standard errors are clustered, then one must set boot=True.
- biters
int, default=1000 The number of bootstrap iterations to use. Only applicable if boot=True.
- clustervars
list[str], optional A list of variables names to cluster on. At most, there can be two variables (otherwise will throw an error) and one of these must be the same as idname which allows for clustering at the individual level.
- est_method{“dr”, “ipw”, “reg”} or
callable, default=”dr” The method to compute group-time average treatment effects. The default is “dr” which uses the doubly robust approach. Other built-in methods include “ipw” for inverse probability weighting and “reg” for first step regression estimators. The user can also pass their own function for estimating group time average treatment effects.
- panelbool, default=True
Whether or not the data is a panel dataset. The panel dataset should be provided in long format.
- allow_unbalanced_panelbool, default=False
Whether or not function should “balance” the panel with respect to time and id. The default values if False which means that att_gt will drop all units where data is not observed in all periods.
- control_group{“nevertreated”, “notyettreated”}, default=”nevertreated”
Which units to use the control group. The default is “nevertreated” which sets the control group to be the group of units that never participate in the treatment.
- anticipation
int, default=0 The number of time periods before participating in the treatment where units can anticipate participating in the treatment and therefore it can affect their untreated potential outcomes.
- base_period{“varying”, “universal”}, default=”varying”
Whether to use a “varying” base period or a “universal” base period.
- random_state
int,Generator, optional Controls the randomness of the bootstrap. Pass an int for reproducible results across multiple function calls. Can also accept a NumPy
Generatorinstance.- n_jobs
int, default=1 Number of parallel jobs for group-time estimation. 1 = sequential (default), -1 = all cores, >1 = that many workers.
- n_partitions
intorNone, default=None Number of Dask partitions per cell. Only used when
datais a Dask DataFrame; ignored for non-Dask inputs.- max_cohorts
intorNone, default=None Maximum number of treatment cohorts to process in parallel. Only used when
datais a Dask DataFrame; ignored for non-Dask inputs.- backend{“numpy”, “cupy”} or
None, default=None Array backend to use for this call only. When set, the backend is activated for the duration of this call and reverted automatically when the call returns.
None(the default) uses whatever backend is currently active (seeset_backend). Ignored whendatais a Dask DataFrame.
- data
- Returns:
MPResultObject containing group-time average treatment effect results:
groups: Array indicating which group (period first treated) each ATT is for
times: Array indicating which time period each ATT is for
att_gt: Array of group-time average treatment effects
se_gt: Standard errors for each ATT(g,t)
vcov_analytical: Analytical variance-covariance matrix
critical_value: Critical value for confidence intervals (simultaneous if bootstrap with cband=True)
influence_func: Influence function matrix for each ATT(g,t)
n_units: Number of unique cross-sectional units
wald_stat: Wald statistic for pre-testing parallel trends
wald_pvalue: P-value for the parallel trends pre-test
alpha: Significance level used
estimation_params: Dictionary with estimation details (control_group, anticipation_periods, etc.)
G: Unit-level group assignments
weights_ind: Unit-level sampling weights (if provided)
See also
aggteAggregate group-time average treatment effects.
References
[1]Callaway, B., & Sant’Anna, P. H. (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
Examples
The dataset below contains 500 observations of county-level teen employment rates from 2003-2007. Some states are first treated in 2004, some in 2006, and some in 2007. The variable
first.treatindicates the first period in which a state is treated:In [1]: import numpy as np ...: from moderndid import att_gt, load_mpdta ...: ...: df = load_mpdta() ...: print(df.head()) ...: shape: (5, 6) ┌──────┬────────────┬──────────┬──────────┬─────────────┬───────┐ │ year ┆ countyreal ┆ lpop ┆ lemp ┆ first.treat ┆ treat │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ i64 ┆ f64 ┆ f64 ┆ i64 ┆ i64 │ ╞══════╪════════════╪══════════╪══════════╪═════════════╪═══════╡ │ 2003 ┆ 8001 ┆ 5.896761 ┆ 8.461469 ┆ 2007 ┆ 1 │ │ 2004 ┆ 8001 ┆ 5.896761 ┆ 8.33687 ┆ 2007 ┆ 1 │ │ 2005 ┆ 8001 ┆ 5.896761 ┆ 8.340217 ┆ 2007 ┆ 1 │ │ 2006 ┆ 8001 ┆ 5.896761 ┆ 8.378161 ┆ 2007 ┆ 1 │ │ 2007 ┆ 8001 ┆ 5.896761 ┆ 8.487352 ┆ 2007 ┆ 1 │ └──────┴────────────┴──────────┴──────────┴─────────────┴───────┘
We can compute group-time average treatment effects for a staggered adoption design where different units adopt treatment at different time periods. The output is an object of type
MPResultwhich is a container for the results:In [2]: result = att_gt( ...: data=df, ...: yname="lemp", ...: tname="year", ...: gname="first.treat", ...: idname="countyreal", ...: est_method="dr", ...: boot=False ...: ) ...: print(result) ...: ============================================================================== Group-Time Average Treatment Effects ============================================================================== ┌───────┬──────┬──────────┬────────────┬────────────────────────────┐ │ Group │ Time │ ATT(g,t) │ Std. Error │ [95% Pointwise Conf. Band] │ ├───────┼──────┼──────────┼────────────┼────────────────────────────┤ │ 2004 │ 2004 │ -0.0105 │ 0.0233 │ [-0.0561, 0.0351] │ │ 2004 │ 2005 │ -0.0704 │ 0.0310 │ [-0.1312, -0.0097] * │ │ 2004 │ 2006 │ -0.1373 │ 0.0364 │ [-0.2087, -0.0658] * │ │ 2004 │ 2007 │ -0.1008 │ 0.0344 │ [-0.1682, -0.0335] * │ │ 2006 │ 2004 │ 0.0065 │ 0.0233 │ [-0.0392, 0.0522] │ │ 2006 │ 2005 │ -0.0028 │ 0.0196 │ [-0.0411, 0.0356] │ │ 2006 │ 2006 │ -0.0046 │ 0.0178 │ [-0.0394, 0.0302] │ │ 2006 │ 2007 │ -0.0412 │ 0.0202 │ [-0.0809, -0.0016] * │ │ 2007 │ 2004 │ 0.0305 │ 0.0150 │ [ 0.0010, 0.0600] * │ │ 2007 │ 2005 │ -0.0027 │ 0.0164 │ [-0.0349, 0.0294] │ │ 2007 │ 2006 │ -0.0311 │ 0.0179 │ [-0.0661, 0.0040] │ │ 2007 │ 2007 │ -0.0261 │ 0.0167 │ [-0.0587, 0.0066] │ └───────┴──────┴──────────┴────────────┴────────────────────────────┘ ------------------------------------------------------------------------------ Signif. codes: '*' confidence band does not cover 0 P-value for pre-test of parallel trends assumption: 0.1681 ------------------------------------------------------------------------------ Data Info ------------------------------------------------------------------------------ Control Group: Never Treated Anticipation Periods: 0 ------------------------------------------------------------------------------ Estimation Details ------------------------------------------------------------------------------ Estimation Method: Doubly Robust ------------------------------------------------------------------------------ Inference ------------------------------------------------------------------------------ Significance level: 0.05 Analytical standard errors ============================================================================== Reference: Callaway and Sant'Anna (2021)