diff_diff.TwoWayFixedEffects#
- class diff_diff.TwoWayFixedEffects[source]#
Bases:
DifferenceInDifferencesTwo-Way Fixed Effects (TWFE) estimator for panel DiD.
Extends DifferenceInDifferences to handle panel data with unit and time fixed effects.
- Parameters:
robust (bool, optional) – DEPRECATED legacy alias inherited from
DifferenceInDifferences(row M-045; warns withFutureWarning, removed in 4.0 - usevcov_type=).cluster (str, optional) –
Column name for cluster-robust standard errors. If None, automatically clusters at the unit level (the unit parameter passed to fit()). This differs from DifferenceInDifferences where cluster=None means no clustering.
Exception (one-way analytical): when
vcov_type in {"classical", "hc2"}is explicit ANDinference="analytical", the unit auto-cluster is dropped because these families are by construction one-way only and the validator rejectscluster_ids + classical/cluster_ids + hc2. The user’s explicit one-way choice wins over the TWFE default. Underinference="wild_bootstrap"the auto-cluster is preserved regardless ofvcov_type(the bootstrap uses the cluster structure to resample residuals). Onhc2_bmthe auto-cluster is also preserved (routes to CR2-BM at unit).alpha (float, default=0.05) – Significance level for confidence intervals.
df_convention ({"residual", "cluster", "normal"}, default "residual") – Inherited from
DifferenceInDifferences: df convention for analytical t/p/CI."residual"(default) uses the fitted residual df;"cluster"uses the Stata/fixestG − 1on clustered fits (no effect on unclustered or Conley fits);"normal"deliberately uses normal-theory z inference at the fallback level on every fit, clustered or not. Survey df and per-coefficient Bell-McCaffrey DOF keep precedence under every value. Default flips to"cluster"at v4.
Notes
This estimator uses the regression:
Y_it = α_i + γ_t + β*(D_i × Post_t) + X_it’δ + ε_it
where α_i are unit fixed effects and γ_t are time fixed effects.
Event-study mode (3.9).
fit(..., event_study=True, time=<calendar column>)estimates per-period treatment effects and returns the unifiedEventStudyResultssurface instead of the single static ATT (absorbing the deprecatedMultiPeriodDiD).spec="within"(default) estimates the unit-FE event studyα_i + γ_t + Σ_e δ_e (D_i × 1[t=e]);spec="pooled"reproduces the MultiPeriodDiD design exactly (treatment-group dummy + period dummies, no unit FE - the only spec valid for repeated cross-sections). Point estimates coincide across the two specs only on balanced no-covariate simultaneous-adoption panels; standard errors differ in general. Both specs assume SIMULTANEOUS adoption (all treated units adopt at the same time). The staggered-adoption advisory can only detect timing from within-unit 0-to-1 transitions (a time-varyingD_itcolumn, which itself draws a warning): with the documented time-invariant ever-treatedD_iindicator, adoption timing is not observable in the inputs at all, so the assumption cannot be verified by the estimator - it is asserted by the user. For the same reason the calendar partition is explicit:post_periods=is REQUIRED in event-study mode (the deprecated MultiPeriodDiD midpoint default is not carried over). For staggered designs useCallawaySantAnnaorSunAbraham. The mode carries TWFE’s inference stack from day one: unit auto-cluster (with the same carve-outs as the static path - dropped on Conley, never injected as a survey PSU, dropped for explicit one-way analytical families), andinference="wild_bootstrap"raises (the wild cluster bootstrap covers the static ATT only). Seedocs/methodology/REGISTRY.md“Event-study mode”.HC2 / Bell-McCaffrey are supported via an internal full-dummy build. Because TWFE’s within-transformation preserves coefficients but not the hat matrix, HC2 leverage and CR2 Bell-McCaffrey corrections on the demeaned design would produce wrong small-sample SEs. When
vcov_type in {"hc2","hc2_bm"}, TWFE bypasses the within-transform and builds the full-dummy design[intercept, treated×post, covariates, unit_dummies, time_dummies]directly, so the leverage correction and BM DOF compute on the full FE projection. Under this path,result.coefficients,result.vcov,result.residuals,result.fitted_values, andresult.r_squaredreflect the full-dummy fit rather than the within-transformed reduced fit; the ATT coefficient, its SE, and analytical inference are unchanged. Auto-cluster-at-unit is preserved onhc2_bm(routes to CR2-BM at unit) and onhc2+wild_bootstrap; dropped on explicithc2+analyticalto match the one-way contract. This wording applies to the non-survey analytical path: undersurvey_design=with no explicitcluster=, TWFE intentionally keeps the documented implicit-PSU path (auto-cluster is NOT injected into the survey PSU structure) — users who want unit-level PSU injection under a survey design must pass explicitcluster="unit"or setsurvey_design.psu. Documented indocs/methodology/REGISTRY.mdunder the scope-limitation note.Conley spatial-HAC (``vcov_type=”conley”``) is supported via the block-decomposed panel sandwich (matches R ``conleyreg`` with ``lag_cutoff > 0``). Pass
conley_coords=(lat_col, lon_col),conley_cutoff_km=<float>, andconley_lag_cutoff=<int>on the constructor; thetime/unitarrays are auto-derived from the estimator’stimeandunitcolumn-name arguments at fit-time. The sandwich sums within-period spatial pairs plus within-unit Bartlett serial pairs (lag=0 excluded to avoid double-counting); this is NOT a multiplicative product kernel. FWL composability: the within-transformed scoresS = X_demeaned * residuals_demeanedform the same meat as the full-dummy-expansion design. The temporal kernel is hardcoded Bartlett regardless ofconley_kernel(matchesconleyreg::time_dist). Explicitcluster=<col>+ Conley enables the combined spatial + cluster product kernelK_total[i, j] = K_space(d_ij/h) · 1{cluster_i = cluster_j}; cluster membership must be constant within each unit across periods (validator-enforced on the panel block-decomposed path). Whencluster=is unset, TWFE’s default auto-cluster at the unit level is silently dropped on the Conley path — Conley spatial HAC alone is applied, not the combined kernel. Restrictions:inference="wild_bootstrap"+ Conley raises (incompatible inference modes);survey_design=+ Conley raises (Phase 5 follow-up).Warning: TWFE can be biased with staggered treatment timing and heterogeneous treatment effects. Consider using more robust estimators (e.g., Callaway-Sant’Anna) for staggered designs.
Methods
__init__([robust, cluster, vcov_type, ...])decompose(data, outcome, unit, time, first_treat)Perform Goodman-Bacon decomposition of TWFE estimate.
fit(data, outcome, treatment[, post, unit, ...])Fit Two-Way Fixed Effects model (static ATT or event-study mode).
get_params([deep])Get estimator parameters (sklearn-compatible).
predict(data)Predict outcomes using the fitted model.
print_summary()Print summary to stdout.
set_params(**params)Set estimator parameters (sklearn-compatible, transactional).
summary()Get summary of estimation results.
- __init__(robust=None, cluster=None, vcov_type=None, alpha=0.05, inference='analytical', n_bootstrap=999, bootstrap_weights='rademacher', p_val_type='two-tailed', seed=None, rank_deficient_action='warn', conley_coords=None, conley_cutoff_km=None, conley_metric='haversine', conley_kernel='bartlett', conley_lag_cutoff=None, df_convention='residual')#
- Parameters:
robust (bool | None)
cluster (str | None)
vcov_type (str | None)
alpha (float)
inference (str)
n_bootstrap (int)
bootstrap_weights (str)
p_val_type (str)
seed (int | None)
rank_deficient_action (str)
conley_cutoff_km (float | None)
conley_metric (str)
conley_kernel (str)
conley_lag_cutoff (int | None)
df_convention (str)
- classmethod __new__(*args, **kwargs)#