mixle.inference.event_study module¶
Hierarchical within-subject event-study associations and identified DiD estimates.
Many SUBJECTS are each observed BEFORE and AFTER a known event time – an exposure with a confirmed timestamp (on social data, a retweet: the act proves the content was seen, and dates it). We estimate whether, and how much, the event shifts each subject’s generative activity, then pool those shifts into a population effect with calibrated uncertainty.
A treated/control split computes the usual difference in changes. It becomes an identified causal
difference-in-differences estimate only when the caller supplies an
EventStudyIdentification receipt. Without that receipt the calculation is explicitly labeled
as a before/after or treated/control association.
Two stages, exact/closed-form where the family permits:
per-subject effect – from the activity family’s sufficient statistics on the pre and post windows: a Gaussian mean-shift (
gaussian_effect) or a Poisson log-rate shift for event counts (poisson_lograte_effect), each with its sampling variance.pooling, weighted by the estimand – the ASSOCIATION paths report a random-effects (DerSimonian-Laird) precision-weighted summary with between-subject heterogeneity
tau^2and empirical-Bayes shrinkage; the IDENTIFIED DiD path instead uses equal-subject-weight (arithmetic) group means with Student-t/Welch inference, because the ATT is an arithmetic mean and precision weighting estimates a different quantity under effect-variance dependence (STAT-RR21-01/STAT-RR22-07). DL diagnostics ride along in both modes.
Within-subject differencing removes additive time-invariant subject effects and a treated/control
contrast removes additive shocks common to both groups. Neither fact alone establishes parallel trends,
exchangeability, consistency, positivity, or absence of interference. tipping_drift() provides a
simple sensitivity calculation; it is not a substitute for an identification argument.
- class EventStudyIdentification(design_evidence, parallel_trends_evidence, exchangeability, positivity, consistency, no_interference, no_anticipation, sensitivity_analysis=None)[source]
Bases:
objectAuditable assumptions for interpreting a treated/control contrast as causal DiD.
- Parameters:
- gaussian_effect(pre, post)[source]
Per-subject mean shift and its (Welch) sampling variance from pre/post activity samples.
- poisson_lograte_effect(k_pre, t_pre, k_post, t_post)[source]
Per-subject log activity-rate shift
log(rate_post) - log(rate_pre)for event counts over windows.k_*are event counts,t_*the window durations (or exposures). The estimate is the Haldane formlog((k_post + 0.5)/t_post) - log((k_pre + 0.5)/t_pre)with the matching plug-in variance1/(k_post + 0.5) + 1/(k_pre + 0.5)– STRICTLY POSITIVE counts only: a zero-count window is REFUSED with a pointer topoisson_pooled_rate_ratio()(STAT-RR17-09: at zero the Haldane offset is pure correction, not rate information, and pooling it drove a true null to p = 1.37e-12). An earlier version of this docstring claimed zero counts were made finite and quoted a1/kvariance; neither matched the executable contract (STAT-P20-03).
- poisson_lograte_effects(k_pre, t_pre, k_post, t_post)[source]
Per-subject log rate-ratio effects for Gaussian pooling, via the CONDITIONAL (binomial) route.
Conditioning is what makes the heterogeneous estimand reachable. Given a subject’s total
n_i = k_pre,i + k_post,iand the common exposure ratior = t_post/t_pre,k_post,i | n_i ~ Binomial(n_i, p_i)withlogit(p_i) = log(theta_i) + log(r)– the subject’s BASELINE RATE lambda_i cancels exactly, so nothing here assumes rate homogeneity. Two earlier constructions failed measurably on that point (pass 19 and its pass-20 replay):Count-estimated per-subject variances (
1/(k+0.5)forms) let inverse-variance weights correlate with the effects (measured corr(1/v, y) = -0.72; weighted true-null mean -0.150; z = -7.8 at n = 1000, 100% false rejection, flat in n).Debiasing at the pooled ARM means fixed the homogeneous fixture but assumed every subject shares one baseline rate: with half the subjects at rate 0.1 and half at 9.1 (exposures 1:3) and every true ratio exactly 1, it rejected 400/400 with mean z -20.75/-65.62 at n = 1e3/1e4 (STAT-RR19-03) – the nonlinear Haldane bias must be removed at each subject’s own law, which is unknowable at the rate scale and EXACT at the conditional scale.
Here each effect is the Haldane conditional logit
log((k_post+0.5)/(k_pre+0.5)) - log(r), debiased by the exact pmf-summation bias of that statistic underBinomial(n_i, p_bar)(p_bar= pooled working proportion; under the null every subject’sp_iequals it exactly, whatever the baseline rates), with the exact conditional variance at(n_i, p_bar)as the pooling variance – a function ofn_ialone givenp_bar, so weights cannot correlate with the per-subject noise. Zero-total subjects (n_i = 0) carry no information about a rate ratio and are excluded from the returned arrays.Measured on the pass-20 fixtures through the real DL pool: heterogeneous 0.1/9.1 (r = 3) true null rejects 0.055 at n = 1000 (400 reps) and 0.0417 at n = 10000 (1200 reps); the milder 2/8 (r = 2) mixture 0.018; the homogeneous 4.6 (r = 3) fixture 0.048; power at a true common ratio of 1.3 on the 2/8 mixture is 1.000. The 4.0 arm-mean floor remains as the pooled-z normal-approximation gate; below it use poisson_pooled_rate_ratio, exact at any sparsity for the common-ratio estimand.
Returns
(effects, variances, selection_receipt). The receipt records the POPULATION this route can speak for (STAT-RR22-01): zero-total subjects are excluded because the conditional likelihood is empty for them, and that exclusion is OUTCOME-DEPENDENT – under extreme baseline heterogeneity (rates 0.01 and 10, true effects +1/-1 with all-subject ATT exactly zero), event-free low-rate subjects vanished differentially and the retained-subject contrast read -0.94 with 100% rejection while silently wearing the all-treated label. Hand the receipt tohierarchical_event_study()so the estimand names the population actually estimated.
- poisson_pooled_rate_ratio(k_pre, t_pre, k_post, t_post, *, alpha=0.05)[source]
EXACT conditional inference for a COMMON post/pre rate ratio – valid at any sparsity.
Sums the counts over subjects: with a common ratio
thetaand a constant per-subject exposure ratior = t_post/t_pre,K_post | K_post + K_pre = Nis exactlyBinomial(N, theta*r / (1 + theta*r)), so the test oftheta = 1is an exact binomial test and the CI is the Clopper-Pearson interval transformed back to the ratio scale (STAT-RR17-09’s sparse-regime route). ESTIMAND: the common ratio – a deliberate reduction from the per-subject random-effects mean, which sparse counts cannot support; heterogeneity across subjects is NOT estimated here.
- class EventStudyResult(effect, se, z, p_value, ci, treated_mean, treated_se, control_mean, control_se, tau2_treated, n_treated, n_control, shrunk_treated, estimand, identified, interpretation, identification, ci_level=0.95, n_treated_population=None, n_control_population=None, df=None)[source]
Bases:
objectPooled change contrast with explicit causal-identification metadata.
- Parameters:
effect (float)
se (float)
z (float)
p_value (float)
treated_mean (float)
treated_se (float)
control_mean (float | None)
control_se (float | None)
tau2_treated (float)
n_treated (int)
n_control (int)
shrunk_treated (ndarray)
estimand (str)
identified (bool)
interpretation (str)
ci_level (float)
n_treated_population (int | None)
n_control_population (int | None)
df (float | None)
- hierarchical_event_study(treated_effects, treated_vars, control_effects=None, control_vars=None, *, alpha=0.05, identification=None, treated_selection=None, control_selection=None)[source]
Pool per-subject changes into an association or explicitly identified DiD estimate.
*_effects/*_varsare per-subject changes and sampling variances. A control group makes the numeric contrasttreated_mean - control_mean. It is labeled an ATT only when a completeidentificationreceipt is attached; otherwise it remains a treated/control change association.THE WEIGHTING FOLLOWS THE ESTIMAND (STAT-RR21-01). The ATT is the treated-population ARITHMETIC mean of unit effects, so the identified path uses equal-subject-weight group means with their empirical standard errors (
sd/sqrt(n)per group – per-subject sampling noise is inside the observed spread, so this SE covers noise and heterogeneity together). DerSimonian-Laird precision weighting estimates a DIFFERENT quantity whenever effect size and sampling variance are dependent – with treated unit effects evenly split between +1 and -1 (true ATT exactly 0), precision weights track the totals that track the effects, and the DL contrast reported +0.197 with 92-100% rejection at nominal 5%. DL pooling remains what the ASSOCIATION paths report (a precision-weighted summary, named as such), and its tau^2 / shrunk-effect diagnostics are attached in both modes.THE POPULATION FOLLOWS THE RECEIPT (STAT-RR22-01). The conditional Poisson route excludes zero-total subjects – an OUTCOME-DEPENDENT exclusion, so its arithmetic contrast estimates the event-positive population, not all treated units (measured: with baseline rates 0.01/10 and true all-subject ATT exactly zero, differential exclusion drove the retained-subject contrast to -0.94 with 100% rejection). Pass each arm’s
selection_receipt(the third return ofpoisson_lograte_effects()); when any subjects were excluded, the identified estimand names the event-positive population explicitly and the result carries the original denominators. Refusing to attach the all-treated label is the point: this route cannot identify it.IDENTIFIED-PATH UNCERTAINTY (STAT-RR22-02): the reference is Student-t with Welch- Satterthwaite degrees of freedom (a normal quantile rejected 18.96% at nominal 5% with 2 subjects per arm), the empirical variance is FLOORED by the supplied per-subject sampling variances (
mean(vars)/nper arm – a degenerate all-identical-estimates arm used to report SE 0 and the contradictionCI=[1,1]withp=1), the p-value and CI come from the same t reference, and subjects are assumed INDEPENDENT units: with 10 clusters repeated 10 times per arm, rejection measured 55.6% at nominal 5% – aggregate to cluster-level effects first.- Parameters:
- Return type:
EventStudyResult
- tipping_drift(result)[source]
Sensitivity bound: the unmeasured differential drift that would explain the effect away.
Within-subject DiD is unbiased only if, absent treatment, treated and control would have drifted equally. This returns the differential drift
delta(in effect units) that nullifies the estimate (= effect) and the value that pushes the result’s OWN confidence interval through zero – at the result’s own level and reference (STAT-RR23-03: a hard-coded Normal 1.96 disagreed with the identified path’s Welch-t interval edge, 0.1235 vs the actual 0.0604, and silently priced a 90% result at 95%). Larger = more robust.- Parameters:
result (EventStudyResult)
- Return type: