diff_diff.TwoWayFixedEffects#

class diff_diff.TwoWayFixedEffects[source]#

Bases: DifferenceInDifferences

Two-Way Fixed Effects (TWFE) estimator for panel DiD.

Extends DifferenceInDifferences to handle panel data with unit and time fixed effects.

Parameters:
  • robust (bool, default=True) – Whether to use heteroskedasticity-robust standard errors.

  • 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 AND inference="analytical", the unit auto-cluster is dropped because these families are by construction one-way only and the validator rejects cluster_ids + classical / cluster_ids + hc2. The user’s explicit one-way choice wins over the TWFE default. Under inference="wild_bootstrap" the auto-cluster is preserved regardless of vcov_type (the bootstrap uses the cluster structure to resample residuals). On hc2_bm the auto-cluster is also preserved (routes to CR2-BM at unit).

  • alpha (float, default=0.05) – Significance level for confidence intervals.

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.

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, and result.r_squared reflect 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 on hc2_bm (routes to CR2-BM at unit) and on hc2 + wild_bootstrap; dropped on explicit hc2 + analytical to match the one-way contract. This wording applies to the non-survey analytical path: under survey_design= with no explicit cluster=, 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 explicit cluster="unit" or set survey_design.psu. Documented in docs/methodology/REGISTRY.md under 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>, and conley_lag_cutoff=<int> on the constructor; the time / unit arrays are auto-derived from the estimator’s time and unit column-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 scores S = X_demeaned * residuals_demeaned form the same meat as the full-dummy-expansion design. The temporal kernel is hardcoded Bartlett regardless of conley_kernel (matches conleyreg::time_dist). Explicit cluster=<col> + Conley enables the combined spatial + cluster product kernel K_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). When cluster= 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, time, unit[, ...])

Fit Two-Way Fixed Effects model.

get_params()

Get estimator parameters (sklearn-compatible).

predict(data)

Predict outcomes using fitted model.

print_summary()

Print summary to stdout.

set_params(**params)

Set estimator parameters (sklearn-compatible).

summary()

Get summary of estimation results.

__init__(robust=True, cluster=None, vcov_type=None, alpha=0.05, inference='analytical', n_bootstrap=999, bootstrap_weights='rademacher', seed=None, rank_deficient_action='warn', conley_coords=None, conley_cutoff_km=None, conley_metric='haversine', conley_kernel='bartlett', conley_lag_cutoff=None)#
Parameters:
  • robust (bool)

  • cluster (str | None)

  • vcov_type (str | None)

  • alpha (float)

  • inference (str)

  • n_bootstrap (int)

  • bootstrap_weights (str)

  • seed (int | None)

  • rank_deficient_action (str)

  • conley_coords (Tuple[str, str] | None)

  • conley_cutoff_km (float | None)

  • conley_metric (str)

  • conley_kernel (str)

  • conley_lag_cutoff (int | None)

classmethod __new__(*args, **kwargs)#