You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Delete the private pandas _iterative_demean twins; covariate/lead paths now
call demean_by_groups (factorize-once + bincount + optional Rust kernel,
group order [time, unit] preserving the historical sweep). Replace both
_iterative_fe bodies with a shared bincount Gauss-Seidel helper
(utils._iterative_fe_solve, modeled on spillover._iterative_fe_subset);
zero-total-weight groups get NaN FE (keys retained) instead of 0/0 NaN
poisoning. Fixes covariate + zero-weight replicate designs (JK1/BRR):
previously ALL replicate refits failed -> NaN SE + non-convergence warning
storm; main fits with zero-weight rows raised opaque ValueError.
TwoStageDiD stage-2 nan-ytilde warning suppressed inside replicate closures
only (warn_nan=False); main-fit warning unchanged. max_iter modernized
100 -> 10_000. REGISTRY notes rewritten; TODO row resolved with two
follow-up rows (spillover migration, lead-path snap guard).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X4AzrFUMqJxcUumSH31mSr
|`SpilloverDiD` sparse cKDTree path for the staggered nearest-treated-distance helper (mirrors the static helper's sparse branch). `_compute_nearest_treated_distance_staggered` always builds dense `(n_units, n_treated_by_onset)` matrices per cohort; add a sparse branch gated on `n > _CONLEY_SPARSE_N_THRESHOLD`. |`spillover.py`| Wave B | Mid | Low |
52
52
|`HeterogeneousAdoptionDiD` Phase 3 Stute: Appendix-D vectorized form replaces the per-iteration OLS refit with a single precomputed `M = I - X(X'X)^{-1}X'` applied to `eps*eta` (~2× faster, functionally identical). Shipped the literal-refit form to match paper text. |`had_pretests.py::stute_test`| Phase 3 | Mid | Low |
53
53
| Multiplier-bootstrap weight chunking (CallawaySantAnna, EfficientDiD, and HAD — all wired through `diff_diff/bootstrap_chunking.py`) covers the **unstratified** survey-PSU generation (the default unit-level bootstrap — `cluster=None`, equivalently `cluster="unit"` — the large-`n_units` OOM case). Remaining gap: the **stratified** survey-PSU generator (`generate_survey_multiplier_weights_batch`, per-stratum + lonely-PSU pooling + FPC) still materializes the full `(n_bootstrap × n_psu)` matrix (consumed via sliced blocks). Stratified designs have few PSUs so this rarely OOMs; tile per-stratum generation over draws (each stratum's draws are independent → contiguous draw-blocks reproduce the stream bit-identically) if a large-PSU stratified design hits memory. |`diff_diff/bootstrap_chunking.py::iter_survey_multiplier_weight_blocks`| follow-up | Mid | Low |
54
-
|`ImputationDiD._iterative_demean` (`imputation.py:1064`) and its near-identical twin `TwoStageDiD._iterative_demean` (`two_stage.py:2201`) rebuild a `pd.Series`+`groupby().transform()` every alternating-projection iteration. Precompute the unit/time group codes once and use `np.bincount` for the per-iteration group means. **Not bit-identical** on pandas 3.0 (`np.bincount` is naive accumulation; pandas' `group_mean` is Kahan-compensated → ~5.8e-11, the same order as the demean's `tol=1e-10`), so this needs a tolerance/REGISTRY-Note treatment + golden re-validation. Modest peak effect (the per-iteration Series are transient), analytical-path-only (the bootstrap reuses #562's cached projection). Optimize both twins together (cross-surface-twins). |`imputation.py`, `two_stage.py`| PR-C deferral | Mid | Low |
54
+
| Migrate `spillover._iterative_fe_subset` onto the shared `diff_diff.utils._iterative_fe_solve` (same Gauss-Seidel-on-codes recursion, specialized to a masked Butts subsample; ImputationDiD/TwoStageDiD already route through the shared helper — this takes the FE-solver copy count from 2 to 1). Preserve the SpilloverDiD positive-weight/NaN-FE REGISTRY contract and `_FE_ITER_MAX=100` budget (or align it to 10k with a REGISTRY note). |`spillover.py`| demean-modernization | Mid | Low |
55
+
| Adopt `snap_absorbed_regressors` (FE-spanned regressor two-stage snap + LSMR confirmation) on the ImputationDiD lead-indicator path — lead columns are the most plausible FE-spanned regressors, and the truncated-MAP-iterate exposure documented at `utils.py` applies; today only `solve_ols` rank detection guards it. Behavior change beyond the demean-modernization refactor, so deferred from that PR. |`imputation.py::_compute_lead_coefficients`| demean-modernization | Mid | Low |
0 commit comments