|
1 | | -# StatsPAI |
| 1 | +# StatsPAI: The Causal Inference & Econometrics Toolkit for Python |
2 | 2 |
|
3 | | -[](https://badge.fury.io/py/StatsPAI) |
| 3 | +[](https://pypi.org/project/StatsPAI/) |
4 | 4 | [](https://pypi.org/project/StatsPAI/) |
5 | | -[](https://github.com/brycewang-stanford/statspai/blob/main/LICENSE) |
6 | | -[](https://github.com/brycewang-stanford/statspai/actions) |
7 | | -[](https://codecov.io/gh/brycewang-stanford/statspai) |
| 5 | +[](https://github.com/brycewang-stanford/statspai/blob/main/LICENSE) |
| 6 | +[](https://github.com/brycewang-stanford/statspai/actions) |
| 7 | +[](https://pepy.tech/project/statspai) |
8 | 8 |
|
9 | | -**The AI-powered Statistics & Econometrics Toolkit for Python** |
| 9 | +StatsPAI is a Python package for causal inference and applied econometrics. It provides a unified, Stata-style API covering the complete empirical research workflow — from estimation to publication-ready tables in Word, Excel, and LaTeX. |
10 | 10 |
|
11 | | -StatsPAI bridges the gap between user-friendly syntax and powerful econometric analysis, making advanced techniques accessible to researchers and practitioners. |
| 11 | +It brings R's [Causal Inference Task View](https://cran.r-project.org/web/views/CausalInference.html) (fixest, did, rdrobust, gsynth, DoubleML, MatchIt, CausalImpact) into a single, consistent Python package. |
12 | 12 |
|
13 | | -## Features |
| 13 | +> Built by the team behind [CoPaper.AI](https://copaper.ai) · Stanford REAP Program |
14 | 14 |
|
15 | | -### Core Econometric Methods |
16 | | -- **Linear Regression**: OLS, WLS with robust standard errors |
17 | | -- **Instrumental Variables**: 2SLS estimation |
18 | | -- **Panel Data**: Fixed Effects, Random Effects models |
19 | | -- **Causal Inference**: Causal Forest implementation (inspired by EconML) |
| 15 | +--- |
20 | 16 |
|
21 | | -### User Experience |
22 | | -- **Formula Interface**: Intuitive R/Stata-style syntax `"y ~ x1 + x2"` |
23 | | -- **Excel Export**: Professional output tables via `outreg2` (Stata-inspired) |
24 | | -- **Flexible API**: Both formula and matrix interfaces supported |
25 | | -- **Rich Output**: Detailed summary statistics and diagnostic tests |
| 17 | +## Main Features |
26 | 18 |
|
27 | | -### Technical Excellence |
28 | | -- **Robust Implementation**: Based on proven econometric theory |
29 | | -- **Performance Optimized**: Efficient algorithms for large datasets |
30 | | -- **Well Tested**: Comprehensive test suite ensuring reliability |
31 | | -- **Type Hints**: Full type annotation for better development experience |
| 19 | +**Regression Models:** |
32 | 20 |
|
33 | | -## Installation |
| 21 | +- Ordinary Least Squares with robust / clustered / HAC standard errors |
| 22 | +- Instrumental Variables / Two-Stage Least Squares (2SLS), with first-stage F, Sargan, and Hausman tests |
| 23 | +- Panel data: Fixed Effects, Random Effects, Between, First Differences (via linearmodels) |
| 24 | +- High-dimensional Fixed Effects (via pyfixest) |
34 | 25 |
|
35 | | -```bash |
36 | | -# Latest stable version |
37 | | -pip install StatsPAI |
| 26 | +**Causal Inference — Difference-in-Differences:** |
38 | 27 |
|
39 | | -# Development version |
40 | | -pip install git+https://github.com/brycewang-stanford/statspai.git |
41 | | -``` |
| 28 | +- Classic 2x2 DID estimator |
| 29 | +- Staggered DID with heterogeneous treatment effects (Callaway & Sant'Anna 2021) |
| 30 | +- Event study plots and pre-trend tests |
42 | 31 |
|
43 | | -### Requirements |
44 | | -- Python 3.8+ |
45 | | -- NumPy, SciPy, Pandas |
46 | | -- scikit-learn (for Causal Forest) |
47 | | -- openpyxl (for Excel export) |
| 32 | +**Causal Inference — Regression Discontinuity:** |
48 | 33 |
|
49 | | -## Quick Start |
| 34 | +- Sharp and Fuzzy RD with local polynomial estimation |
| 35 | +- MSE-optimal bandwidth selection (CCT 2014) |
| 36 | +- Robust bias-corrected confidence intervals |
| 37 | +- RD plots with binned scatter and polynomial fit |
50 | 38 |
|
51 | | -### Basic Regression Analysis |
52 | | -```python |
53 | | -import pandas as pd |
54 | | -from statspai import reg, outreg2 |
| 39 | +**Causal Inference — Matching:** |
55 | 40 |
|
56 | | -# Load your data |
57 | | -df = pd.read_csv('data.csv') |
| 41 | +- Propensity Score Matching (logit-based PSM) |
| 42 | +- Mahalanobis distance matching |
| 43 | +- Coarsened Exact Matching (CEM) |
| 44 | +- Balance diagnostics with standardized mean differences |
58 | 45 |
|
59 | | -# Run OLS regression |
60 | | -result1 = reg('wage ~ education + experience', data=df) |
61 | | -print(result1.summary()) |
| 46 | +**Causal Inference — Synthetic Control:** |
62 | 47 |
|
63 | | -# Add control variables |
64 | | -result2 = reg('wage ~ education + experience + age + gender', data=df) |
| 48 | +- Abadie-Diamond-Hainmueller SCM |
| 49 | +- Penalized / ridge SCM for many donors |
| 50 | +- Placebo (permutation) inference with MSPE ratios |
| 51 | +- Donor weight tables and gap plots |
65 | 52 |
|
66 | | -# Export results to Excel |
67 | | -outreg2([result1, result2], 'regression_results.xlsx', |
68 | | - title='Wage Regression Analysis') |
69 | | -``` |
| 53 | +**Causal Inference — Machine Learning Methods:** |
70 | 54 |
|
71 | | -### Instrumental Variables |
72 | | -```python |
73 | | -# 2SLS estimation |
74 | | -iv_result = reg('wage ~ education | mother_education + father_education', |
75 | | - data=df, method='2sls') |
76 | | -print(iv_result.summary()) |
77 | | -``` |
| 55 | +- Double/Debiased Machine Learning: Partially Linear (PLR) and Interactive (IRM) models with cross-fitting (Chernozhukov et al. 2018) |
| 56 | +- Causal Forest for heterogeneous treatment effects (HTE) |
| 57 | +- Compatible with any scikit-learn estimator as first-stage ML model |
78 | 58 |
|
79 | | -### Panel Data Analysis |
80 | | -```python |
81 | | -# Fixed effects model |
82 | | -fe_result = reg('y ~ x1 + x2', data=df, |
83 | | - entity_col='firm_id', time_col='year', |
84 | | - method='fixed_effects') |
85 | | -``` |
| 59 | +**Causal Inference — Other Methods:** |
86 | 60 |
|
87 | | -### Causal Forest for Heterogeneous Treatment Effects |
88 | | -```python |
89 | | -from statspai import CausalForest |
| 61 | +- Causal Impact: Bayesian structural time-series intervention analysis (Brodersen et al. 2015) |
| 62 | +- Causal Mediation Analysis: ACME / ADE decomposition with bootstrap inference (Imai et al. 2010) |
| 63 | +- Shift-Share / Bartik IV with Rotemberg weight diagnostics (GPSS 2020) |
90 | 64 |
|
91 | | -# Initialize Causal Forest |
92 | | -cf = CausalForest(n_estimators=100, random_state=42) |
| 65 | +**Post-Estimation:** |
93 | 66 |
|
94 | | -# Fit model: outcome ~ treatment | features | controls |
95 | | -cf.fit('income ~ job_training | age + education + experience | region + year', |
96 | | - data=df) |
| 67 | +- Marginal effects (AME / MEM) with delta-method standard errors, equivalent to Stata's `margins, dydx(*)` |
| 68 | +- Wald test for linear restrictions, equivalent to Stata's `test` |
| 69 | +- Linear combinations of coefficients with inference, equivalent to Stata's `lincom` |
97 | 70 |
|
98 | | -# Estimate individual treatment effects |
99 | | -individual_effects = cf.effect(df) |
| 71 | +**Diagnostics:** |
100 | 72 |
|
101 | | -# Get confidence intervals |
102 | | -effects_ci = cf.effect_interval(df, alpha=0.05) |
| 73 | +- Oster (2019) coefficient stability / selection-on-unobservables bounds |
| 74 | +- McCrary (2008) density manipulation test for RD validity |
103 | 75 |
|
104 | | -# Export results |
105 | | -cf_summary = cf.summary() |
106 | | -outreg2([cf_summary], 'causal_forest_results.xlsx') |
107 | | -``` |
| 76 | +**Publication-Quality Output:** |
108 | 77 |
|
109 | | -## Advanced Usage |
| 78 | +- Multi-model comparison tables (equivalent to R's `modelsummary` / Stata's `esttab`) |
| 79 | +- Coefficient forest plots across models |
| 80 | +- Summary statistics tables (equivalent to Stata's `tabstat`) |
| 81 | +- Balance tables for matching / DID / RCT papers |
| 82 | +- Cross-tabulation with chi-squared / Fisher's exact test (equivalent to Stata's `tab, chi2`) |
| 83 | +- **Export to Word (.docx), Excel (.xlsx), LaTeX (.tex), HTML** — all tables, all formats |
| 84 | +- Every result object has `.summary()`, `.plot()`, `.to_latex()`, `.to_docx()`, `.cite()` |
110 | 85 |
|
111 | | -### Robust Standard Errors |
112 | | -```python |
113 | | -# Heteroskedasticity-robust standard errors |
114 | | -result = reg('y ~ x1 + x2', data=df, robust=True) |
| 86 | +--- |
115 | 87 |
|
116 | | -# Clustered standard errors |
117 | | -result = reg('y ~ x1 + x2', data=df, cluster='firm_id') |
118 | | -``` |
| 88 | +## Installation |
119 | 89 |
|
120 | | -### Model Comparison |
121 | | -```python |
122 | | -from statspai import compare_models |
| 90 | +```bash |
| 91 | +pip install statspai |
| 92 | +``` |
123 | 93 |
|
124 | | -models = [ |
125 | | - reg('y ~ x1', data=df), |
126 | | - reg('y ~ x1 + x2', data=df), |
127 | | - reg('y ~ x1 + x2 + x3', data=df) |
128 | | -] |
| 94 | +With optional dependencies: |
129 | 95 |
|
130 | | -comparison = compare_models(models) |
131 | | -print(comparison.summary()) |
| 96 | +```bash |
| 97 | +pip install statspai[plotting] # matplotlib, seaborn |
| 98 | +pip install statspai[fixest] # pyfixest for high-dimensional FE |
132 | 99 | ``` |
133 | 100 |
|
134 | | -### Custom Output Formatting |
| 101 | +**Requirements:** Python >= 3.9 |
| 102 | + |
| 103 | +**Core dependencies:** NumPy, SciPy, Pandas, statsmodels, scikit-learn, linearmodels, patsy, openpyxl, python-docx |
| 104 | + |
| 105 | +--- |
| 106 | + |
| 107 | +## Quick Example |
| 108 | + |
135 | 109 | ```python |
136 | | -outreg2(results, 'output.xlsx', |
137 | | - title='Regression Results', |
138 | | - add_stats={'Observations': lambda r: r.nobs, |
139 | | - 'R-squared': lambda r: r.rsquared}, |
140 | | - decimal_places=4, |
141 | | - star_levels=[0.01, 0.05, 0.1]) |
| 110 | +import statspai as sp |
| 111 | + |
| 112 | +# --- Estimation --- |
| 113 | +r1 = sp.regress("wage ~ education + experience", data=df, robust='hc1') |
| 114 | +r2 = sp.ivreg("wage ~ (education ~ parent_edu) + experience", data=df) |
| 115 | +r3 = sp.did(df, y='wage', treat='policy', time='year', id='worker') |
| 116 | +r4 = sp.rdrobust(df, y='score', x='running_var', c=0) |
| 117 | +r5 = sp.match(df, y='outcome', treat='treated', covariates=['age', 'edu']) |
| 118 | +r6 = sp.dml(df, y='wage', treat='training', covariates=['age', 'edu', 'exp']) |
| 119 | + |
| 120 | +# --- Post-estimation --- |
| 121 | +me = sp.margins(r1, data=df) # Marginal effects |
| 122 | +sp.test(r1, "education = experience") # Wald test: beta_edu = beta_exp? |
| 123 | +sp.lincom(r1, "education + experience") # Linear combination |
| 124 | + |
| 125 | +# --- Tables (to Word / Excel / LaTeX) --- |
| 126 | +sp.modelsummary(r1, r2, output='table2.docx') |
| 127 | +sp.outreg2(r1, r2, r3, filename='results.xlsx') |
| 128 | +sp.sumstats(df, vars=['wage', 'education', 'age'], output='table1.docx') |
| 129 | +sp.balance_table(df, treat='treated', covariates=['age', 'edu'], output='balance.docx') |
| 130 | +sp.tab(df, 'treatment', 'outcome', output='crosstab.docx') |
142 | 131 | ``` |
143 | 132 |
|
144 | | -## Documentation |
| 133 | +--- |
145 | 134 |
|
146 | | -- **[User Guide](docs/user_guide.md)**: Comprehensive tutorials and examples |
147 | | -- **[API Reference](docs/api_reference.md)**: Detailed function documentation |
148 | | -- **[Theory Guide](docs/theory_guide.md)**: Mathematical foundations |
149 | | -- **[Examples](examples/)**: Jupyter notebooks with real-world applications |
| 135 | +## API Summary |
150 | 136 |
|
151 | | -## Contributing |
| 137 | +| Category | Functions | Description | |
| 138 | +| --- | --- | --- | |
| 139 | +| **Regression** | `regress`, `ivreg`, `panel`, `fixest.feols` | OLS, IV/2SLS, Panel (FE/RE/FD/BE), High-dimensional FE | |
| 140 | +| **DID** | `did`, `did_2x2`, `callaway_santanna` | Classic 2x2, Staggered (C&S 2021), Event study | |
| 141 | +| **RD** | `rdrobust`, `rdplot` | Sharp/Fuzzy RD, CCT robust inference, RD plots | |
| 142 | +| **Matching** | `match` | PSM, CEM, Mahalanobis, Balance diagnostics | |
| 143 | +| **Synth** | `synth` | Abadie SCM, Penalized SCM, Placebo inference | |
| 144 | +| **ML Causal** | `dml`, `causal_forest` | Double ML (PLR/IRM), Causal Forest (HTE) | |
| 145 | +| **Other Causal** | `causal_impact`, `mediate`, `bartik` | Intervention analysis, Mediation, Shift-share IV | |
| 146 | +| **Post-estimation** | `margins`, `marginsplot`, `test`, `lincom` | Marginal effects, Wald tests, Linear combinations | |
| 147 | +| **Diagnostics** | `oster_bounds`, `mccrary_test` | Coefficient stability, Density manipulation | |
| 148 | +| **Tables** | `modelsummary`, `outreg2`, `sumstats`, `balance_table`, `tab` | Multi-model tables, Summary stats, Balance, Cross-tabs | |
| 149 | +| **Plots** | `coefplot`, `marginsplot`, `rdplot`, `result.plot()` | Coefficient, Margins, RD, Event study plots | |
| 150 | +| **Export** | `.to_docx()`, `.to_latex()`, `output='*.xlsx'` | Word, Excel, LaTeX, HTML — all tables, all formats | |
152 | 151 |
|
153 | | -We welcome contributions! See our [Contributing Guide](CONTRIBUTING.md) for details. |
| 152 | +All causal methods return a unified **`CausalResult`** object: |
154 | 153 |
|
155 | | -### Development Setup |
156 | | -```bash |
157 | | -# Clone repository |
158 | | -git clone https://github.com/brycewang-stanford/statspai.git |
159 | | -cd statspai |
| 154 | +```python |
| 155 | +result.estimate # Point estimate |
| 156 | +result.se # Standard error |
| 157 | +result.pvalue # P-value |
| 158 | +result.ci # Confidence interval |
| 159 | +result.summary() # Formatted text summary |
| 160 | +result.plot() # Appropriate visualization |
| 161 | +result.to_latex() # LaTeX table |
| 162 | +result.to_docx() # Word document |
| 163 | +result.cite() # BibTeX citation for the method |
| 164 | +``` |
160 | 165 |
|
161 | | -# Install in development mode |
162 | | -pip install -e ".[dev]" |
| 166 | +--- |
163 | 167 |
|
164 | | -# Install pre-commit hooks |
165 | | -pre-commit install |
| 168 | +## Comparison with Stata and R |
166 | 169 |
|
167 | | -# Run tests |
168 | | -pytest |
169 | | -``` |
| 170 | +| Task | Stata | R | StatsPAI | |
| 171 | +| --- | --- | --- | --- | |
| 172 | +| OLS with robust SE | `reg y x, r` | `feols(y ~ x, vcov="HC1")` | `sp.regress("y ~ x", robust='hc1')` | |
| 173 | +| IV regression | `ivregress 2sls y (x = z)` | `feols(y ~ 1 \| x ~ z)` | `sp.ivreg("y ~ (x ~ z)")` | |
| 174 | +| Staggered DID | `csdid y, ivar(id) time(t) gvar(g)` | `att_gt(y ~ 1, ...)` | `sp.did(df, y, treat, time, id)` | |
| 175 | +| RD design | `rdrobust y x, c(0)` | `rdrobust(Y, X, c=0)` | `sp.rdrobust(df, y, x, c=0)` | |
| 176 | +| PSM matching | `psmatch2 treat x1 x2` | `matchit(treat ~ x1+x2)` | `sp.match(df, y, treat, covs)` | |
| 177 | +| Double ML | — | `DoubleML$new(...)` | `sp.dml(df, y, treat, covs)` | |
| 178 | +| Marginal effects | `margins, dydx(*)` | `margins(model)` | `sp.margins(result, data=df)` | |
| 179 | +| Wald test | `test x1 = x2` | `linearHypothesis(...)` | `sp.test(result, "x1 = x2")` | |
| 180 | +| Export to Word | `outreg2 using r.doc, word` | `modelsummary(output="t.docx")` | `sp.outreg2(r, filename="r.docx")` | |
| 181 | +| Summary stats | `tabstat y x, s(mean sd)` | `datasummary(...)` | `sp.sumstats(df, vars=[...])` | |
170 | 182 |
|
171 | | -## License |
| 183 | +--- |
172 | 184 |
|
173 | | -This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. |
| 185 | +## About |
174 | 186 |
|
175 | | -## Acknowledgments |
| 187 | +**StatsPAI Inc.** is the research infrastructure company behind [CoPaper.AI](https://copaper.ai) — the AI co-authoring platform for empirical research, born out of Stanford's [REAP](https://reap.fsi.stanford.edu/) program. |
176 | 188 |
|
177 | | -- Inspired by Stata's `outreg2` command for output formatting |
178 | | -- Causal Forest implementation based on Wager & Athey (2018) |
179 | | -- Built on the shoulders of NumPy, SciPy, and scikit-learn |
| 189 | +**CoPaper.AI** — Upload your data, set your research question, and produce a fully reproducible academic paper with code, tables, and formatted output. Powered by StatsPAI under the hood. [copaper.ai](https://copaper.ai) |
180 | 190 |
|
181 | | -## Contact |
| 191 | +**Team:** |
182 | 192 |
|
183 | | -- **Author**: Bryce Wang |
184 | | -- **Email**: brycew6m@gmail.com |
185 | | -- **GitHub**: [brycewang-stanford](https://github.com/brycewang-stanford) |
| 193 | +- **Bryce Wang** — Founder. Economics, Finance, CS & AI. Stanford REAP. |
| 194 | +- **Dr. Scott Rozelle** — Co-founder & Strategic Advisor. Stanford Senior Fellow, author of *Invisible China*. |
186 | 195 |
|
187 | | -## Citation |
| 196 | +--- |
188 | 197 |
|
189 | | -If you use StatsPAI in your research, please cite: |
| 198 | +## Contributing |
| 199 | + |
| 200 | +```bash |
| 201 | +git clone https://github.com/brycewang-stanford/statspai.git |
| 202 | +cd statspai |
| 203 | +pip install -e ".[dev,plotting,fixest]" |
| 204 | +pytest |
| 205 | +``` |
| 206 | + |
| 207 | +--- |
| 208 | + |
| 209 | +## Citation |
190 | 210 |
|
191 | 211 | ```bibtex |
192 | | -@software{wang2024statspai, |
193 | | - title={StatsPAI: The AI-powered Statistics & Econometrics Toolkit for Python}, |
| 212 | +@software{wang2025statspai, |
| 213 | + title={StatsPAI: The Causal Inference & Econometrics Toolkit for Python}, |
194 | 214 | author={Wang, Bryce}, |
195 | | - year={2024}, |
| 215 | + year={2025}, |
196 | 216 | url={https://github.com/brycewang-stanford/statspai}, |
197 | 217 | version={0.1.0} |
198 | 218 | } |
199 | 219 | ``` |
| 220 | + |
| 221 | +## License |
| 222 | + |
| 223 | +MIT License. See [LICENSE](LICENSE). |
| 224 | + |
| 225 | +--- |
| 226 | + |
| 227 | +[GitHub](https://github.com/brycewang-stanford/statspai) · [PyPI](https://pypi.org/project/StatsPAI/) · [Documentation](https://statspai.readthedocs.io/) · [CoPaper.AI](https://copaper.ai) |
0 commit comments