Skip to content

Commit c11eaed

Browse files
igerberclaude
andcommitted
Release 3.3.2: dCDH by_path × trends extensions, Yatchew mean_independence, HAD Phase 4 R-parity, Rust rand bump
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 5443c13 commit c11eaed

6 files changed

Lines changed: 8 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [Unreleased]
8+
## [3.3.2] - 2026-04-26
99

1010
### Added
1111
- **`ChaisemartinDHaultfoeuille.by_path` is now compatible with `trends_linear` (DID^{fd} group-specific linear trends) and `trends_nonparam` (state-set trends).** For `trends_linear`, the first-differencing transform runs once globally before path enumeration, so per-path raw second-differences `DID^{fd}_{path, l}` surface on `path_effects[path]["horizons"][l]` automatically. Per-path **cumulated level effects** `delta_{path, l} = sum_{l'=1..l} DID^{fd}_{path, l'}` (the quantity R returns under `did_multiplegt_dyn(..., by_path, trends_lin)`) surface on the new `results.path_cumulated_event_study[path][l]` field, mirroring the global `linear_trends_effects` cumulation. `to_dataframe(level="by_path")` exposes `cumulated_effect` / `cumulated_se` columns (always present, NaN-when-None — mirrors the `cband_*` convention from PR #374); `summary()` renders a "Cumulated Level Effects (DID^{fd}, trends_linear)" sub-section under each per-path block. SE on the cumulated layer is the conservative upper bound (sum of per-horizon component SEs, NaN-consistent), matching the global `linear_trends_effects` convention. Path enumeration runs on the post-first-differenced `N_mat_fd`: switchers with `F_g==2` fail the window-eligibility check and are dropped from path enumeration entirely (the existing global `F_g >= 3` warning still surfaces the issue), so a path whose switchers all have `F_g < 3` is silently absent from `path_effects` rather than present-with-NaN. Placebo under `trends_linear` returns RAW per-horizon values — there is no per-path placebo cumulation surface in either Python or R. For `trends_nonparam`, the set membership column is validated and stored once globally as `set_ids_arr`; the `set_ids` parameter is now threaded through the four per-path IF helpers (`_compute_path_effects`, `_compute_path_placebos`, `_collect_path_bootstrap_inputs`, `_collect_path_placebo_bootstrap_inputs`) so per-path analytical SE, bootstrap, placebos, and sup-t bands all consume the set-restricted control pool automatically. Per-period effects remain unadjusted under both extensions, consistent with the existing per-period DID contract. Validated against R via two new golden-value scenarios: `single_baseline_multi_path_by_path_trends_lin` (n_periods=13, F_g >= 4, cohort-single-path; per-path cumulated point estimates match R bit-exactly with `POINT_RTOL=1e-9`, cumulated SE within `CUM_SE_RTOL=0.20`) and `multi_path_reversible_by_path_trends_nonparam` (per-path point estimates AND placebos match R bit-exactly with `POINT_RTOL=1e-9`, per-path SE within `SE_RTOL=0.15`). **F_g=3 boundary-case divergence (`by_path + trends_linear`):** `F_g=3` switchers have only 1 valid pre-window Z value after first-differencing, triggering 30%+ relative divergence between Python and R per-path point estimates on paths whose switchers include `F_g=3`. A targeted `UserWarning` fires at fit-time on this regime; R parity is asserted only on the `F_g >= 4` parity fixture. Placebo parity for `trends_linear` is intentionally skipped (R's per-path placebo computation re-runs on the path-restricted subsample with different control eligibility than Python's global-then-disaggregate architecture surfaces; placebo + `trends_linear` is exercised via internal regression only). Cross-path cohort-sharing SE deviation from R documented for `path_effects` is inherited unchanged. Gates at `chaisemartin_dhaultfoeuille.py:1014-1023` removed; `by_path` docstring updated to add the two new compatibility paragraphs and remove `trends_linear` / `trends_nonparam` from the incompatible list. R-parity tests at `tests/test_chaisemartin_dhaultfoeuille_parity.py::TestDCDHDynRParityByPathTrendsLinear` and `::TestDCDHDynRParityByPathTrendsNonparam`; cross-surface regressions at `tests/test_chaisemartin_dhaultfoeuille.py::TestByPathTrendsLinear` and `::TestByPathTrendsNonparam`. See `docs/methodology/REGISTRY.md` §ChaisemartinDHaultfoeuille `Note (Phase 3 by_path ...)` → "Per-path linear-trends DID^{fd}" and "Per-path state-set trends" for the full contract.
@@ -1421,6 +1421,7 @@ for the full feature history leading to this release.
14211421
[2.1.2]: https://github.com/igerber/diff-diff/compare/v2.1.1...v2.1.2
14221422
[2.1.1]: https://github.com/igerber/diff-diff/compare/v2.1.0...v2.1.1
14231423
[2.1.0]: https://github.com/igerber/diff-diff/compare/v2.0.3...v2.1.0
1424+
[3.3.2]: https://github.com/igerber/diff-diff/compare/v3.3.1...v3.3.2
14241425
[3.3.1]: https://github.com/igerber/diff-diff/compare/v3.3.0...v3.3.1
14251426
[3.3.0]: https://github.com/igerber/diff-diff/compare/v3.2.0...v3.3.0
14261427
[3.2.0]: https://github.com/igerber/diff-diff/compare/v3.1.3...v3.2.0

CITATION.cff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ authors:
77
family-names: Gerber
88
orcid: "https://orcid.org/0009-0009-3275-5591"
99
license: MIT
10-
version: "3.3.1"
11-
date-released: "2026-04-25"
10+
version: "3.3.2"
11+
date-released: "2026-04-26"
1212
doi: "10.5281/zenodo.19646175"
1313
url: "https://github.com/igerber/diff-diff"
1414
repository-code: "https://github.com/igerber/diff-diff"

diff_diff/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@
287287
DCDH = ChaisemartinDHaultfoeuille
288288
HAD = HeterogeneousAdoptionDiD
289289

290-
__version__ = "3.3.1"
290+
__version__ = "3.3.2"
291291
__all__ = [
292292
# Estimators
293293
"DifferenceInDifferences",

diff_diff/guides/llms-full.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
> A Python library for Difference-in-Differences causal inference analysis. Provides sklearn-like estimators with statsmodels-style output for econometric analysis.
44

5-
- Version: 3.3.1
5+
- Version: 3.3.2
66
- Repository: https://github.com/igerber/diff-diff
77
- License: MIT
88
- Dependencies: numpy, pandas, scipy (no statsmodels dependency)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "maturin"
44

55
[project]
66
name = "diff-diff"
7-
version = "3.3.1"
7+
version = "3.3.2"
88
description = "Difference-in-Differences causal inference with sklearn-like API. Callaway-Sant'Anna, Synthetic DiD, Honest DiD, event studies, parallel trends."
99
readme = "README.md"
1010
license = "MIT"

rust/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "diff_diff_rust"
3-
version = "3.3.1"
3+
version = "3.3.2"
44
edition = "2021"
55
rust-version = "1.85"
66
description = "Rust backend for diff-diff DiD library"

0 commit comments

Comments
 (0)