Skip to content

Commit 73cf984

Browse files
chore(release): bump version to 0.7.1
DID-focused polish release. See CHANGELOG.md [0.7.1] for the full list of additions and fixes: - ETWFE full parity with R etwfe (xvar multi, panel=False, cgroup, etwfe_emfx with four aggregations + include_leads). - One-call method-robustness workflow (did_summary + plot + export bundle via did_report). - Twelve review-round fixes across blocker (C1-C5) and high-severity (H1-H7) categories; regression tests locked in. 27 DID-focused pytest cases pass (tests/test_did_summary.py). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 80768a2 commit 73cf984

3 files changed

Lines changed: 96 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,98 @@
22

33
All notable changes to StatsPAI will be documented in this file.
44

5+
## [0.7.1] - 2026-04-15
6+
7+
DID-focused polish release. Brings the Wooldridge (2021) ETWFE
8+
implementation to full feature parity with the R `etwfe` package,
9+
adds a one-call method-robustness workflow, and closes 12 issues
10+
uncovered by an internal code review round. All 27 new / updated
11+
DID tests pass (`pytest tests/test_did_summary.py`).
12+
13+
### Added — ETWFE full parity with R `etwfe`
14+
15+
- **`sp.etwfe()` explicit API** aligned with R `etwfe` (McDermott 2023)
16+
naming. Thin alias over `wooldridge_did()` with a full argument-
17+
mapping table in the docstring.
18+
- **`xvar=` covariate heterogeneity** (single string or list of names).
19+
Adds per-cohort × post × `(x_j − mean(x_j))` interactions; `detail`
20+
gains `slope_<x>` / `slope_<x>_se` / `slope_<x>_pvalue` columns.
21+
Baseline ATT is reported at the sample means of every covariate.
22+
- **`panel=False` repeated cross-section mode** — replaces unit FE
23+
with cohort + time dummies (R `etwfe(ivar=NULL)` equivalent).
24+
- **`cgroup='nevertreated'`** — per-cohort regressions restricted to
25+
(cohort g) ∪ (never-treated); cohort-size-weighted aggregation
26+
(R `etwfe(cgroup='never')` equivalent). Default `'notyet'` preserves
27+
prior ETWFE behaviour.
28+
- **`sp.etwfe_emfx(result, type=…)`** — R `etwfe::emfx`-equivalent
29+
four aggregations: `'simple'`, `'group'`, `'event'`, `'calendar'`.
30+
`include_leads=True` returns full event-time output including pre-
31+
treatment leads for pre-trend inspection (`rel_time = -1` is the
32+
reference category).
33+
34+
### Added — one-call DID method-robustness workflow
35+
36+
- **`sp.did_summary()`** — fits five modern staggered-DID estimators
37+
(CS, SA, BJS, ETWFE, Stacked) to the same data and returns a tidy
38+
comparison table with per-method (estimate, SE, p, 95 % CI). Mean
39+
across methods + cross-method SD flag method-sensitivity of results.
40+
- **`include_sensitivity=True`** — attaches the Rambachan-Roth (2023)
41+
breakdown `M*` to the CS row, giving a three-way robustness readout
42+
in a single call.
43+
- **`sp.did_summary_plot()`** — forest plot of per-method estimates
44+
with cross-method mean line; `sort_by='estimate'` supported.
45+
- **`sp.did_summary_to_markdown()` / `_to_latex()`** — publication-
46+
ready exports (GFM tables / booktabs LaTeX with auto-escaped
47+
ampersands).
48+
- **`sp.did_report(save_to=dir)`** — one-call bundle that writes
49+
`did_summary.txt` / `.md` / `.tex` / `.png` / `.json` to a folder.
50+
51+
### Fixed — 12 issues from the internal code review
52+
53+
Blockers (C-severity):
54+
55+
- `etwfe(xvar=…)` now raises a clear `ValueError` when the covariate
56+
is all-NaN or (near-)constant. Previously returned `n_obs = 0,
57+
estimate = 0` silently.
58+
- `etwfe(panel=False, cgroup='nevertreated')` now raises a crisp
59+
`NotImplementedError` instead of silently falling back to
60+
`'notyet'`.
61+
- `did_summary` now validates column names up front (raises
62+
`KeyError` listing missing columns) and only catches narrow
63+
estimator-side exceptions inside the fit loop; user typos in
64+
`controls=` / `cluster=` surface as proper errors.
65+
- `did_summary` results round-trip cleanly through stdlib
66+
serialisation (`DIDSummaryResult(CausalResult)` subclass with a
67+
real `.summary()` method, replacing the prior closure-bound
68+
instance attribute).
69+
70+
High-severity:
71+
72+
- `etwfe_emfx(type='event'/'calendar')` now computes SEs via the
73+
delta method on the stored event-study vcov instead of the
74+
independent-coefficient approximation. `model_info['se_method']`
75+
advertises which path was used.
76+
- `etwfe_emfx(type='group')` headline `se` / `pvalue` / `ci` are now
77+
populated (match the underlying fit's overall ATT exactly).
78+
- Validation for `did_summary_plot` / `_to_markdown` / `_to_latex`
79+
aligned on a single sentinel `model_info['_did_summary_marker']`.
80+
- `_etwfe_never_only` no longer leaves a `_ft_cache` helper column
81+
on the caller's DataFrame.
82+
- Slope indexing in `_etwfe_with_xvar` is now name-keyed
83+
(`coef_index` dict); regression test verifies swapping
84+
`xvar=['x1','x2']` vs `['x2','x1']` produces identical slopes per
85+
name.
86+
- `etwfe(panel=False)` with rank-deficient designs emits a
87+
`RuntimeWarning` pointing at concrete remedies (previously fell
88+
through to `pinv` silently).
89+
90+
### Tests
91+
92+
- New test module `tests/test_did_summary.py` — 27 cases covering
93+
consistency with direct estimator calls, export formats, forest
94+
plot rendering, `etwfe_emfx` round-trips, xvar / panel / cgroup
95+
options, the 12 review fixes, and the `include_leads` mode.
96+
597
## [0.7.0] - 2026-04-14
698

799
Focused release reaching feature parity with the R `did` / `HonestDiD`

pyproject.toml

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

55
[project]
66
name = "StatsPAI"
7-
version = "0.7.0"
7+
version = "0.7.1"
88
description = "The Agent-Native Causal Inference & Econometrics Toolkit for Python"
99
readme = "README.md"
1010
license = {text = "MIT"}

src/statspai/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
>>> sp.outreg2(result, filename="results.xlsx")
2323
"""
2424

25-
__version__ = "0.7.0"
25+
__version__ = "0.7.1"
2626
__author__ = "Bryce Wang"
2727
__email__ = "bryce@copaper.ai"
2828

@@ -74,13 +74,15 @@
7474
from .spatial import (
7575
sar, sem, sdm, slx, sac, SpatialModel,
7676
sar_gmm, sem_gmm, sarar_gmm,
77+
gwr, mgwr, gwr_bandwidth,
7778
W, queen_weights, rook_weights, knn_weights,
7879
distance_band, kernel_weights, block_weights,
7980
moran, moran_local, geary, getis_ord_g, getis_ord_local, join_counts,
8081
moran_plot, lisa_cluster_map,
8182
lm_tests, moran_residuals, impacts,
8283
)
8384
from . import spatial
85+
from . import iv
8486
from .plots import binscatter, set_theme, list_themes, use_chinese, interactive, get_code
8587
from .utils import (
8688
label_var, label_vars, get_label, get_labels, describe, pwcorr, winsor, read_data,

0 commit comments

Comments
 (0)