Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
9eecfda
feat: add LWDiD estimator (Lee & Wooldridge 2025, 2026)
gorgeousfish Jun 30, 2026
54ac4ed
fix(lwdid): Step 2 — address maintainer review
gorgeousfish Jul 19, 2026
0d26cf0
docs(tutorial): execute 27_lwdid notebook with outputs
gorgeousfish Jul 19, 2026
7118e53
fix(lwdid): Step 2 final — IPWRA event-study, mypy zero, tutorial out…
gorgeousfish Jul 19, 2026
1c1332d
refactor(lwdid): put LWDiDResults on the shared results contract
gorgeousfish Jul 30, 2026
7b6b419
fix(lwdid): build staggered cells per (g,t) and aggregate them jointly
gorgeousfish Jul 30, 2026
f3b9548
test(lwdid): cover cohort-time cells, joint inference and the aggrega…
gorgeousfish Jul 30, 2026
633379f
docs(lwdid): register the staggered module and the never-treated repl…
gorgeousfish Jul 30, 2026
e771e77
refactor(lwdid): inherit BaseEstimator, drop manual get/set_params
gorgeousfish Aug 7, 2026
f9d6bb3
refactor(lwdid): adopt canonical fit vocabulary and register naming-g…
gorgeousfish Aug 7, 2026
72f4be2
fix(lwdid): align event_study aggregate with upstream schema
gorgeousfish Aug 7, 2026
b2970a2
docs(lwdid): register tutorial and homepage rows for docs-IA guards
gorgeousfish Aug 8, 2026
36d9184
fix(lwdid): unified vectorized treatment-design validation
gorgeousfish Aug 8, 2026
2253723
fix(lwdid): per-cohort pre-period in transformation diagnostics
gorgeousfish Aug 8, 2026
a270a25
docs(lwdid): move clustering advisory to REGISTRY; remove module
gorgeousfish Aug 8, 2026
76d0987
refactor(lwdid): scope sensitivity to T0 + no-anticipation
gorgeousfish Aug 8, 2026
5145010
refactor(lwdid): retire trend pre-tests superseded by placebo machinery
gorgeousfish Aug 8, 2026
492115d
docs(tutorial): re-execute 27_lwdid with outputs
gorgeousfish Aug 8, 2026
8e45e0b
docs: use staggered interface in choosing_estimator LWDiD example
gorgeousfish Aug 8, 2026
1ca6f57
fix(lwdid): native time-scale pre-period identification + review polish
gorgeousfish Aug 8, 2026
152faac
fix(lwdid): use residual-based influence for cross-cell classical cov…
gorgeousfish Aug 10, 2026
65205fd
fix(lwdid): reject all-eventually-treated designs instead of truncating
gorgeousfish Aug 10, 2026
50c8083
fix(lwdid): reject time-varying covariates in staggered designs
gorgeousfish Aug 10, 2026
7911ad0
fix(lwdid): count ties as extreme in randomization-inference p-values
gorgeousfish Aug 10, 2026
23d4f9f
fix(lwdid): report failed sensitivity fits as not_estimable
gorgeousfish Aug 10, 2026
aa05797
fix(lwdid): honor the cohort parameter in recommend_transformation
gorgeousfish Aug 10, 2026
b93cd24
fix(lwdid): make LWDiDResults.to_dict() JSON-serializable
gorgeousfish Aug 10, 2026
1a6cff8
docs(lwdid): fix malformed RST table and stale staggered examples
gorgeousfish Aug 10, 2026
934a1fa
fix(lwdid): support datetime and Period time scales in staggered fits
gorgeousfish Aug 10, 2026
566dccc
fix(lwdid): resolve cluster column lookup when cluster equals unit
gorgeousfish Aug 10, 2026
e59ea54
test(lwdid): align equivalence aggregation with LW 2026 eq 7.19
gorgeousfish Aug 10, 2026
79c4250
fix(lwdid): serialize datetime labels in to_dict
gorgeousfish Aug 10, 2026
7beb428
docs(lwdid): document staggered contract tightenings + changelog
gorgeousfish Aug 10, 2026
787b41c
docs(lwdid): explain not_estimable robustness level in tutorial
gorgeousfish Aug 10, 2026
556a5d6
test(lwdid): pin NaT -> None serialization contract
gorgeousfish Aug 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`tests/test_docs_ia.py`.

