Skip to content

Commit 433343c

Browse files
committed
Fix statsmodels causal inference reference: use real TreatmentEffect API
The treatment-effects example imported statsmodels.treatment.propensity_score, which does not exist, and labeled plain propensity score estimation as propensity score matching. Replace it with the actual TreatmentEffect API (IPW, RA, AIPW), keep score estimation as a separate diagnostic snippet, and add brief estimand/overlap/balance caveats. Verified against statsmodels 0.14.6. Bump skill version to 1.3.
1 parent cc37669 commit 433343c

2 files changed

Lines changed: 33 additions & 8 deletions

File tree

skills/statsmodels/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ allowed-tools: Read Write Edit Bash
55
compatibility: Requires Python 3.9+ and statsmodels 0.14.6-compatible dependencies. Use `uv pip install statsmodels==0.14.6`; optional predictive-metric examples also need scikit-learn.
66
license: BSD-3-Clause license
77
metadata:
8-
version: "1.2"
8+
version: "1.3"
99
skill-author: K-Dense Inc.
1010
---
1111

skills/statsmodels/references/stats_diagnostics.md

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -808,19 +808,44 @@ print(f"p-value: {result.pvalue:.4f}")
808808

809809
## Treatment Effects and Causal Inference
810810

811-
**Propensity score matching**:
811+
**Treatment effect estimation** (`TreatmentEffect`):
812812

813813
```python
814-
from statsmodels.treatment import propensity_score
814+
import statsmodels.api as sm
815+
from statsmodels.treatment.treatment_effects import TreatmentEffect
815816

816-
# Estimate propensity scores
817-
ps_model = sm.Logit(treatment, X).fit()
818-
propensity_scores = ps_model.predict(X)
817+
# exog: observed confounders (with constant); treatment: 0/1 indicator
818+
exog = sm.add_constant(confounders)
819+
select_model = sm.Probit(treatment, exog) # treatment (selection) model
820+
outcome_model = sm.OLS(outcome, exog) # outcome model
819821

820-
# Use for matching or weighting
821-
# (manual implementation of matching needed)
822+
te = TreatmentEffect(outcome_model, treatment,
823+
results_select=select_model.fit(disp=0))
824+
825+
print(te.ipw()) # inverse probability weighting
826+
print(te.ra()) # regression adjustment
827+
print(te.aipw()) # augmented IPW (doubly robust)
828+
# Also available: te.aipw_wls(), te.ipw_ra()
829+
# Results report the ATE and potential-outcome means POM0/POM1
822830
```
823831

832+
**Propensity scores** (for diagnostics or custom weighting):
833+
834+
```python
835+
ps_model = sm.Logit(treatment, exog).fit(disp=0)
836+
propensity_scores = ps_model.predict(exog)
837+
# statsmodels does not implement matching; estimating scores
838+
# alone is not propensity score matching
839+
```
840+
841+
Causal caveats:
842+
843+
- Estimates are causal only under no unmeasured confounding and positivity
844+
- Check overlap of propensity score distributions between groups; extreme
845+
scores near 0 or 1 make IPW unstable
846+
- Check covariate balance after weighting (e.g. standardized mean differences)
847+
- `TreatmentEffect` targets the ATE; the ATT is a different estimand
848+
824849
**Difference-in-differences**:
825850

826851
```python

0 commit comments

Comments
 (0)