Skip to content

Add multi-period DiD support#6

Merged
igerber merged 1 commit intomainfrom
claude/add-multi-period-support-OhFL8
Jan 2, 2026
Merged

Add multi-period DiD support#6
igerber merged 1 commit intomainfrom
claude/add-multi-period-support-OhFL8

Conversation

@igerber
Copy link
Copy Markdown
Owner

@igerber igerber commented Jan 2, 2026

Extend the library to optionally work across multiple time periods:

  • Add MultiPeriodDiD estimator that handles multiple pre/post periods
  • Add MultiPeriodDiDResults for period-specific and average ATT
  • Add PeriodEffect dataclass for individual period treatment effects
  • Support for period dummies and treatment × period interactions
  • Compute average ATT with proper covariance-adjusted standard errors
  • Allow custom reference period selection
  • Auto-infer post-periods when not specified (last half of periods)
  • Full support for covariates, fixed effects, and absorbed FE
  • Cluster-robust and heteroskedasticity-robust standard errors
  • Comprehensive test suite with 28 new tests (70 total passing)

Extend the library to optionally work across multiple time periods:

- Add MultiPeriodDiD estimator that handles multiple pre/post periods
- Add MultiPeriodDiDResults for period-specific and average ATT
- Add PeriodEffect dataclass for individual period treatment effects
- Support for period dummies and treatment × period interactions
- Compute average ATT with proper covariance-adjusted standard errors
- Allow custom reference period selection
- Auto-infer post-periods when not specified (last half of periods)
- Full support for covariates, fixed effects, and absorbed FE
- Cluster-robust and heteroskedasticity-robust standard errors
- Comprehensive test suite with 28 new tests (70 total passing)
@igerber igerber merged commit 88c6542 into main Jan 2, 2026
@igerber igerber deleted the claude/add-multi-period-support-OhFL8 branch January 2, 2026 15:40
igerber pushed a commit that referenced this pull request Jan 4, 2026
Revised review reflects:
- #1, #4 verified as non-issues (correct by design)
- #3, #5, #6, #8, #13 addressed in commit e40d6b4
- Updated recommendation to approve and merge
- Remaining items are low-priority style suggestions for future PRs
igerber added a commit that referenced this pull request Apr 18, 2026
Addresses axis B findings #6 and #7 from the silent-failures audit:
trop_global.py:448 outer alternating-min loop, trop_global.py:466
hard-coded range(20) inner FISTA loop, and trop_local.py:680
alternating-minimization loop all exited silently on max_iter
exhaustion, returning the current iterate as if converged.

- trop_global._solve_global_with_lowrank: thread a converged flag through
  the outer loop; count non-convergence events from the inner FISTA and
  surface the count in the outer warning for diagnostic context. One
  warn_if_not_converged call per solver invocation.
- trop_local._estimate_model: thread a converged flag through the outer
  alternating-min loop; call warn_if_not_converged on exhaustion.
- REGISTRY updated under TROP.

New TestTROPConvergenceWarnings class (4 tests) exercises both global
and local paths with forced non-convergence (max_iter=1, tol=1e-15)
and a convergent negative control.

Notable: the default TROP local config (max_iter=100, tol=1e-6) does
not converge within max_iter on typical synthetic panels, so this PR
surfaces a previously silent non-convergence that affected routine
user fits. No numerical change in the returned iterate; the warning
is additive.

Axis-B regression-lint baseline: 5 -> 2 silent range(max_iter) loops
remaining (minor loops in honest_did/power not yet addressed).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
igerber added a commit that referenced this pull request Apr 19, 2026
P0: bias_corrected_local_linear now routes the CI through
`safe_inference()` so degenerate cases with `se_robust <= 0` or
non-finite `se_robust` (e.g., exact-fit / constant-y) return
`(NaN, NaN)` rather than a misleading zero-width or infinite CI.
Matches the repo-wide inference contract (CLAUDE.md Key Design
Pattern #6).

P1: Auto-bandwidth path now calls `lpbwselect_mse_dpi` directly
with `cluster`, `vce`, and `nnmatch` forwarded. Previously it went
through `mse_optimal_bandwidth` which hard-codes unclustered / nn /
nnmatch=3, silently mismatching the downstream `lprobust` fit's
reported estimator.

Tests added: TestNaNSafeCI (constant-y + near-zero-SE) and
TestAutoBandwidthForwardsParameters (cluster+auto, vce='hc1'+auto,
nnmatch=5+auto), all asserting the selected bandwidth changes when
the corresponding parameter changes (catches silent fallback).

Also: suppress spurious BLAS FPE warnings in lprobust_bw's hc/hc2/hc3
branch (numpy issue #21432 pattern), newly reachable via the
wired-through vce='hc1' auto-bandwidth path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
igerber added a commit that referenced this pull request Apr 22, 2026
Close BR/DR gap #6: target-parameter block in schemas
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants