Skip to content

Commit c9ceb72

Browse files
docs: add R-to-StatsPAI migration cheatsheet
New guide at docs/guides/migration-from-r.md mapping R causal-inference packages to StatsPAI's unified sp.* API, covering: - fixest (feols/fepois/feglm/etable) - did, DIDmultiplegt, didimputation, HonestDiD, pretrends, bacondecomp - rdrobust, rddensity, rdmulti, rdhonest - Synth, gsynth, augsynth, synthdid - MatchIt, ebal, cobalt - AER, ivmodel, hdm, MendelianRandomization - DoubleML, grf, SuperLearner, policytree, causalTree - pcalg, EValue, specr All 63 sp.* references and 5 class imports in the doc are verified against the installed package (no broken references). Also includes a 'What StatsPAI Adds That R Cannot' section to reinforce the unifier positioning from the README. Added with -f since docs/ is in .gitignore (only selected doc files are tracked, following precedent of the existing guides/). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2b263be commit c9ceb72

1 file changed

Lines changed: 195 additions & 0 deletions

File tree

docs/guides/migration-from-r.md

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
# Migrating from R to StatsPAI
2+
3+
A practical one-page map for researchers moving from R's causal inference
4+
ecosystem to StatsPAI. Every R function listed here has an independent
5+
Python re-implementation in StatsPAI, following the same statistical
6+
methodology but exposed through a unified `sp.*` API.
7+
8+
```python
9+
import statspai as sp
10+
```
11+
12+
---
13+
14+
## Regression & Fixed Effects (`fixest`)
15+
16+
| R (`fixest`) | StatsPAI | Notes |
17+
| ----------------------------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------ |
18+
| `feols(y ~ x1 + x2, data = df)` | `sp.feols("y ~ x1 + x2", data=df)` | pyfixest-backed; same formula syntax |
19+
| `feols(y ~ x \| firm + year, data = df)` | `sp.feols("y ~ x \| firm + year", data=df)` | Two-way fixed effects |
20+
| `fepois(y ~ x \| firm, data = df)` | `sp.fepois("y ~ x \| firm", data=df)` | HDFE Poisson / PPML for gravity models |
21+
| `feglm(..., family = "binomial")` | `sp.feglm(..., family="binomial")` | HDFE GLM |
22+
| `etable(m1, m2, m3)` | `sp.etable([m1, m2, m3])` | Publication-quality regression tables (LaTeX / MD / HTML) |
23+
| `vcov(m, cluster = ~firm)` | `vcov={"CRV1": "firm"}` in `sp.feols` | Cluster-robust SE |
24+
| `fixef(m)` | `m.fixef()` (on pyfixest result) | Extract fixed-effect estimates |
25+
26+
For plain OLS without HDFE, `sp.regress("y ~ x", data=df)` gives a statsmodels-
27+
compatible interface returning a `CausalResult`.
28+
29+
---
30+
31+
## Staggered DID (`did`, `fixest::sunab`, `didimputation`, `DIDmultiplegt`)
32+
33+
| R | StatsPAI |
34+
| ------------------------------------------------------- | -------------------------------------------------------- |
35+
| `did::att_gt(yname, tname, gname, idname, data)` | `sp.callaway_santanna(data, y=, time=, first_treat=, group=)` |
36+
| `did::aggte(obj, type = "dynamic")` | `sp.aggte(cs_result, type="dynamic")` |
37+
| `did::aggte(obj, type = "group")` | `sp.aggte(cs_result, type="group")` |
38+
| `did::ggdid(agg)` | `sp.ggdid(agg_result)` |
39+
| `fixest::sunab(cohort, period)` inside `feols` | `sp.sun_abraham(data, y=, time=, first_treat=, group=)` |
40+
| `didimputation::did_imputation(...)` | `sp.did_imputation(data, y=, time=, first_treat=, group=)` |
41+
| `DIDmultiplegt::did_multiplegt(...)` | `sp.did_multiplegt(data, y=, group=, time=, treatment=)` |
42+
| `DIDmultiplegt::did_multiplegt_dyn(...)` | `sp.did_multiplegt(..., dynamic=True)` |
43+
| `bacondecomp::bacon(...)` | `sp.bacon_decomposition(data, y=, time=, treat=, id=)` |
44+
|| `sp.etwfe(...)` — Wooldridge (2021) explicit API |
45+
| `HonestDiD::createSensitivityResults(...)` | `sp.honest_did(cs_result, Mbar=...)` / `sp.breakdown_m(...)` |
46+
| `HonestDiD::createSensitivityResults_relativeMagnitudes` | `sp.sensitivity_rr(cs_result, Mbar=...)` |
47+
| `pretrends::pretrends_power(...)` | `sp.pretrends_power(...)` / `sp.pretrends_test(...)` |
48+
|| `sp.stacked_did(...)`, `sp.ddd(...)`, `sp.continuous_did(...)`, `sp.cic(...)` |
49+
50+
One-call integrated report:
51+
52+
```python
53+
report = sp.cs_report(data, y="y", time="t", first_treat="g", group="id",
54+
save_to="output/did_report")
55+
# Produces .txt + .md + .tex + .xlsx + .png in one call
56+
```
57+
58+
---
59+
60+
## Regression Discontinuity (`rdrobust`, `rddensity`, `rdmulti`, `rdhonest`)
61+
62+
| R | StatsPAI |
63+
| --------------------------------------------- | ------------------------------------------------------ |
64+
| `rdrobust::rdrobust(y, x, c = 0)` | `sp.rdrobust(y, x, c=0)` |
65+
| `rdrobust::rdplot(y, x)` | `sp.rdplot(y, x)` |
66+
| `rdrobust::rdbwselect(y, x)` | bandwidth auto-selected inside `sp.rdrobust(...)` |
67+
| `rddensity::rddensity(x, c = 0)` | `sp.rdplotdensity(x, c=0)` |
68+
| `rdmulti::rdmc(...)` | `sp.rdmc(...)` |
69+
| `rdmulti::rdms(...)` | `sp.rdms(...)` |
70+
| `rdhonest::RDHonest(...)` | `sp.rd_honest(...)` (Armstrong-Kolesár honest CI) |
71+
|| `sp.rkd(...)` — Regression kink designs |
72+
73+
---
74+
75+
## Synthetic Control (`Synth`, `gsynth`, `augsynth`, `synthdid`)
76+
77+
| R | StatsPAI |
78+
| -------------------------------------------- | -------------------------------------------- |
79+
| `Synth::synth(...)` | `sp.synth(...)` |
80+
| `gsynth::gsynth(Y ~ D \| X, data)` | `sp.gsynth(data, y=, treat=, unit=, time=)` |
81+
| `augsynth::augsynth(...)` | `sp.augsynth(...)` |
82+
| `synthdid::synthdid_estimate(...)` | `sp.sdid(...)` |
83+
|| `sp.staggered_synth(...)` — Staggered SCM |
84+
|| `sp.robust_synth(...)` — Robust SCM |
85+
86+
---
87+
88+
## Matching & Reweighting (`MatchIt`, `ebal`, `cobalt`)
89+
90+
| R | StatsPAI |
91+
| ---------------------------------------- | --------------------------------------------------- |
92+
| `MatchIt::matchit(..., method = "nearest")` | `sp.match(..., method="psm")` |
93+
| `MatchIt::matchit(..., method = "cem")` | `sp.match(..., method="cem")` |
94+
| `MatchIt::matchit(..., method = "mahal")` | `sp.match(..., method="mahalanobis")` |
95+
| `ebal::ebalance(...)` | `sp.ebalance(...)` |
96+
| `cobalt::bal.tab(...)` | Built into `sp.match()` output: `result.balance` |
97+
98+
---
99+
100+
## IV (`AER`, `ivmodel`, `ivreg`)
101+
102+
| R | StatsPAI |
103+
| ---------------------------------------------- | ----------------------------------------------------- |
104+
| `AER::ivreg(y ~ x \| z, data = df)` | `sp.ivreg("y ~ x", instruments=["z"], data=df)` |
105+
| `ivmodel::LIML(...)` | `sp.liml(...)` |
106+
| `ivmodel::JIVE(...)` | `sp.jive(...)` |
107+
| `hdm::rlassoIV(...)` | `sp.lasso_iv(...)` |
108+
| `fixest::feols(y ~ 1 \| fe \| x ~ z)` | `sp.feols("y ~ 1 \| fe \| x ~ z", data=df)` |
109+
| `MendelianRandomization::mr_ivw(...)` | `sp.mr_ivw(...)` |
110+
| `MendelianRandomization::mr_egger(...)` | `sp.mr_egger(...)` |
111+
112+
---
113+
114+
## Machine Learning Causal Inference
115+
116+
| R | StatsPAI |
117+
| -------------------------------------------- | --------------------------------------------------- |
118+
| `DoubleML::DoubleMLPLR$new(...)` | `sp.dml(..., model="plr")` |
119+
| `DoubleML::DoubleMLIRM$new(...)` | `sp.dml(..., model="irm")` |
120+
| `grf::causal_forest(X, Y, W)` | `sp.causal_forest(X, Y, W)` |
121+
| `grf::causal_forest(...)$predict(...)` | `forest.predict(X_new)` |
122+
| `grf::instrumental_forest(...)` | `sp.causal_forest(..., instrumental=True)` |
123+
| `SuperLearner::SuperLearner(...)` | `sp.tmle(...)` with custom learners |
124+
| `policytree::policy_tree(...)` | `sp.policy_tree(X, reward)` |
125+
| `causalTree::honest.causalTree(...)` | `sp.causal_forest(..., honest=True)` |
126+
127+
Meta-learner suite (no single R package covers all of these):
128+
129+
```python
130+
# Unified one-call API:
131+
sp.metalearner(data, y="y", treat="D", covariates=["x1", "x2"], learner="S")
132+
sp.metalearner(data, ..., learner="T")
133+
sp.metalearner(data, ..., learner="X")
134+
sp.metalearner(data, ..., learner="R")
135+
sp.metalearner(data, ..., learner="DR") # default
136+
137+
# Or use the class API for finer control:
138+
from statspai import SLearner, TLearner, XLearner, RLearner, DRLearner
139+
```
140+
141+
---
142+
143+
## Bounds, Conformal, Discovery, Policy
144+
145+
| R | StatsPAI |
146+
| -------------------------------------- | --------------------------------------------------- |
147+
| `bounds::bounds(...)` (manual) | `sp.manski_bounds(...)`, `sp.lee_bounds(...)` |
148+
| `EValue::evalues.OR(...)` | `sp.evalue(...)` |
149+
| `pcalg::pc(suffStat, ...)` | `sp.pc_algorithm(data)` |
150+
| `pcalg::fci(...)` | `sp.causal_discovery(data, method="fci")` |
151+
| — (NOTEARS: Python only historically) | `sp.notears(data)` |
152+
| `policytree::policy_tree(...)` | `sp.policy_tree(...)` |
153+
|| `sp.conformal_cate(...)` — conformal CATE |
154+
155+
---
156+
157+
## Post-estimation, Diagnostics, Robustness
158+
159+
| R | StatsPAI |
160+
| ------------------------------------------------ | -------------------------------------------------- |
161+
| `modelsummary::modelsummary(list(m1, m2))` | `sp.outreg2([m1, m2])` or `sp.modelsummary([m1, m2])` |
162+
| `sandwich::vcovCL(m, cluster = ~id)` | `vcov={"CRV1": "id"}` in `sp.feols` / `sp.regress` |
163+
| `lmtest::coeftest(m, vcov = vcovHC)` | `result.robust()` / `result.summary(vcov="HC3")` |
164+
| `car::linearHypothesis(m, "x1 = x2")` | `result.test("x1 = x2")` |
165+
| `marginaleffects::avg_slopes(m)` | `result.marginal_effects()` |
166+
| `multiwayvcov::cluster.vcov(m, ~c1 + c2)` | `vcov={"CRV1": ["c1", "c2"]}` |
167+
| `specr::specr(...)` / `spec_curve` | `sp.spec_curve(...)` — native implementation |
168+
169+
---
170+
171+
## What StatsPAI Adds That R Cannot
172+
173+
These are not migration items — they are **net-new capabilities** that the
174+
R ecosystem does not currently offer in unified form:
175+
176+
- **`sp.list_functions()` / `sp.describe_function()` / `sp.function_schema()`** — agent-native introspection for LLM workflows
177+
- **`sp.interactive(fig)`** — Jupyter WYSIWYG plot editor with reproducible code export
178+
- **`sp.cs_report(..., save_to=...)`** — one-call bundle: txt + md + tex + xlsx + png
179+
- **Unified `CausalResult`** across all 390+ functions with `.summary()`, `.plot()`, `.to_latex()`, `.cite()`
180+
- **sklearn Pipeline / JAX / PyTorch integration** — neural causal models natively
181+
182+
---
183+
184+
## Quick Install
185+
186+
```bash
187+
pip install statspai
188+
# Optional HDFE backend (for sp.feols / sp.fepois at scale):
189+
pip install pyfixest
190+
```
191+
192+
---
193+
194+
If you find a missing R function that should be mapped here, please open
195+
an issue at [github.com/brycewang-stanford/statspai/issues](https://github.com/brycewang-stanford/statspai/issues).

0 commit comments

Comments
 (0)