
StatsPAI
io.github.brycewang-stanford由 GitHub 账号 brycewang-stanford 发布v1.43.1更新于 Nov 13, 2026
Econometrics and causal inference (DiD, IV, RD, synthetic control, DML) with Stata/R parity grades
概览
把 StatsPAI 的 Stata/R 风格计量经济学与因果推断估计器开放给助手,可加载数据、拟合模型、运行诊断并导出表格。
- 可以做什么
- 通过搜索、描述、调用三个元工具或精选工具列表发现并查看估计器
- 读取本地 CSV、Stata .dta 等 pandas 可读文件,估计 OLS、IV、logit/probit、高维固定效应、交错 DiD、断点回归、合成控制、匹配与双重机器学习
- 运行检验、线性组合、边际效应等事后分析,并查看诊断与验证状态
- 导出论文表格与图形,翻译或直接运行已有的 Stata 命令行
- 使用内置工作流提示与目录资源引导分析
- 适用场景
- 适合原本在 Stata、R 与 Python 之间来回切换的实证研究与应用经济学工作:助手可在同一界面估计因果模型、审查结果并生成可直接用于论文的表格。
- 运行要求
- 需在本机安装 Python 包(pip 或 uvx,Python 3.10-3.13,Linux 与 macOS);绘图、贝叶斯、神经网络、JAX、Rust、空间等为可选扩展。数据以路径传入;STATSPAI_MCP_DATA_ROOTS 限定可读目录,STATSPAI_MCP_PROFILE 决定公开的工具数量。
安装
在 SourceWeft 中
- 打开 控制台中的 StatsPAI,将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
简体中文 | English
[StatsPAI - Python-native Stata and R replacement for applied causal inference]
StatsPAI: an Agent&Python-native Stata/R replacement for applied causal inference
[PyPI version] [Python versions] [License: MIT] [Tests] [Docs] [PyPI Downloads] [JOSS] [DOI]
[Stanford Rural Education Action Program (REAP) - Center on China's Economy & Institutions]
[JOSS - The Journal of Open Source Software]
Developed and maintained by the Stanford REAP team
Published in the Journal of Open Source Software (JOSS): Wang & Rozelle (2026), 11(125), 10604 · doi:10.21105/joss.10604
StatsPAI is for empirical researchers who would normally jump between Stata, R, and Python. Its goal is to make common Stata/R econometrics and causal-inference workflows feel native in Python: load a dataset, estimate a model, inspect diagnostics, export tables, and hand the result to an agent or notebook without leaving one API.
It is meant to be a practical replacement path for new Python-first work:
- Stata-style routines:
regress,ivregress,reghdfe,csdid,rdrobust,synth,psmatch2,esttab/outreg2. - R-style routines:
lm,fixest,did,rdrobust,Synth,DoubleML,MatchIt,modelsummary,broom. - Stata conventions where they matter:
vce="robust"/vce="cluster firm"onregress,ivregand the likelihood estimators, Stata's small-sample factors and z / t reference distributions,test/lincom/margins, dydx()after any fit, andsp.stata("...", data=df)to run Stata command lines you already have. - Python-native outputs:
.summary(),.tidy(),.plot(),.to_latex(),.to_docx(),.to_agent_summary()where supported by the result object. - Agent-native access: every public function is registered with a
machine-readable schema (
sp.list_functions(),sp.describe_function(),sp.function_schema()), and the bundledstatspai-mcpserver exposes the estimators to MCP clients such as Claude Code, Claude Desktop, and Cursor. - Companion Stata tooling: our own
stata-codecan work with StatsPAI so agents can understand existing Stata workflows, translate them into Python, and cross-check results more smoothly. - Companion skill repos:
Auto-Empirical-Research-Skills,AER-Skills,Awesome-Journal-Skills, andPaper-WorkFlowcan work alongside StatsPAI and an agent as the methods, journal, manuscript, and reproducibility skill layer.
StatsPAI is not a promise that every Stata/R command is bit-for-bit identical.
The API is broad, and the numerical evidence behind it is uneven: some
estimators are checked against R/Stata on identical data, others only against
known-truth simulations, and many are API-stable without a numerical-parity
claim yet. Every function carries a validation_status that says which case
applies: validation_status distinguishes certified/validated evidence from API-stable breadth. See
Validation before relying
on a number for publication.
Install
Python 3.10 – 3.13 on Linux and macOS. The core install covers estimation, diagnostics, the bundled
datasets, .xlsx / .docx / LaTeX export, and matplotlib figures (.plot(),
sp.ggdid() and the rest). seaborn / plotly styles and heavier backends are
optional extras:
The interactive figure editor additionally needs ipywidgets inside Jupyter.
sp is the convention used throughout these docs, but the alias is your
choice. If sp is already taken in your code (for example by
import scipy as sp), import statspai as si works just as well.
StatsPAI bundles 14 datasets that load offline. Most are real published
extracts (source == "bundled CSV"): Card (1995) NLSYM schooling data,
LaLonde/NSW with a PSID comparison group, the U.S. Senate RD data distributed
with R's rdrobust, California Proposition 99, the castle-doctrine panel, and
NHEFS, among others. A few are deterministic simulated replicas calibrated
to a published design (source == "simulated"), including the
Callaway–Sant'Anna mpdta panel used below; their numbers are not the numbers
from the original data.
At a glance: 1,681 registered functions across 92 submodules; 756k LOC (core) + 519k LOC (tests). Run python scripts/registry_stats.py to reproduce these numbers.
If You Come From Stata Or R
On regress, ivreg, glm, logit, probit, poisson, nbreg, the
ordered / multinomial / conditional logits, the zero-inflated and hurdle
models, liml and more, vce= / robust= follow Stata's vce() grammar
(sp.feols keeps fixest's vcov= / cluster=): True, "robust",
"vce(robust)", "oim", "hc0"–"hc3", and a cluster variable written
inline ("cluster firm", "vce(cluster firm)", "cl firm"). A spelling an
estimator does not implement raises an error instead of quietly falling back
to different standard errors. Robust and cluster SEs apply Stata's
small-sample factors, clustered OLS / IV use t(G-1), and likelihood-based fits
report z. The oim / robust / cluster standard errors of 29 estimators are
pinned to Stata 18 at the 1e-6 parity budget (three documented exceptions
where the two optimisers stop at slightly different points). See the
shared argument grammar guide.
Causal entry points also accept one shared set of argument names next to each
estimator's native spelling: id= for the panel unit, time=,
first_treat= for adoption cohorts, covariates=, and running= /
cutoff= for RD. sp.callaway_santanna(data=mp, y="lemp", time="year", id="countyreal", first_treat="first_treat") is the same call as the
t= / i= / g= version below; a misspelt keyword names the closest one
(runing= → "did you mean 'running'?"), and
sp.describe_function(name)["aliases"] lists the accepted spellings.
sp.esttab(), sp.outreg2(), and sp.modelsummary() still exist, but they are
deprecated thin wrappers over sp.regtable() and emit a DeprecationWarning.
Compared With Other Python Packages
StatsPAI aims to be one broad Stata/R-style workbench. Several focused Python packages do one part of that job, often with a longer track record; if you only need that part, they are good choices.
Use StatsPAI when you want one package, one function registry, and one agent interface across the everyday Stata/R empirical workflow.
Beginner Examples With Results
The outputs below were produced with StatsPAI 1.29.0 on the bundled
datasets and are pinned by tests/test_readme_examples.py, so they cannot
drift from the code silently. Example 6 uses the Stata vce() grammar and
post-estimation commands introduced in 1.29.0; on an older release install
from source with
pip install "statspai @ git+https://github.com/brycewang-stanford/StatsPAI".
Long summaries are abridged (... marks omitted lines); the numbers are pinned
by tests/test_readme_examples.py and tests/test_synth_placebo_pvalue.py, so
they cannot silently drift from the code again.
1. OLS: the first regress / lm replacement
Question: how much higher is log wage for one more year of schooling in the Card (1995) NLSYM data?
Result:
Read it like a Stata/R regression table: conditional on experience, race,
region, and SMSA, one more year of schooling is associated with about 0.074
higher log wage (roughly 7.4%). This is a correlation, not yet a causal return:
schooling is plausibly correlated with unobserved ability, which motivates the
IV in example 2. The HC1 standard errors follow Stata's vce(robust) /
sandwich::vcovHC(type = "HC1") convention.
2. IV / 2SLS: replace ivregress 2sls or AER::ivreg
Question: instrument schooling with growing up near a four-year college
(nearc4).
Result:
The IV estimate (0.132) is larger than OLS but about 13 times less precise.
The instrument is not strong — nearc4 explains only 0.55% of the residual
variation in schooling (first-stage F ≈ 16.7) — and the Hausman test does not
reject exogeneity of educ (p = 0.21). Default standard errors are the
unadjusted ones with the small-sample correction used by AER::ivreg (Stata:
ivregress 2sls ..., small); pass robust="hc1" for heteroskedasticity-robust
errors, and the first-stage F then uses the same variance estimator, as Stata's
estat firststage does.
With a first stage this modest, report a weak-instrument-robust interval too:
3. Staggered DiD: replace csdid or R did
Question: what is the average effect of minimum-wage increases on teen
employment in the Callaway–Sant'Anna mpdta design?
Result:
The aggregated ATT is about -0.033 log points and statistically precise. The
bundled mpdta is a calibrated simulated replica, so this is not the number R
reports on the original mpdta data. What is checked: the same CSV run
through R did::att_gt() + aggte() and Stata csdid returns the same ATT
and standard error (Track A parity module 04_csdid).
4. Regression discontinuity: replace rdrobust
Question: is there a party incumbency advantage at the zero-margin cutoff in U.S. Senate elections?
Result:
The data are the extract of Cattaneo, Frandsen & Titiunik (2015,
doi:10.1515/jci-2013-0010) that ships
with R's rdrobust (the loader keeps its historical name): x is the party's
vote-share margin in the election at time t and y its vote share (0–100) in
the election at t+2, following rdrobust's own illustration. Barely winning at
t raises the vote share at t+2 by about 7.4 percentage points (conventional),
7.5 with robust bias correction; the headline line reports the robust
bias-corrected estimate and CI. On this data
the default MSE-optimal bandwidths, estimates, and standard errors match R
rdrobust::rdrobust() and Stata rdrobust (Track A parity module 06_rd).
Observations are 1,297 because 93 rows have a missing outcome.
5. Synthetic control: replace Stata/R synth
Question: how did California's Proposition 99 affect cigarette sales?
Result:
The estimate says California consumed about 20 fewer packs per capita per year
after the intervention. The p-value is the in-space placebo rank: California's
post/pre RMSPE ratio ranks 3rd of the 39 states, so p = 3/39 ≈ 0.077. This
default matches on pre-treatment outcomes only; pass covariates= (e.g.
["lnincome", "retprice", "age15to24", "beer"]) for an ADH-style predictor
specification. That path re-solves the nested V-W problem for every placebo
state and is much slower: pass n_jobs=-1 to fit the placebos in parallel
(bit-identical results), or placebo=False while iterating on the
specification.
Read this number with its caveat, which the full summary also prints:
classical SCM weights are often not uniquely identified on empirical data, and
different correct solvers can land on different donor weights. StatsPAI's
native solver is certified on uniquely identified designs and labelled
identification-dependent elsewhere. On this specification R Synth reaches an
ATT of about -19.59 rather than -19.51; pass backend="synth" (needs a
local R with the Synth package; outcome-lag specification only) when you need
R's exact numbers.
6. Logit, clustered SEs and post-estimation: Stata's logit + margins
Question: in Thornton's Malawi experiment, how much did a randomly offered cash incentive raise the probability that people collected their HIV test results? Villages are the clusters.
Result:
As in Stata, the 9 rows with a missing age or village id leave the
estimation sample (N = 2,825, 119 villages); the 4 dropped for a missing
cluster variable are reported in a StatsPAIWarning and in
fit.model_info["n_missing_cluster_dropped"].
The logit coefficient is on the log-odds scale; sp.margins reports the effect
on the probability, with a delta-method standard error. any is a 0/1
treatment, so it enters as C(any) (Stata's i.any) and the margin is the
discrete change from 0 to 1. Being offered any incentive raised the probability
of collecting results by about 45 percentage points, close to the raw difference
in means of 45.1 points. Without C() the column counts as continuous, as in
Stata without i., and margins returns the average slope (0.3558). That slope
is not the effect of the offer. The coefficients, the village-clustered standard
errors, and the marginal effect match Stata 18
logit got i.any distvct male age, vce(cluster villnum) followed by
margins, dydx(any) (0.4500223, SE 0.0217017).
Tests and linear combinations use the full covariance matrix and the fit's own reference distribution (χ² / z here, F / t after OLS):
If you already have the Stata lines, run them as they are:
sp.stata returns the output of the last line — here the same marginal-effects
table. A line it cannot translate faithfully (for example xtreg, fe without
the panel id that xtset would have supplied) raises instead of running a
different model; sp.from_stata(line) shows the Python call without running
it.
Export Results
sp.regtable() is the single table builder behind every format. Build the table
once, then write it wherever your co-authors need it:
[sp.regtable export — Card 1995 OLS + IV table]
[sp.regtable export — LaLonde/NSW earnings regressions]
The images are the .xlsx files written by tbl.to_excel(), rendered with
LibreOffice: the Card (1995) table above, and a LaLonde/NSW table regressing
1978 earnings on NSW treatment with a PSID comparison group. The LaLonde table
is also a warning about observational comparisons: the treatment coefficient
moves from -635 to +1,551 once pre-treatment earnings and demographics are
controlled for. See the
export guide for journal
templates, standard-error formats, and single-model exports.
Interactive Plot Editing
If you miss Stata's Graph Editor, use sp.interactive(fig) on any matplotlib
figure returned by StatsPAI. In Jupyter it opens an editing panel next to a
live preview, so beginners can adjust a figure without learning every
matplotlib option first. Requires pip install ipywidgets.
What it is for:
- change titles, labels, fonts, colors, markers, line widths, grids, legends (including entry names), axis limits, figure size, and export DPI;
- recolor a series together with its error bars and confidence band, or apply
a palette such as
okabe_ito(color-blind safe) orgrayscale; - switch among StatsPAI's publication themes (
academic,aea,minimal,cn_journal) and the built-in matplotlib and seaborn styles, for this figure only; - keep the data layer locked (
protect_data=Trueby default): axis limits never hide a point, error bar or band, and data cannot be made invisible; - export reproducible Python code for the edits. Tests check, pixel for pixel, that the code reproduces the edited figure and that undo restores the original;
- save journal-ready PDFs with embedded TrueType fonts, and run
editor.check()for text that is too small or series that look alike in black and white.
Outside a notebook (scripts, servers, agents) pass the edits as a list:
sp.interactive(fig, actions=[{"action": "apply_theme", "theme": "aea"}]).
See the figure editor guide.
[StatsPAI interactive plot editor screenshot]
The screenshot above shows the intended workflow: preview on one side, editing controls on the other, and code export for reproducibility.
Everyday Workflow
Useful docs:
- Getting started and Cookbook
- Choosing an estimator: DiD, IV, RD, matching, synthetic control
- Migrating: from R, Stata/R command translators, shared argument grammar
- Exporting regression tables
- Agents: agent API, MCP workflow for economists
- Evidence: stability and validation tiers, parity matrix, tier census
Using StatsPAI From An Agent
The same registry that powers sp.help() is exposed three ways.
In Python — discover functions and their schemas without reading source:
From the shell — statspai list, statspai describe rdrobust,
statspai search "synthetic control"; and estimation with the same payload an
MCP client gets: statspai run callaway_santanna --data panel.csv --arg y=lemp --arg g=first_treat --arg t=year --arg i=countyreal, or the schema-driven
shortcuts statspai did --data panel.csv --y lemp --treat treated --time year --id id. statspai route did --answer design=staggered routes a question to
estimators without data; statspai mcp starts the server.
Over MCP — the package installs a statspai-mcp stdio server (pure Python,
no extra dependencies). By default it lists the hand-curated estimators,
workflow and pipeline tools plus three discovery meta-tools
(search_functions → describe_function → call_function) that reach every
registered function; statspai-mcp --profile full advertises every
auto-generated tool as its own entry (several hundred, about 2 MB, more than
a client context window holds; for schema dumps and debugging). Clients that
connect to a URL use statspai-mcp --transport http (binds
127.0.0.1:8765/mcp by default; any other address needs
STATSPAI_MCP_HTTP_TOKEN). It also ships
workflow prompts (for example audit_did_result, stata_command_workflow)
and resources such as statspai://catalog. Tools take a data_path (CSV,
Stata .dta, and other formats pandas can read) and return structured JSON
with data provenance, captured runtime warnings and any unsupported
arguments. For Claude Code:
For Claude Desktop, Cursor, and other clients:
See the MCP workflow guide for data handoff, result handles, and the recommended detect → estimate → audit loop.
As a Claude Code skill — statspai skill install copies the packaged
statspai-analysis skill (applied-econ / epidemiology / ML-causal pipelines
with paper-ready exports) into ~/.claude/skills; statspai skill validate
re-checks every API claim in it against the installed package, and with --run
executes its pipelines on synthetic data. The installed skill is a copy and does
not follow package upgrades: statspai skill status reports whether it is
current, statspai skill install --force refreshes it. Agents using the
library start at AGENTS.md and llms.txt.
Validation: What Has Been Checked, And What Has Not
StatsPAI has a large API surface, so validation status matters.
Every registered function carries one of these tiers (counts at the last
release; sp.list_functions(validation_status=...) gives the live numbers):
In other words, 1,026 of the 1,681 registered functions carry numerical evidence. Breadth is not the same as validation; check the tier of the functions you depend on.
The evidence scorecard puts the four checks a specialist makes on one page, each regenerated from committed artifacts: agreement with R / Stata on the same data, confidence interval coverage in Monte Carlo, speed against the reference on the same task, and the estimators that still have no evidence.
Cross-language parity, made queryable
The tiers above are derived from an auditable parity index: every verified
function records what it was aligned against, to what tolerance, on which test,
and how closely it matched. Each row traces to a committed test artifact (the
pinned StatsPAI ↔ R ↔ Stata harness, version-locked via renv.lock + per-run
provenance) — nothing is asserted from memory.
Grades: bit-exact (headline relative error ≤ 1e-6 against a named R/Stata
reference), aligned (a documented, pre-registered looser tolerance),
analytical-only (recovers a known DGP truth or closed-form identity),
external-replication (reproduces published-paper numbers), and unverified
(registered but no parity evidence attached yet — the honest gap). The full,
auto-generated matrix is published at
docs/parity.md.
For your own data, sp.cross_validate re-runs one estimand through every
independent engine installed locally and reports whether they agree:
Engines that are not installed (pyfixest, or R with fixest) are skipped. Every
engine is asked for the same variance estimator (including cluster= and
vcov=) and the same small-sample convention, so the standard errors are
compared as well as the point estimates.
Beyond point-parity, a Track-B coverage study runs B=1000 Monte Carlo
replications per estimator and checks that 95% confidence intervals hit their
nominal rate on known-truth DGPs, against a 99% Wilson acceptance band of
[0.935, 0.967]. The thirteen materialized nominal rows (twelve known-truth DGPs) — OLS on an RCT (0.952),
a 2×2 DiD (0.955), strong-instrument IV (0.962), Callaway–Sant'Anna staggered
ATT (0.947), Sun–Abraham overall ATT (0.950), a two-way FE panel through sp.panel (0.948) and through sp.fast.feols (0.955),
entropy balancing (0.945), a causal-forest AIPW ATE at 2,000 trees (0.959), DML
IRM ATE (0.968), SDID with placebo SEs (0.928), sharp RD with the robust CI
(0.934), and DML PLR with the default learners (0.883) — each also record bias,
Monte Carlo SD and SE calibration. The SDID and RD shortfalls come with
calibrated SEs (RD's intervals equal R rdrobust's draw by draw); the PLR
shortfall is regularisation bias of the default gradient-boosting nuisances
(0.95 with the true nuisances); see tests/coverage_monte_carlo/FINDINGS.md. The committed artifacts live under
tests/coverage_monte_carlo/results_b1000/.
Life Cycle
StatsPAI is in active development (PyPI status "Beta") and uses semantic
versioning. Releases add functions and optional parameters, but a stable
function is never broken without notice.
The old behaviour first warns (DeprecationWarning, or FutureWarning for
a changing default) for at least one minor release, and every such change
is listed in MIGRATION.md. A fix that changes returned
numbers is flagged as a correctness fix there and in the changelog. The 32
core entry points (sp.list_functions(core=True)) have snapshot-tested
signatures. A function marked experimental may change in any minor
release and makes no numerical-validation claim; the tiers above say how
far each function's numbers have been checked. The
glossary
defines these terms.
Changelog
Release notes live outside the README:
- CHANGELOG.md for the full version history.
- MIGRATION.md for deprecations and correctness fixes that change numbers.
- Docs changelog page for the rendered documentation site.
The README is intentionally focused on first-time users.
Paper
StatsPAI is described in a peer-reviewed paper in the Journal of Open Source Software (2026, 11(125), 10604): https://doi.org/10.21105/joss.10604. The reviewer-facing material prepared for that review remains the quickest way to audit the package:
Citation
If you use StatsPAI in research, cite the JOSS paper (preferred) and the
underlying method papers for each estimator. sp.citation() returns the paper
citation, sp.citation(which="software") the versioned software entry, and
many result objects expose estimator-level citation helpers.
[The StatsPAI article page at the Journal of Open Source Software]
The JOSS article page, published 3 September 2026
License
MIT. See LICENSE.
来源:README.md,提交 eb86416
工具
0版本历史
2- v1.43.1最新Nov 13, 2026
- v1.43.0Nov 12, 2026
评分
已满足适用检查项的 50%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通25 分
请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。
- 已声明认证方式10 分
请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分
其他 Stats 集成
Garmin & Strava for Claude and ChatGPT
training.stats官方发布者
一个远程 MCP 端点,让 AI 助手以只读方式访问 Garmin 和 Strava 的运动、睡眠、HRV、准备度和训练负荷数据。

Mcp Tiktok Video Stats
com.mambabuilt
按帖子链接或 ID 读取 TikTok 视频与图文帖的公开数据:播放、点赞、评论、分享、收藏及作者总量。

Zovo Birth Stats Poster
由 GitHub 账号 theluckystrike 发布
根据宝宝姓名、出生日期时间、体重、身长、地点和父母信息,生成可打印的出生数据海报 PDF。

Sports Betting Stats MCP
由 GitHub 账号 GeminiGeorge22 发布
基于 Apify 的 MCP 工具,提供体育博彩赔率、球员盘口、比分、足球 xG、赛马及预测市场套利数据。

Essay Stats Mcp
由 GitHub 账号 AnonymousOnyx22 发布
本地离线运行的 MCP 服务器,可统计字数与页数、评估可读性、标记文风问题,并按字数上限检查文章。