Skip to content

Commit 1aa6d16

Browse files
igerberclaude
andcommitted
Address CI review P0/P1 findings for PR #237
P0: Rao-Wu census FPC (f_h >= 1) now checked before m_h, keeping original weights for census strata instead of unreachable guard P1: ContinuousDiD ACRT_glob bootstrap uses survey-weighted dpsi_mean P1: Document lonely_psu="adjust" rejection in REGISTRY Phase 6 section P1: Document TROP no-strata pseudo-strata behavior in REGISTRY Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent b4a3aca commit 1aa6d16

3 files changed

Lines changed: 17 additions & 6 deletions

File tree

diff_diff/bootstrap_utils.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -605,15 +605,14 @@ def generate_rao_wu_weights(
605605
f"({n_h}). FPC must be >= number of PSUs."
606606
)
607607
f_h = n_h / N_h
608+
if f_h >= 1.0:
609+
# Census stratum — keep original weights (zero variance)
610+
rescaled[mask_h] = base_weights[mask_h]
611+
continue
608612
m_h = max(1, round((1.0 - f_h) * (n_h - 1)))
609613
else:
610614
m_h = n_h - 1
611615

612-
if m_h == 0:
613-
# Full census — keep original weights
614-
rescaled[mask_h] = base_weights[mask_h]
615-
continue
616-
617616
# Draw m_h PSUs with replacement
618617
drawn_indices = rng.choice(n_h, size=m_h, replace=True)
619618
counts = np.bincount(drawn_indices, minlength=n_h)

diff_diff/continuous_did.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1438,7 +1438,11 @@ def _bootstrap_gt_cell(gt, info):
14381438
mean_dy_treated_pert = (w_treated @ att_glob_score) / n_t
14391439
att_glob_b = att_glob_gt + mean_dy_treated_pert - mu_0_pert
14401440

1441-
dpsi_mean = np.mean(dPsi_treated, axis=0)
1441+
if sw_treated is not None:
1442+
sw_norm = sw_treated / sw_treated.sum()
1443+
dpsi_mean = sw_norm @ dPsi_treated
1444+
else:
1445+
dpsi_mean = np.mean(dPsi_treated, axis=0)
14421446
acrt_glob_b = delta_beta @ dpsi_mean
14431447

14441448
return att_d_b, acrt_d_b, att_glob_b, acrt_glob_b, info.get("acrt_glob", 0.0)

docs/methodology/REGISTRY.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1961,6 +1961,10 @@ ContinuousDiD, EfficientDiD):
19611961
Without FPC: `m_h = n_h - 1`. With FPC: `m_h = max(1, round((1 - f_h) * (n_h - 1)))`.
19621962
Rescaled weight: `w*_i = w_i * (n_h / m_h) * r_hi` where `r_hi` = count of PSU *i* drawn.
19631963
- **Note:** FPC enters through the resample size `m_h`, not as a post-hoc scaling factor.
1964+
When `f_h >= 1` (census stratum), observations keep original weights (zero variance).
1965+
- **Note:** Bootstrap paths support `lonely_psu="remove"` and `"certainty"` only.
1966+
`lonely_psu="adjust"` raises `NotImplementedError` for survey-aware bootstrap;
1967+
use analytical inference for designs requiring `adjust` semantics.
19641968
- **Deviation from R:** R `survey::as.svrepdesign(type="subbootstrap")` uses the same
19651969
formula. Our implementation matches.
19661970

@@ -1978,6 +1982,10 @@ ContinuousDiD, EfficientDiD):
19781982
creates pseudo-strata as `(survey_stratum x treatment_group)` for Rao-Wu resampling.
19791983
This preserves both survey variance structure and treatment ratio. Survey df computed
19801984
from pseudo-strata structure.
1985+
- **Note:** When `survey_design.strata` is None but PSU/FPC trigger full-design bootstrap,
1986+
TROP uses treatment group (treated vs control) as pseudo-strata for Rao-Wu resampling
1987+
to preserve treatment ratio. FPC is applied within these pseudo-strata. This matches
1988+
TROP's existing treatment-stratified resampling pattern.
19811989

19821990
---
19831991

0 commit comments

Comments
 (0)