Skip to content

Commit 4d65f75

Browse files
igerberclaude
andcommitted
Fix HonestDiD varying-base split: use t<0/t>=0 when no reference marker
When base_period="varying" (no n_groups=0 reference marker), split at t<0/t>=0 instead of synthesizing ref_period=-1 which misclassified the real e=-1 effect. Grid validation uses gap=1 for varying (no omitted reference) vs gap=2 for universal (omitted reference). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 4073fa8 commit 4d65f75

1 file changed

Lines changed: 20 additions & 12 deletions

File tree

diff_diff/honest_did.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -670,16 +670,20 @@ def _extract_event_study_params(
670670

671671
# Infer the omitted reference period from the n_groups=0 entry
672672
# (injected by _aggregate_event_study for universal base).
673-
# Default to e=-1 if no reference found (varying base).
674-
ref_period = -1
673+
ref_period = None
675674
for t, data in results.event_study_effects.items():
676675
if data.get("n_groups", 1) == 0:
677676
ref_period = t
678677
break
679678

680-
# Split relative to the reference period, not hardcoded at 0
681-
pre_times = [t for t in rel_times if t < ref_period]
682-
post_times = [t for t in rel_times if t > ref_period]
679+
if ref_period is not None:
680+
# Universal base: split relative to the reference period
681+
pre_times = [t for t in rel_times if t < ref_period]
682+
post_times = [t for t in rel_times if t > ref_period]
683+
else:
684+
# Varying base or no reference marker: split at t < 0 / t >= 0
685+
pre_times = [t for t in rel_times if t < 0]
686+
post_times = [t for t in rel_times if t >= 0]
683687

684688
if len(pre_times) == 0:
685689
raise ValueError(
@@ -718,14 +722,18 @@ def _extract_event_study_params(
718722
else:
719723
sigma = np.diag(np.array(ses) ** 2)
720724

721-
# Validate the full event-time grid is consecutive around
722-
# the omitted reference period (exactly one gap allowed).
723-
# R's HonestDiD refuses non-consecutive grids.
725+
# Validate the full event-time grid is consecutive.
726+
# For universal base: exactly one gap for the omitted reference.
727+
# For varying base: no gap expected (pre ends at -1, post starts at 0).
724728
if pre_times and post_times:
725-
# Expected: pre_times[-1] + 1 = reference, reference + 1 = post_times[0]
726-
# So post_times[0] - pre_times[-1] should be exactly 2
727-
ref_gap = post_times[0] - pre_times[-1]
728-
has_gap = ref_gap != 2
729+
if ref_period is not None:
730+
# Universal: pre[-1]+1 = ref, ref+1 = post[0] → gap of 2
731+
ref_gap = post_times[0] - pre_times[-1]
732+
has_gap = ref_gap != 2
733+
else:
734+
# Varying: pre ends at -1, post starts at 0 → gap of 1
735+
ref_gap = post_times[0] - pre_times[-1]
736+
has_gap = ref_gap != 1
729737
elif pre_times:
730738
has_gap = False # only pre, no ref gap to check
731739
elif post_times:

0 commit comments

Comments
 (0)