Skip to content

Commit 9eecfda

Browse files
gorgeousfishclaude
andcommitted
feat: add LWDiD estimator (Lee & Wooldridge 2025, 2026)
Maintainer rebase onto current main (igerber, 2026-07-17), per plan agreed in PR igerber#588: dropped committed datasets (tutorial now uses the checksummed load_prop99()/load_walmart() loaders on main), kept the maintainer-authored paper reviews and references entries from igerber#685, removed the lwdid dev dependency (external reference implementations stay environmental, importorskip-gated), renumbered tutorial 26 -> 27. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 54df914 commit 9eecfda

30 files changed

Lines changed: 12908 additions & 2 deletions

‎CHANGELOG.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
10461046
point estimates, SEs, and t-statistics never move. Results objects echo
10471047
`df_convention`, and `SunAbraham`/`StackedDiD` gain `inference_df` (the
10481048
overall-ATT df actually used; None under bootstrap overrides).
1049+
- **`LWDiD` (Lee & Wooldridge 2025, 2026 rolling-transformation DiD).** Unit-specific
1050+
demean/detrend converts panel data to cross-sectional transformed outcomes;
1051+
supports staggered adoption with never-treated / not-yet-treated controls,
1052+
RA/IPW/IPWRA estimation, and cluster-robust inference. Alias `LW`.
10491053
- **Stata parity arm for ETWFE and Callaway-Sant'Anna ATT(g,t) (`jwdid` / `csdid`).**
10501054
`benchmarks/stata/generate_etwfe_cs_golden.do` anchors both staggered
10511055
estimators against their canonical Stata implementations on the genuine

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ Full guide: `diff_diff.get_llm_guide("practitioner")`.
120120
- [WooldridgeDiD](https://diff-diff.readthedocs.io/en/stable/api/wooldridge_etwfe.html) - Wooldridge (2023, 2025) ETWFE: saturated OLS, logit/Poisson QMLE (ASF-based ATT). Alias `ETWFE`.
121121
- [LPDiD](https://diff-diff.readthedocs.io/en/stable/api/lpdid.html) - Dube, Girardi, Jorda & Taylor (2025) Local Projections DiD: per-horizon long-difference event study on clean controls (no negative weighting), variance- or equally-weighted ATT, for absorbing or non-absorbing (reversible) treatment
122122
- [ChangesInChanges](https://diff-diff.readthedocs.io/en/stable/api/changes_in_changes.html) - Athey & Imbens (2006) nonlinear/distributional DiD for the 2x2 design: full counterfactual distribution and quantile treatment effects via CDF transformation, plus the QDiD comparison estimator via `method="qdid"`; bootstrap inference; R qte parity. Alias `CiC`
123+
- [LWDiD](https://diff-diff.readthedocs.io/en/stable/api/lwdid.html) - Lee & Wooldridge (2025, 2026) rolling-transformation DiD: unit-specific demean/detrend converts panel to cross-section, staggered adoption, RA/IPW/IPWRA estimation. Alias `LW`.
123124
- [BaconDecomposition](https://diff-diff.readthedocs.io/en/stable/api/bacon.html) - Goodman-Bacon (2021) decomposition for diagnosing TWFE bias in staggered settings
124125

125126
## Diagnostics & Sensitivity

‎diff_diff/__init__.py‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@
160160
)
161161
from diff_diff.lpdid import LPDiD
162162
from diff_diff.lpdid_results import LPDiDResults
163+
from diff_diff.lwdid import LWDiD
164+
from diff_diff.lwdid_results import LWDiDResults
163165
from diff_diff.mmm import (
164166
MeridianROIPrior,
165167
to_meridian_roi_prior,
@@ -333,6 +335,7 @@
333335
CiC = ChangesInChanges
334336
RDD = RegressionDiscontinuity
335337
SCM = SyntheticControl
338+
LW = LWDiD
336339

337340
# Alias diet (rows M-132..M-134, mechanism M-135): CDiD / Gardner /
338341
# Stacked are deprecated in 3.9 and removed in 4.0. They deliberately
@@ -454,6 +457,46 @@ def __getattr__(name: str) -> _Any:
454457
# LPDiD (Local Projections DiD)
455458
"LPDiD",
456459
"LPDiDResults",
460+
# LWDiD (Lee & Wooldridge rolling transformation DiD)
461+
"LWDiD",
462+
"LWDiDResults",
463+
"LW",
464+
"wild_cluster_bootstrap",
465+
"WildClusterBootstrapResult",
466+
"randomization_inference",
467+
"RandomizationResult",
468+
"test_parallel_trends",
469+
"diagnose_heterogeneous_trends",
470+
"recommend_transformation",
471+
"ParallelTrendsTestResult",
472+
"sensitivity_analysis",
473+
"robustness_pre_periods",
474+
"sensitivity_no_anticipation",
475+
"SensitivityResult",
476+
"lwdid",
477+
"plot_cohort_trends",
478+
"plot_lwdid_event_study",
479+
"plot_lwdid_sensitivity",
480+
"plot_bootstrap_distribution",
481+
# LWDiD exceptions
482+
"LWDIDError",
483+
"LWDIDWarning",
484+
"LWDIDInferenceError",
485+
"RandomizationError",
486+
"DiagnosticError",
487+
"NumericalWarning",
488+
"DiagnosticWarning",
489+
"SensitivityWarning",
490+
"VisualizationError",
491+
# LWDiD clustering diagnostics
492+
"diagnose_clustering",
493+
"diagnose_clustering_from_data",
494+
"recommend_clustering_level",
495+
"ClusteringDiagnostics",
496+
"ClusteringRecommendation",
497+
# LWDiD utility functions
498+
"validate_staggered_data",
499+
"is_never_treated",
457500
# Visualization
458501
"plot_bacon",
459502
"plot_event_study",

‎diff_diff/guides/llms.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ The site is organized into 5 sections, each with a landing page:
8080
- [LPDiD](https://diff-diff.readthedocs.io/en/stable/api/lpdid.html): Dube, Girardi, Jorda & Taylor (2025) Local Projections DiD: per-horizon long-difference event study on clean controls (no negative weighting); variance- or equally-weighted ATT, premean differencing, pooled pre/post, fast. Absorbing by default; non-absorbing (reversible) treatment via `non_absorbing="first_entry"` (Eq. 12) or `"effect_stabilization"` (Eq. 13, window `L`). Complex-survey designs (pweight + stratified-PSU TSL SEs) on the default path via `fit(survey_design=...)`.
8181
- [ChangesInChanges](https://diff-diff.readthedocs.io/en/stable/api/changes_in_changes.html): Athey & Imbens (2006) nonlinear/distributional DiD for the 2x2 design: recovers the treated group's full counterfactual outcome distribution and quantile treatment effects (ATT + QTE grid) via the CDF transformation `F_10(F_00^{-1}(F_01(y)))`; invariant to monotone outcome transformations (unconditional fits; the covariate QR branch is not); bootstrap inference (panel or repeated cross-section resampling); point parity with R `qte::CiC()`, including its covariate branch (`covariates=` -> per-cell linear quantile regression, Melly-Santangelo-style conditional CiC). Continuous outcomes, numeric covariates. Alias `CiC`.
8282
- [QDiD](https://diff-diff.readthedocs.io/en/stable/api/changes_in_changes.html): **Deprecated 3.9, removed 4.0 - use `ChangesInChanges(method="qdid")`.** Athey & Imbens (2006) quantile DiD comparison estimator (additive quantile-by-quantile DiD, matching R `qte::QDiD()` including its covariate branch via `covariates=`); same bootstrap machinery as ChangesInChanges. The paper recommends CiC over QDiD (scale-dependent model with testable restrictions; a non-monotonicity warning fires when violated - unconditional fits only, the covariate-path counterfactual quantile curve is monotone by construction).
83+
- [LWDiD](https://diff-diff.readthedocs.io/en/stable/api/lwdid.html): Lee & Wooldridge (2025, 2026) rolling-transformation DiD — unit-specific demean/detrend converts panel to cross-section, supports staggered adoption with flexible control groups and estimation (RA/IPW/IPWRA). Alias: LW
8384
- [BaconDecomposition](https://diff-diff.readthedocs.io/en/stable/api/bacon.html): Goodman-Bacon (2021) decomposition for diagnosing TWFE bias in staggered settings
8485

8586
## Diagnostics and Sensitivity Analysis

0 commit comments

Comments
 (0)