### Fixed
- **`LWDiD` review-round fixes** (staggered contract and inference tightenings):
- Staggered classical/HC SEs now come from the joint influence function
across cohort-time cells (the LW 2026 eq. 7.19 pooled-regression basis),
accounting for correlation among cohort effects that share controls
instead of assuming independence.
- All-eventually-treated panels under `control_group='not_yet_treated'`
raise `ValueError` instead of silently truncating the sample; staggered
`covariates` must be unit-constant, time-varying columns raise
`ValueError`.
- Randomization inference counts ties as extreme (`>=`), so an all-tie
permutation distribution yields p = 1.0 rather than 0.
- `sensitivity_analysis` gains a `not_estimable` robustness level (with a
warning) when the ratio cannot be computed, instead of mislabeling it.
- `recommend_transformation` validates the `cohort` column (unknown names
raise `ValueError` instead of silently degrading to common timing) and
actually uses it for staggered diagnostics.
- `to_dict()` output is fully JSON-native, including datetime/Period
cohort and time labels (ISO-8601 / period strings, NaT -> None).
- Staggered fits accept datetime64 and Period time scales; cluster
variable equal to the unit column no longer raises a spurious
column-lookup error.
- **`docs/r_comparison.rst` migration tips named a nonexistent results field**
(`.ci`); the canonical accessor is `.conf_int`. The `aggte()` comparison
comment also claimed aggregation is requested at fit time, which stopped being
Expand Down Expand Up @@ -1046,6 +1067,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
point estimates, SEs, and t-statistics never move. Results objects echo
`df_convention`, and `SunAbraham`/`StackedDiD` gain `inference_df` (the
overall-ATT df actually used; None under bootstrap overrides).
- **`LWDiD` (Lee & Wooldridge 2025, 2026 rolling-transformation DiD).** Unit-specific
demean/detrend converts panel data to cross-sectional transformed outcomes;
supports staggered adoption with never-treated / not-yet-treated controls,
RA/IPW/IPWRA estimation, and cluster-robust inference. Alias `LW`.
- **Stata parity arm for ETWFE and Callaway-Sant'Anna ATT(g,t) (`jwdid` / `csdid`).**
`benchmarks/stata/generate_etwfe_cs_golden.do` anchors both staggered
estimators against their canonical Stata implementations on the genuine
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ Full guide: `diff_diff.get_llm_guide("practitioner")`.
- [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`.
- [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
- [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`
- [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`.
- [BaconDecomposition](https://diff-diff.readthedocs.io/en/stable/api/bacon.html) - Goodman-Bacon (2021) decomposition for diagnosing TWFE bias in staggered settings

## Diagnostics & Sensitivity
Expand Down
7 changes: 7 additions & 0 deletions diff_diff/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@
)
from diff_diff.lpdid import LPDiD
from diff_diff.lpdid_results import LPDiDResults
from diff_diff.lwdid import LWDiD
from diff_diff.lwdid_results import LWDiDResults
from diff_diff.mmm import (
MeridianROIPrior,
to_meridian_roi_prior,
Expand Down Expand Up @@ -333,6 +335,7 @@
CiC = ChangesInChanges
RDD = RegressionDiscontinuity
SCM = SyntheticControl
LW = LWDiD

# Alias diet (rows M-132..M-134, mechanism M-135): CDiD / Gardner /
# Stacked are deprecated in 3.9 and removed in 4.0. They deliberately
Expand Down Expand Up @@ -454,6 +457,10 @@ def __getattr__(name: str) -> _Any:
# LPDiD (Local Projections DiD)
"LPDiD",
"LPDiDResults",
# LWDiD (Lee & Wooldridge rolling transformation DiD)
"LWDiD",
"LWDiDResults",
"LW",
# Visualization
"plot_bacon",
"plot_event_study",
Expand Down
1 change: 1 addition & 0 deletions diff_diff/guides/llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ The site is organized into 5 sections, each with a landing page:
- [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=...)`.
- [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`.
- [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).
- [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
- [BaconDecomposition](https://diff-diff.readthedocs.io/en/stable/api/bacon.html): Goodman-Bacon (2021) decomposition for diagnosing TWFE bias in staggered settings

## Diagnostics and Sensitivity Analysis
Expand Down
Loading