Skip to content

Commit 8ccfadf

Browse files
igerberclaude
andcommitted
Address PR #396 R1 review (1 P1 + 1 P2)
P1: troubleshooting:block17/block18 are not actually context-dependent within docs/troubleshooting.rst — the page has no prior HAD est/results binding before the new HAD Issues section. Suppressing NameError on those IDs hid broken docs (the readers' copy-paste would fail) while CI stopped reporting the failure. Fix: rewrote both snippets self-contained, mirroring the inline HAD- shape panel construction pattern from PR #396's r_comparison:block6 fix and the upstream choosing_estimator:block7 fix in 55d7a27. - block17 (Resolved estimand inspection): inline 200-unit / 5-period HAD panel with beta(0.5, 1.0) doses — d.min() near zero so the Design 1' (continuous_at_zero) detection rule fires and `target_ parameter == "WAS"` for the inspection demo. - block18 (Mass-point design selected): inline 200-unit / 5-period HAD panel where 30% of units share d_lower=0.5 so the modal-fraction-at-d.min() > 2% threshold trips and `_detect_design` resolves to mass_point. Verified locally: design='mass_point', target_parameter='WAS_d_lower'. Both snippets now define `est` and `results` locally; removed troubleshooting:block17 and troubleshooting:block18 from _CONTEXT_DEPENDENT_SNIPPETS. P2: r_comparison:block6 was already in _CONTEXT_DEPENDENT_SNIPPETS from a pre-existing entry, but PR #396's earlier rewrite already made it self-contained. The stale allowlist entry would mask future NameError regressions. Removed. Verification: PYTHONPATH=. DIFF_DIFF_BACKEND=python pytest tests/test_doc_snippets.py reports 111 passed, 4 skipped, 0 failed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 8ecbaf7 commit 8ccfadf

2 files changed

Lines changed: 55 additions & 8 deletions

File tree

docs/troubleshooting.rst

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -498,17 +498,36 @@ is meaningfully positive relative to the dose scale.
498498

499499
.. code-block:: python
500500
501-
# Inspect the dose support before fitting
502501
import numpy as np
503-
d = data['dose'].to_numpy()
504-
print(data['dose'].describe())
502+
import pandas as pd
503+
from diff_diff import HeterogeneousAdoptionDiD
504+
505+
# Build a HAD-shape panel: D=0 in pre-periods (t < F), D > 0 only at F+.
506+
rng = np.random.default_rng(42)
507+
G, F, T = 200, 4, 5
508+
doses = rng.beta(0.5, 1.0, size=G)
509+
rows = []
510+
for g in range(G):
511+
for t in range(1, T + 1):
512+
y = (rng.normal()
513+
+ (doses[g] + doses[g] ** 2) * (t >= F)
514+
+ rng.normal(0, 0.5))
515+
d = doses[g] if t >= F else 0.0
516+
rows.append({'unit': g, 'period': t, 'y': y, 'dose': d})
517+
had_data = pd.DataFrame(rows)
518+
519+
# Inspect the dose support before fitting
520+
d = had_data['dose'].to_numpy()
521+
print(had_data['dose'].describe())
505522
print(f"d.min() = {d.min():.6g}; "
506523
f"0.01 * median(|d|) = {0.01 * np.median(np.abs(d)):.6g}; "
507524
f"d.min() < threshold => Design 1' (WAS)")
508525
509526
# Check the resolved estimand after fitting
510-
results = est.fit(data, outcome_col='y', unit_col='unit',
511-
time_col='period', dose_col='dose')
527+
est = HeterogeneousAdoptionDiD()
528+
results = est.fit(had_data, outcome_col='y', unit_col='unit',
529+
time_col='period', dose_col='dose',
530+
aggregate='event_study')
512531
print(f"Resolved: {results.target_parameter}")
513532
514533
# If you intend Design 1' but `d.min()` exceeds the threshold, verify
@@ -536,6 +555,37 @@ SE path is not used here).
536555

537556
.. code-block:: python
538557
558+
import numpy as np
559+
import pandas as pd
560+
from diff_diff import HeterogeneousAdoptionDiD
561+
562+
# Build a HAD panel with a heavy boundary mass at d_lower so the
563+
# modal fraction at d.min() exceeds 2% and `_detect_design` resolves
564+
# to `mass_point`.
565+
rng = np.random.default_rng(42)
566+
G, F, T = 200, 4, 5
567+
d_lower = 0.5
568+
mass_frac = 0.3
569+
doses = np.where(
570+
rng.uniform(size=G) < mass_frac,
571+
d_lower,
572+
rng.uniform(d_lower + 0.1, 2.0, size=G),
573+
)
574+
rows = []
575+
for g in range(G):
576+
for t in range(1, T + 1):
577+
y = (rng.normal()
578+
+ doses[g] * (t >= F)
579+
+ rng.normal(0, 0.5))
580+
d = doses[g] if t >= F else 0.0
581+
rows.append({'unit': g, 'period': t, 'y': y, 'dose': d})
582+
had_data = pd.DataFrame(rows)
583+
584+
est = HeterogeneousAdoptionDiD()
585+
results = est.fit(had_data, outcome_col='y', unit_col='unit',
586+
time_col='period', dose_col='dose',
587+
aggregate='event_study')
588+
539589
# Inspect the resolved design
540590
print(f"Design: {results.design}") # 'mass_point' here
541591

tests/test_doc_snippets.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,11 +365,8 @@ def _restore_datasets_module():
365365
"r_comparison:block2",
366366
"r_comparison:block3",
367367
"r_comparison:block4",
368-
"r_comparison:block6",
369368
"r_comparison:block7",
370369
"troubleshooting:block8",
371-
"troubleshooting:block17",
372-
"troubleshooting:block18",
373370
}
374371

375372

0 commit comments

Comments
 (0)