Skip to content

StatsPAI — Ecosystem & Code Statistics

This page tracks StatsPAI's size and coverage against the broader statistical ecosystem, in the spirit of evidence-based positioning. Numbers marked "measured" are reproducible on a standard install; numbers marked "estimated" are extrapolated from public ecosystem statistics with the reasoning shown.

StatsPAI live numbers last measured: 2026-10-07 against the local statspai 1.38.0 source tree (python scripts/registry_stats.py; line counts do not depend on the platform). External ecosystem comparison rows are retained from the 2026-05-03 measurement unless noted otherwise.

The four StatsPAI numbers (function count, submodule count, source LOC, test LOC) are reproducible from a single canonical generator: python scripts/registry_stats.py. The per-module table in §2 is regenerated by python scripts/registry_stats.py --table. CI guards against drift via python scripts/registry_stats.py --check.


1 · Cross-ecosystem lines-of-code

Ecosystem / Project Method Files Lines of code Primary focus
StatsPAI src/statspai/ measured 1,276 735,758 validation-tiered causal inference
StatsPAI tests (tests/) measured 2,340 503,223 —
statsmodels 0.14.x measured 948 381,981 GLM / time series / general
linearmodels measured 131 36,607 panel / IV
Python causal-inference subtotal 1,079 418,588
Stata 18 — official .ado measured 3,767 937,543 command layer above closed kernel
Stata 18 — official .mata measured 411 103,822 Mata numerical layer
Stata official executable code measured 4,178 1,041,365 (+ 738,543 lines of .sthlp help text, not counted as code)
Stata SSC (third-party) estimated ~3,500 pkgs 2M – 4M community extensions; local sample (reghdfe + winsor2 + 50 others) = 33,296 LOC
R base interpreter (C + R + Fortran) estimated — ~1.5M language itself
R base library (73 recommended pkgs) measured 509 62,321 shipped with R on this machine
CRAN (~22,000 packages, 2026) estimated — 80M–120M (R-only; >200M incl. C/C++/Fortran) main R package universe
Bioconductor (~2,300 packages) estimated — 30M–50M bioinformatics
R ecosystem total estimated — ≈ 150M+

How to read this table

LOC is a vanity metric in isolation — what matters is coverage density within a target domain. StatsPAI is deliberately scoped at causal inference and applied econometrics; it is not trying to match R's 150M+ lines because ~90% of CRAN is bioinformatics, visualization, text mining, and general-purpose ML that is out of scope. The relevant comparison is the coverage matrix in §3 below.


2 · StatsPAI per-module breakdown

Sorted by LOC. This table is generated from the live source tree by python scripts/registry_stats.py --table; it intentionally avoids editorial focus labels so the numbers can be refreshed mechanically before a release.

Module LOC Files Registered functions (sp.*)
did 60,280 87 99
agent 51,145 83 4
regression 35,376 47 65
timeseries 34,668 63 88
synth 32,524 47 56
rd 23,783 35 57
smart 17,011 21 31
forest 16,856 18 33
matching 18,726 29 44
inference 17,632 34 59
output 14,926 22 42
mcmc 14,643 25 48
diagnostics 15,478 28 47
core 15,238 27 7
panel 15,329 25 29
dml 10,333 25 17
decomposition 9,940 19 32
iv 9,274 17 10
fast 9,455 20 0
spatial 8,453 32 40
dag 7,048 12 27
plots 8,692 21 9
causal_discovery 6,220 15 26
doe 5,879 14 24
multilevel 5,638 9 11
bayes 5,408 12 20
metalearners 5,342 10 25
mendelian 5,201 13 41
frontier 4,995 8 12
structural 6,108 15 15
utils 6,961 15 42
survival 6,714 12 18
tmle 6,459 11 15
workflow 4,549 5 3
gmm 4,305 12 4
qte 4,129 9 12
robustness 4,099 8 14
network 3,514 9 33
neural_causal 3,450 6 18
postestimation 5,945 11 20
bounds 3,328 7 12
interference 3,789 12 23
bartik 3,209 6 9
causal_llm 3,025 10 15
experimental 4,615 10 23
conformal_causal 2,947 10 22
rlasso 2,859 7 10
crossval 2,812 7 2
epi 2,666 6 21
mediation 3,640 9 7
datasets 2,632 4 5
selection 2,557 5 8
nonparametric 3,117 6 14
fixest 4,938 7 4
policy_learning 2,121 5 8
question 2,103 3 6
power 2,061 5 15
proximal 2,061 8 13
causal_text 1,774 4 4
survey 3,426 10 12
bcf 1,792 5 8
ope 1,869 4 9
fairness 1,500 3 9
target_trial 1,475 7 9
bunching 1,449 5 8
bridge 1,345 8 2
principal_strat 1,238 2 3
mht 1,194 3 7
causal_rl 1,103 5 12
dtr 1,100 5 8
longitudinal 1,076 3 7
dose_response 1,089 3 5
imputation 1,133 4 4
surrogate 1,061 2 3
gformula 987 3 4
deepiv 891 2 2
transport 834 5 10
multivariate 849 3 4
msm 1,091 3 3
causal_impact 954 3 3
assimilation 708 3 4
matrix_completion 685 3 2
multi_treatment 522 2 2
compat 379 2 0
censoring 381 2 2
quasi 357 2 2
geolift 183 2 1
checks 154 2 0
causal 124 1 0
schemas 0 0 0
Total 634,029 1071 1562
## 3 · Causal-inference coverage matrix (full)

