statspai.principal_strat¶
principal_strat ¶
Principal Stratification (Frangakis & Rubin 2002).
Principal strata classify units by the joint potential values of a post-treatment variable (e.g. compliance type or survival status). Methods provided:
principal_strat(..., method='monotonicity')— sharp bounds on complier/always-taker/never-taker ATEs under monotonicity (Angrist, Imbens & Rubin 1996; Abadie 2002) + point-identified LATE.principal_strat(..., method='principal_score')— covariate- based weighting estimator (Jo & Stuart 2009; Ding & Lu 2017) that point-identifies stratum-specific effects when principal ignorability holds.
Also ships :func:survivor_average_causal_effect (SACE bounds —
Zhang & Rubin 2003) as a specialized entry point for the classical
truncation-by-death problem.
PrincipalStratResult
dataclass
¶
Bases: ResultProtocolMixin
Principal stratification result.
Attributes:
| Name | Type | Description |
|---|---|---|
method |
str
|
'monotonicity' or 'principal_score'. |
strata_proportions |
dict
|
Estimated proportion in each stratum. |
effects |
DataFrame
|
Point estimate / SE / CI for each stratum-specific causal effect. |
bounds |
DataFrame or None
|
For 'monotonicity' method, sharp Zhang-Rubin bounds on SACE. |
n_obs |
int
|
|
alpha |
float
|
|
model_info |
dict
|
|
Examples:
>>> import statspai as sp
>>> import numpy as np, pandas as pd
>>> rng = np.random.default_rng(0)
>>> n = 400
>>> D = rng.integers(0, 2, n)
>>> S = (rng.uniform(size=n) < 0.4 + 0.3 * D).astype(int)
>>> Y = 1.0 + 0.5 * D + 0.8 * S + rng.normal(0, 1.0, n)
>>> df = pd.DataFrame({"y": Y, "treat": D, "surv": S})
>>> res = sp.principal_strat(
... df, y="y", treat="treat", strata="surv",
... method="monotonicity", n_boot=100, seed=0,
... )
>>> isinstance(res, sp.PrincipalStratResult)
True
>>> res.n_obs
400
>>> bool("Principal Stratification" in res.summary())
True
survivor_average_causal_effect ¶
survivor_average_causal_effect(data: DataFrame, y: str, treat: str, survival: str, alpha: float = 0.05, n_boot: int = 500, seed: Optional[int] = None) -> CausalResult
Zhang-Rubin (2003) sharp bounds on the Survivor Average Causal Effect.
Returns a :class:CausalResult with estimate set to the midpoint
of the SACE bounds and the endpoints stored in model_info.
References
zhang2003estimation
Examples:
>>> import statspai as sp
>>> import numpy as np, pandas as pd
>>> rng = np.random.default_rng(0)
>>> n = 400
>>> D = rng.integers(0, 2, n) # treatment
>>> S = (rng.uniform(size=n) < 0.4 + 0.3 * D).astype(int) # survival
>>> Y = 1.0 + 0.5 * D + 0.8 * S + rng.normal(0, 1.0, n) # outcome
>>> df = pd.DataFrame({"y": Y, "treat": D, "surv": S})
>>> res = sp.survivor_average_causal_effect(
... df, y="y", treat="treat", survival="surv",
... n_boot=100, seed=0,
... )
>>> res.estimand
'SACE'
>>> bool(res.model_info["sace_lower"] <= res.model_info["sace_upper"])
True