Diagnostics
compute_positivity_metrics
compute_positivity_metrics(df: DataFrame, ps_col: str = PS_COL, treatment_col: str = TREATMENT_COL, eps: float = 0.01, common_support_threshold: float = 0.05) -> dict
Compute positivity/overlap diagnostics for the propensity score.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
df
|
DataFrame
|
Input DataFrame with treatment and propensity score columns. |
required |
ps_col
|
str
|
Name of the propensity score column. |
PS_COL
|
treatment_col
|
str
|
Name of the treatment status column (1 treated, 0 control). |
TREATMENT_COL
|
eps
|
float
|
Propensity scores outside [eps, 1 - eps] are counted as extreme. |
0.01
|
common_support_threshold
|
float
|
Quantile threshold passed to get_common_support_range. |
0.05
|
Returns:
| Type | Description |
|---|---|
dict
|
dict with sample sizes, shares of extreme propensity scores (overall and |
dict
|
per arm), the trimmed common support range (intersection of the arms' |
dict
|
quantile-trimmed PS ranges — observations can fall outside it even under |
dict
|
perfect overlap when common_support_threshold > 0) and shares outside it, |
dict
|
the KS test comparing the arms' propensity score distributions, and a |
dict
|
flag_extreme_ps bool (True if any propensity scores fall outside |
dict
|
[eps, 1 - eps] — evidence of a practical positivity problem, not proof of |
dict
|
a formal violation). |
Source code in CausalEstimate/diagnostics/positivity.py
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
compute_weight_diagnostics
compute_weight_diagnostics(df: DataFrame, ps_col: str = PS_COL, treatment_col: str = TREATMENT_COL, weight_type: Literal['ATE', 'ATT'] = 'ATE', clip_percentile: float = 1) -> dict
Compute IPW weight diagnostics: effective sample size and weight summaries.
Weights are computed with compute_ipw_weights; clip_percentile=1 (default) means raw, unclipped weights, matching the estimators' default. Propensity scores of exactly 0 or 1 raise ValueError: their IPW weights are undefined and would only reflect the numerical stabilizer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
df
|
DataFrame
|
Input DataFrame with treatment and propensity score columns. |
required |
ps_col
|
str
|
Name of the propensity score column. |
PS_COL
|
treatment_col
|
str
|
Name of the treatment status column (1 treated, 0 control). |
TREATMENT_COL
|
weight_type
|
Literal['ATE', 'ATT']
|
"ATE" or "ATT". |
'ATE'
|
clip_percentile
|
float
|
Upper-tail clipping passed to compute_ipw_weights. |
1
|
Returns:
| Type | Description |
|---|---|
dict
|
dict with per-arm ESS, ESS as a fraction of arm size, and per-arm weight |
dict
|
summaries (max, mean, 95th and 99th percentile). Pooled equivalents |
dict
|
(ess_total, ess_fraction_total, max_weight, mean_weight, weight_q95, |
dict
|
weight_q99) are included only for weight_type="ATE": ATT weights put the |
dict
|
two arms on different scales (treated weights are identically 1), so |
dict
|
pooled Kish ESS and pooled quantiles would be misleading there. |
Source code in CausalEstimate/diagnostics/weights.py
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | |
compute_ess
compute_ess(weights: ndarray) -> float
Effective sample size of a weighted sample (Kish): (sum w)^2 / sum(w^2).
Equals n for uniform weights and approaches 1 as a single weight dominates. Defined for nonnegative weights; nonfinite, negative, or all-zero weights raise ValueError.
Source code in CausalEstimate/diagnostics/weights.py
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
compute_ipw_weights
compute_ipw_weights(A: ndarray, ps: ndarray, weight_type: Literal['ATE', 'ATT'] = 'ATE', clip_percentile: float = 1, eps: float = 1e-09) -> np.ndarray
Inverse Propensity Score weights with optional per-arm clipping.
Formulas: - ATE: w = A/ps + (1-A)/(1-ps) - ATT: w = A + (1-A) * ps/(1-ps)
Note these are the IPW estimator's weights, which differ from the TMLE
targeting weights of compute_arm_weights: the ATT variants are
normalised differently (1 vs 1/p_treated on the treated arm), and here the
two arms are summed into a single vector rather than kept separate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
A
|
ndarray
|
Binary treatment assignment vector (1 for treated, 0 for control). |
required |
ps
|
ndarray
|
Propensity score vector. |
required |
weight_type
|
Literal['ATE', 'ATT']
|
"ATE" or "ATT". |
'ATE'
|
clip_percentile
|
float
|
Upper quantile at which to clip, as a PROPORTION in (0, 1]. 1.0 (default) applies no clipping; 0.99 clips the top 1%. |
1
|
eps
|
float
|
Small constant added to denominators. |
1e-09
|
Returns:
| Type | Description |
|---|---|
ndarray
|
An array of IPW weights. |
Raises:
| Type | Description |
|---|---|
ValueError
|
on an invalid |
Source code in CausalEstimate/estimators/functional/utils.py
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 | |
compute_evalue
compute_evalue(estimate: float, ci_lower: Optional[float] = None, ci_upper: Optional[float] = None, scale: Literal['RR', 'RD'] = 'RR', baseline_risk: Optional[float] = None) -> dict
E-value for unmeasured confounding (VanderWeele & Ding, 2017).
The E-value is the minimum strength of association, on the risk-ratio scale, that an unmeasured confounder would need with both treatment and outcome (conditional on measured covariates) to fully explain away the observed effect. For RR >= 1, E = RR + sqrt(RR * (RR - 1)); protective effects use 1 / RR. The CI E-value applies the same formula to the confidence bound closest to the null and is 1 when the interval contains the null.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
estimate
|
float
|
Effect estimate on the given scale. |
required |
ci_lower
|
Optional[float]
|
Lower confidence bound; pass together with ci_upper. |
None
|
ci_upper
|
Optional[float]
|
Upper confidence bound. |
None
|
scale
|
Literal['RR', 'RD']
|
"RR" for risk ratios (RR, RRT effect types), or "RD" for risk differences (ATE, ARR, ATT, ATC on a binary outcome). RD values are converted to risk ratios via (baseline_risk + RD) / baseline_risk. |
'RR'
|
baseline_risk
|
Optional[float]
|
Outcome risk in the untreated (e.g. the estimator's
|
None
|
Returns:
| Type | Description |
|---|---|
dict
|
dict with keys "evalue" and "evalue_ci" (None if no CI was given). |
Source code in CausalEstimate/diagnostics/sensitivity.py
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | |