Skip to content

Commit 9bc0341

Browse files
igerberclaude
andcommitted
Add warnings for silent cell drops and fix NaN pscore caching
- Warn when base period is outside observed panel (previously silent skip) - Warn when DDD subgroups are empty with details of which cells are missing - Zero-fill NaN logistic coefficients before caching to prevent NaN propagation on cache reuse with rank-deficient covariates Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2a44d56 commit 9bc0341

1 file changed

Lines changed: 27 additions & 2 deletions

File tree

diff_diff/staggered_triple_diff.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,14 @@ def fit(
285285
base_period_val = self._get_base_period(g, t)
286286
if base_period_val is None:
287287
continue
288-
if base_period_val not in time_to_col or t not in time_to_col:
288+
if base_period_val not in time_to_col:
289+
warnings.warn(
290+
f"Base period {base_period_val} for (g={g}, t={t}) is "
291+
"outside the observed panel. Skipping this cell.",
292+
UserWarning, stacklevel=2,
293+
)
294+
continue
295+
if t not in time_to_col:
289296
continue
290297

291298
has_never_enabled = bool(np.any(unit_cohorts == 0))
@@ -770,6 +777,21 @@ def _compute_ddd_gt_gc(
770777
n_c = int(np.sum(sub_c_mask))
771778

772779
if n_treated == 0 or n_a == 0 or n_b == 0 or n_c == 0:
780+
empty = []
781+
if n_treated == 0:
782+
empty.append(f"(S={g},Q=1)")
783+
if n_a == 0:
784+
empty.append(f"(S={g},Q=0)")
785+
if n_b == 0:
786+
empty.append(f"(S={g_c},Q=1)")
787+
if n_c == 0:
788+
empty.append(f"(S={g_c},Q=0)")
789+
warnings.warn(
790+
f"Empty subgroup(s) {', '.join(empty)} for "
791+
f"(g={g}, g_c={g_c}, t={t}). "
792+
"Comparison unidentified, skipping.",
793+
UserWarning, stacklevel=3,
794+
)
773795
return None
774796

775797
if min(n_treated, n_a, n_b, n_c) < 5:
@@ -1038,7 +1060,10 @@ def _compute_pscore(
10381060
rank_deficient_action=self.rank_deficient_action,
10391061
)
10401062
_check_propensity_diagnostics(pscore, self.pscore_trim)
1041-
pscore_cache[pscore_key] = beta_logistic
1063+
# Zero-fill NaN coefficients (from rank-deficient columns)
1064+
# before caching, so cache reuse doesn't propagate NaN.
1065+
beta_clean = np.where(np.isfinite(beta_logistic), beta_logistic, 0.0)
1066+
pscore_cache[pscore_key] = beta_clean
10421067
except (np.linalg.LinAlgError, ValueError):
10431068
if self.rank_deficient_action == "error":
10441069
raise

0 commit comments

Comments
 (0)