FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Address P2/P3: trim_weights lower>upper, R-equivalence claim, test · UtilityTools/diff-diff@f065afe · GitHub

Commit f065afe

Browse files
andcommitted
Address P2/P3: trim_weights lower>upper, R-equivalence claim, test
P2: Validate lower <= upper in trim_weights after quantile resolution. Raise ValueError when lower exceeds upper to prevent silent corruption. P3: Reword single-singleton bootstrap fallback as library-specific documented behavior (not R equivalence — R's analytical adjust uses grand-mean centering, but the bootstrap single-singleton analogue is not defined in the literature). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 5bec03c commit f065afe

4 files changed

Lines changed: 21 additions & 6 deletions

File tree

‎diff_diff/bootstrap_utils.py‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -552,8 +552,8 @@ def generate_survey_multiplier_weights_batch(
552552
pooled_cols = np.array(_singleton_cols)
553553
weights[:, pooled_cols] = pooled_weights
554554
else:
555-
# Single singleton — cannot pool, zero weight (matches R survey
556-
# package behavior where adjust with one singleton = remove).
555+
# Single singleton — cannot pool, zero weight (library-specific
556+
# fallback; bootstrap adjust with one singleton = remove).
557557
import warnings
558558

559559
warnings.warn(
@@ -684,8 +684,8 @@ def generate_rao_wu_weights(
684684
p = int(obs_psu[idx])
685685
rescaled[idx] = base_weights[idx] * psu_scale_map.get(p, 1.0)
686686
else:
687-
# Single singleton — cannot pool, keep base weights (matches R
688-
# survey package: adjust with one singleton = remove).
687+
# Single singleton — cannot pool, keep base weights (library-specific
688+
# fallback; bootstrap adjust with one singleton = remove).
689689
import warnings
690690

691691
warnings.warn(

‎diff_diff/prep.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1280,6 +1280,12 @@ def trim_weights(
12801280
raise ValueError(f"quantile must be in (0, 1), got {quantile}")
12811281
upper = float(np.nanquantile(w, quantile))
12821282

1283+
if upper is not None and lower is not None and lower > upper:
1284+
raise ValueError(
1285+
f"lower ({lower}) must be <= upper ({upper}). "
1286+
f"When using quantile, the resolved upper cap may be below lower."
1287+
)
1288+
12831289
if upper is not None:
12841290
w = np.minimum(w, upper)
12851291
if lower is not None:

‎docs/methodology/REGISTRY.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2222,8 +2222,9 @@ ContinuousDiD, EfficientDiD):
22222222
ContinuousDiD, EfficientDiD) and Rao-Wu bootstrap (SunAbraham, SyntheticDiD, TROP).
22232223
FPC scaling is skipped for pooled singletons (conservative). When only one singleton
22242224
stratum exists total, pooling is not possible — the singleton contributes zero bootstrap
2225-
variance (same as `remove`), with a `UserWarning` emitted. This matches R's `survey`
2226-
package behavior. Reference: Rust & Rao (1996).
2225+
variance (same as `remove`), with a `UserWarning` emitted. This is a library-specific
2226+
documented fallback (R's analytical `adjust` uses grand-mean centering, but the bootstrap
2227+
analogue for a single singleton is not defined in the literature). Reference: Rust & Rao (1996).
22272228
- **Deviation from R:** For the no-FPC case (`m_h = n_h - 1`), this matches R
22282229
`survey::as.svrepdesign(type="subbootstrap")`. The FPC-adjusted resample size
22292230
`m_h = round((1-f_h)*(n_h-1))` follows Rao, Wu & Yue (1992) Section 3.

‎tests/test_survey_phase8.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,6 +1201,14 @@ def test_trim_quantile_with_nan(self):
12011201
assert np.isfinite(result["w"].iloc[0])
12021202
assert np.isfinite(result["w"].iloc[4])
12031203

1204+
def test_trim_lower_exceeds_upper_raises(self):
1205+
"""lower > upper raises ValueError."""
1206+
from diff_diff.prep import trim_weights
1207+
1208+
data = pd.DataFrame({"w": [1.0, 5.0, 10.0]})
1209+
with pytest.raises(ValueError, match="lower.*<=.*upper"):
1210+
trim_weights(data, "w", upper=5.0, lower=6.0)
1211+
12041212

12051213
# ===========================================================================
12061214
# 8e-iii: ImputationDiD Pretrends + Survey

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL