diff_diff.LWDiD#
- class diff_diff.LWDiD[source]#
Bases:
BaseEstimatorLee & Wooldridge rolling-transformation DiD estimator.
- Parameters:
rolling ({'demean', 'detrend', 'demeanq', 'detrendq'}, default 'demean') – Unit-specific transformation method. ‘demean’: subtract pre-treatment mean ‘detrend’: subtract pre-treatment linear trend ‘demeanq’: subtract unit-specific seasonal (quarterly) means ‘detrendq’: subtract unit-specific linear trend + seasonal effects
estimation_method ({'reg', 'ipw', 'dr', 'psm'}, default 'reg') – Treatment effect estimation method. ‘reg’: regression adjustment (OLS) ‘ipw’: inverse probability weighting ‘dr’: doubly robust (augmented IPW) ‘psm’: propensity score matching (1:n_neighbors nearest-neighbor, 1:1 by default); POINT ESTIMATES ONLY - inference is NaN pending an Abadie-Imbens matching variance (see DEFERRED.md)
vcov_type ({'classical', 'hc1', 'hc2', 'hc3'}, default 'hc1') – Variance-covariance estimator. ‘hc2’: leverage-corrected (u_i^2 / (1-h_ii)) ‘hc3’: jackknife-style leverage correction (u_i^2 / (1-h_ii)^2) The full set applies to
estimation_method='reg'only: ‘ipw’/’dr’/’psm’ accept ‘hc1’ alone (the influence-function variance on ipw/dr; psm reports NaN inference - see below). Cluster-robust (CR1) inference activates via thecluster=parameter, not through avcov_typevalue, composes only with ‘hc1’, and is rejected for ‘psm’.cluster (str or None, default None) – Column name for cluster-robust (CR1) standard errors. When set, clustered inference is active for the whole fit.
control_group ({'never_treated', 'not_yet_treated'}, default 'not_yet_treated') – Control group definition for staggered designs. Both options require never-treated units: ‘never_treated’ needs at least two, and ‘not_yet_treated’ needs at least one so that every cohort-time cell keeps a valid control pool. Panels where all units are eventually treated are rejected with a ValueError.
alpha (float, default 0.05) – Significance level for confidence intervals.
n_bootstrap (int, default 0) – Number of bootstrap replications (0 = analytical inference).
seed (int or None, default None) – Random seed for bootstrap inference.
pscore_trim (float, default 0.01) – Propensity score trimming threshold. Scores below this value or above (1 - pscore_trim) are clipped. Used by IPW/DR/PSM. Must be in
(0, 0.5)and large enough that1 - pscore_trim < 1in float64 (a sub-ulp trim would disable the upper clip).n_neighbors (int, default 1) – Number of nearest neighbors for PSM matching.
caliper (float or None, default None) – Maximum allowable distance for PSM matches. Unmatched treated units (no control within caliper) receive NaN.
with_replacement (bool, default True) – Whether PSM matching is done with replacement.
n_jobs (int, default 1) – Execution parallelism for the common-timing bootstrap (ThreadPoolExecutor when > 1; experimental). Purely an execution setting: seeded bootstrap draws are identical for every value (per-replicate SeedSequence streams), so it never affects any reported number and is not stored in result provenance.
Notes
Parameter mapping from lwdid-py to diff-diff:
The standalone
lwdid-pypackage (from lwdid import lwdid) uses a functional interface with separated(ever-treated indicator) andpost(post-period indicator) columns. In diff-diff, thetreatmentcolumn is the time-varying binary indicatorD_i * post_t—i.e., the product of the two lwdid-py columns.# lwdid-py (functional API): lwdid(data, y='y', d='d', ivar='unit', tvar='time', post='post', rolling='demean', estimator='ra', vce=None) # Equivalent in diff-diff (class-based API): LWDiD(rolling='demean', estimation_method='reg', vcov_type='classical').fit( data, outcome='y', unit='unit', time='time', treatment='treat') # where data['treat'] == data['d'] * data['post']
Parameter correspondence:
lwdid-py
diff-diff
Notes
y
outcome
Outcome column name
d + post
treatment
Binary D_it (ever-treated × post)
ivar
unit
Unit identifier
tvar
time
Time variable
gvar
first_treat
Cohort (first treatment period)
rolling
rolling
Same values
estimator=’ra’
estimation_method
‘ra’ -> ‘reg’, ‘ipwra’ -> ‘dr’
vce=None
vcov_type
Homoskedastic == ‘classical’
vce=’hc1’
vcov_type=’hc1’
Heteroskedasticity-robust
vce=’cluster’
cluster=<column>
Constructor cluster= parameter
cluster_var
cluster
Cluster variable name
controls
covariates
fit() covariates= parameter
control_group
control_group
Same values
Results mapping:
lwdid-py
diff-diff
Notes
result.att
result.att
ATT point estimate
result.se_att
result.se
Standard error
result.t_stat
result.t_stat
t-statistic
result.pvalue
result.p_value
p-value (note underscore)
result.ci_lower
result.conf_int[0]
CI lower bound
result.ci_upper
result.conf_int[1]
CI upper bound
result.nobs
result.n_obs
Number of observations
result.n_treated
result.n_treated
Treated units
result.n_control
result.n_control
Control units
result.vce_type
result.vcov_type
Variance family
result.cluster_var
result.cluster_name
Cluster variable name
result.n_clusters
result.n_clusters
Number of clusters
Examples
>>> import numpy as np, pandas as pd >>> from diff_diff.lwdid import LWDiD >>> from diff_diff import generate_staggered_data >>> data = generate_staggered_data(n_units=100, n_periods=8, seed=0) >>> model = LWDiD(rolling='demean', estimation_method='reg') >>> result = model.fit(data, outcome='outcome', unit='unit', ... time='period', treatment='treated', ... first_treat='first_treat') >>> result.att != 0 True
Methods
__init__([rolling, estimation_method, ...])fit(data, outcome, unit, time, treatment[, ...])Fit the LWDiD estimator.
get_params([deep])Get estimator parameters (sklearn-compatible).
get_transformation_diagnostics(data, ...[, ...])Run the transformation step and return diagnostics without full estimation.
set_params(**params)Set estimator parameters (sklearn-compatible, transactional).
- __init__(rolling='demean', estimation_method='reg', vcov_type='hc1', cluster=None, control_group='not_yet_treated', alpha=0.05, n_bootstrap=0, seed=None, pscore_trim=0.01, n_neighbors=1, caliper=None, with_replacement=True, n_jobs=1)[source]#
- classmethod __new__(*args, **kwargs)#