Legend: B = broad API coverage within this comparison table; Y = implemented entry points; P = partial, scattered, or single-algorithm support; N = no first-class entry point. These are API-breadth labels, not validation tiers.

"Stata" = official + major SSC packages. "R" = CRAN. "sm+lm" = statsmodels + linearmodels.

# Method family Stata R sm+lm DoubleML StatsPAI StatsPAI entry points
1 DiD — staggered (CS / SA / BJS / dCdH / Gardner / Wooldridge ET) + event-study + honest CIs (Rambachan-Roth) P Y N N B sp.callaway_santanna, sp.sun_abraham, sp.borusyak_jaravel_spiess, sp.dchd, sp.gardner_did, sp.wooldridge_did, sp.honest_did, sp.cs_report
2 IV — classical (2SLS / LIML / GMM) + modern (Kernel IV / Deep IV / KAN-DeepIV) Y classical only Y classical only P classical (lm) P B sp.ivreg, sp.kernel_iv, sp.deep_iv, sp.kan_deepiv
3 RD — CCT sharp/fuzzy/kink + 2D / boundary + multi-cutoff + honest CIs + ML-CATE (18+ estimators) P (rdrobust SSC) Y (rdrobust) N N B sp.rdrobust, sp.rd2d, sp.rdhte, sp.rd_forest, sp.rd_boost, sp.rdrandinf, sp.rdpower, sp.rdsummary
4 Synthetic Control (ADH / ASCM / gsynth / BSTS / Bayesian / PenSCM / FDID — 20 methods + 6 inference strategies) P (synth SSC) P (7 pkgs: Synth, gsynth, CausalImpact, MSCMT, …) N N B sp.synth(method=...), sp.synth_compare, sp.synth_recommend, sp.synth_power, sp.synth_sensitivity
5 Matching — PS / CEM / optimal / cardinality / one-to-many P (psmatch2 SSC) Y (MatchIt, optmatch) N N Y sp.match, sp.cem, sp.optimal_match, sp.cardinality_match
6 Double / Debiased ML N Y (DoubleML) N Y Y sp.dml(model=...), sp.dml_model_averaging, sp.kernel_dml
7 Meta-Learners (S/T/X/R/DR) + Causal Forest / GRF family N Y (grf, rlearner) N N Y sp.s_learner, sp.t_learner, sp.x_learner, sp.r_learner, sp.dr_learner, sp.causal_forest, sp.iv_forest, sp.multi_arm_forest, sp.lm_forest, sp.causal_survival_forest, sp.quantile_forest, sp.survival_forest
8 TMLE / HAL-TMLE N Y (tmle, hal9001) N N Y sp.tmle, sp.hal_tmle, sp.ctmle
9 Neural causal (TARNet / CFRNet / DragonNet / CEVAE) N N N N B sp.tarnet, sp.cfrnet, sp.dragonnet, sp.cevae
10 Causal discovery (NOTEARS / PC / LiNGAM / GES + deep variants) N P (pcalg) N N B sp.notears, sp.pc_algorithm, sp.lingam, sp.ges
11 Proximal CI (fortified / bidirectional / MTP / double-negative-control / surrogate) N P (pci scattered) N N B sp.proximal, sp.fortified_pci, sp.bidirectional_pci, sp.pci_mtp, sp.double_negative_control
12 QTE / distributional TE / CiC / dist-IV / beyond-avg-LATE / HD panel P (ivqreg) P (qte, Counterfactual) N N Y sp.qte, sp.qdid, sp.cic, sp.distributional_te, sp.dist_iv
13 Mendelian randomization (IVW / Egger / median / mode / MR-PRESSO / MVMR / BMA) N Y (MendelianRandomization, TwoSampleMR) N N Y sp.mr_ivw, sp.mr_egger, sp.mr_median, sp.mr_presso, sp.mvmr, sp.mr_bma
14 Conformal causal inference (ITE / CATE / density / dose-response / cluster / fair) N N N N B sp.conformal_ite, sp.conformal_cate, sp.conformal_dose_response
15 Bayesian causal (BCF / ordinal BCF / factor-exposure BCF) N P (bcf) N N Y sp.bcf, sp.bcf_ordinal, sp.bcf_factor_exposure
16 Spatial econometrics (weights → ESDA → ML/GMM → GWR/MGWR → panel) N P (5 pkgs: spdep, spatialreg, sphet, splm, GWmodel) N N B 38 functions including sp.sem, sp.sar, sp.gwr, sp.mgwr, sp.splm
17 Policy learning / OPE N P (policytree) N N Y sp.policy_tree, sp.policy_value, sp.doubly_robust_ope
18 Bunching estimation P (bunching SSC) N N N Y sp.bunching, sp.kink_bunching
19 Interference / spillover (partial / network / cluster-RCT / HTE) N P (interference) N N B 18 functions including sp.spillover, sp.cluster_rct, sp.hte_interference
20 Matrix completion for panels N P (gsynth) N N Y sp.matrix_completion
21 Causal MAS (multi-agent LLM causal discovery — arXiv:2509.00987) N N N N B sp.causal_mas, sp.causal_llm.openai_client, sp.causal_llm.anthropic_client
22 Publication tables (Word / Excel / LaTeX / HTML / Markdown) P (outreg2) P (modelsummary) P N B Supported result objects expose .to_word() / .to_excel() / .to_latex() / .to_html()
23 Agent-native tool-calling schemas (function_schema()) N N N N B sp.list_functions(), sp.describe_function(), sp.function_schema(), sp.agent.mcp_server

4 · How to reproduce these numbers

# StatsPAI (Python)
find src/statspai -name '*.py' -exec wc -l {} + | tail -1
find tests        -name '*.py' -exec wc -l {} + | tail -1
python3 -c "import statspai as sp; print(len(sp.list_functions()))"

# statsmodels + linearmodels
python3 -c "import statsmodels, os; print(os.path.dirname(statsmodels.__file__))"
python3 -c "import linearmodels, os; print(os.path.dirname(linearmodels.__file__))"
find $(python3 -c "import statsmodels,os;print(os.path.dirname(statsmodels.__file__))") -name '*.py' -exec wc -l {} + | tail -1
find $(python3 -c "import linearmodels,os;print(os.path.dirname(linearmodels.__file__))") -name '*.py' -exec wc -l {} + | tail -1

# Stata (macOS default install path)
find /Applications/Stata/ado/base -name '*.ado'  | xargs wc -l | tail -1
find /Applications/Stata/ado/base -name '*.mata' | xargs wc -l | tail -1

# R (installed library only; base-interpreter source requires R-<version>.tar.gz)
find /Library/Frameworks/R.framework/Resources/library \( -name '*.R' -o -name '*.r' \) -exec wc -l {} + | tail -1

Ecosystem-wide estimates (SSC / CRAN / Bioconductor totals) are drawn from:

The SSC sample used for extrapolation is the 52-file local install (/Users/brycewang/Library/Application Support/Stata/ado/plus, 33,296 LOC — includes reghdfe, winsor2, and others).


5 · Why we don't lead with "line-count wins"

Three reasons a naked LOC comparison is misleading for StatsPAI positioning:

  1. Vanity metric: 188K vs R's 150M+ tells a reviewer nothing about capability per line. R's CRAN is ~90% out-of-scope (bioinformatics, visualization, text, general ML) — apples to oranges.
  2. Moving target: CRAN and statsmodels grow every month. A headline number in the README rots quarterly unless regenerated by CI.
  3. Wrong axis: StatsPAI's differentiator is causal-inference depth in one API — see §3. Most cells where we win are ❌ in Stata / R / statsmodels entirely, not "fewer lines".

The coverage matrix in §3 is the honest positioning. LOC in §1 is supporting evidence for "yes, there is real code behind these claims" — not a competitive boast.