statspai.core¶
core ¶
Core package initialization
BaseModel ¶
Bases: ABC
Abstract base class for all econometric models
fit
abstractmethod
¶
fit(**kwargs: Any) -> EconometricResults
predict
abstractmethod
¶
Generate predictions from the fitted model
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
DataFrame
|
Data for prediction. If None, uses training data. |
None
|
Returns:
| Type | Description |
|---|---|
ndarray
|
Predicted values |
summary ¶
Return a summary of the fitted model
Returns:
| Type | Description |
|---|---|
str
|
Model summary |
BaseEstimator ¶
Bases: ABC
Abstract base class for estimation algorithms
estimate
abstractmethod
¶
Estimate model parameters
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y
|
ndarray
|
Dependent variable |
required |
X
|
ndarray
|
Independent variables |
required |
**kwargs
|
Any
|
Additional estimation options |
{}
|
Returns:
| Type | Description |
|---|---|
Dict[str, Any]
|
Estimation results including parameters, standard errors, etc. |
EconometricResults ¶
Unified results class for econometric models
This class provides a consistent interface for accessing results from different econometric estimators, similar to R's broom package.
Examples:
>>> import statspai as sp
>>> import numpy as np
>>> import pandas as pd
>>> rng = np.random.default_rng(0)
>>> x = rng.normal(size=50)
>>> df = pd.DataFrame({"y": 2.0 * x + rng.normal(size=50), "x": x})
>>> res = sp.regress("y ~ x", data=df)
>>> type(res).__name__
'EconometricResults'
>>> round(float(res.params["x"]), 1)
1.9
n_obs
property
writable
¶
Alias of :attr:nobs, the name :class:CausalResult uses.
A fit that recorded no sample size has no n_obs (the attribute
raises AttributeError), so hasattr(result, "n_obs") keeps
meaning "the sample size is known".
vcov ¶
Covariance matrix of :attr:params, labelled by coefficient.
The matrix behind the reported standard errors (its diagonal equals
std_errors ** 2). Raises when the fit stores no such matrix --
e.g. standard errors replaced after the fit by a bootstrap -- rather
than returning a diagonal matrix that would claim the estimates are
uncorrelated.
Examples:
>>> import statspai as sp, numpy as np, pandas as pd
>>> rng = np.random.default_rng(0)
>>> x = rng.normal(size=50)
>>> df = pd.DataFrame({"y": 2.0 * x + rng.normal(size=50), "x": x})
>>> res = sp.regress("y ~ x", data=df)
>>> V = res.vcov()
>>> bool(np.allclose(np.sqrt(np.diag(V)), res.std_errors))
True
summary ¶
Generate a summary table of results
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
alpha
|
float
|
Significance level for confidence intervals. Defaults to the
level requested at fit time (0.05 unless the estimator was
called with |
None
|
Returns:
| Type | Description |
|---|---|
str
|
Formatted summary table |
inference_rule ¶
The variance, reference distribution and small-sample convention.
Coefficients and standard errors can agree with another program
while t / F / p values do not, because the statistics are referred
to a different distribution (t(N-K), t(G-1) or z) or the variance
carries a different finite-sample factor. This states the rule the
fit used, as recorded by the estimator; summary() prints it.
Returns:
| Type | Description |
|---|---|
dict
|
|
Examples:
conf_int ¶
Return confidence intervals for parameters
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
alpha
|
float
|
Significance level. Defaults to the fit-time level (0.05 unless
the estimator was called with |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
Confidence intervals |
tidy ¶
Return a long-format DataFrame of coefficients, broom-style.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
conf_level
|
float
|
Confidence level of the interval columns. Defaults to the
fit-time level (0.95 unless the estimator was called with
|
None
|
Columns
term : str Variable / coefficient name. estimate : float std_error : float statistic : float t-statistic. p_value : float conf_low, conf_high : float Two-sided conf_level CI.
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> df = pd.DataFrame({"x1": rng.normal(size=100), "x2": rng.normal(size=100)})
>>> df["y"] = 1 + df.x1 - df.x2 + rng.normal(size=100)
>>> result = sp.regress("y ~ x1 + x2", data=df)
>>> result.tidy().columns[:3].tolist()
['term', 'estimate', 'std_error']
See Also
glance : 1-row model-level summary (R^2, F, N, AIC, BIC).
coef ¶
One coefficient's full inference row as a named Series.
Shorthand for result.tidy().set_index("term").loc[term] —
the estimate, standard error, t-statistic, p-value, and CI for
a single term without the indexing dance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
term
|
str
|
Coefficient name as it appears in |
required |
conf_level
|
float
|
CI level for |
None
|
Returns:
| Type | Description |
|---|---|
Series
|
Index: |
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> x = rng.normal(size=200)
>>> df = pd.DataFrame({"y": 2.0 * x + rng.normal(size=200), "x": x})
>>> row = sp.regress("y ~ x", data=df).coef("x")
>>> bool(abs(row["estimate"] - 2.0) < 0.2)
True
>>> bool(row["p_value"] < 0.01)
True
test ¶
Wald test of linear restrictions -- Stata's test after a fit.
Shorthand for :func:statspai.test (result, hypothesis).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hypothesis
|
str
|
|
required |
Returns:
| Type | Description |
|---|---|
dict
|
|
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> x1, x2 = rng.normal(size=200), rng.normal(size=200)
>>> df = pd.DataFrame({"y": x1 + x2 + rng.normal(size=200),
... "x1": x1, "x2": x2})
>>> out = sp.regress("y ~ x1 + x2", data=df).test("x1 = x2")
>>> bool(out["pvalue"] > 0.01)
True
lincom ¶
Linear combination of coefficients -- Stata's lincom.
Shorthand for :func:statspai.lincom (result, expression, alpha).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
expression
|
str
|
|
required |
alpha
|
float
|
Significance level for the confidence interval. |
0.05
|
Returns:
| Type | Description |
|---|---|
dict
|
Estimate, standard error, test statistic, p-value and CI. |
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> x1, x2 = rng.normal(size=200), rng.normal(size=200)
>>> df = pd.DataFrame({"y": x1 + x2 + rng.normal(size=200),
... "x1": x1, "x2": x2})
>>> out = sp.regress("y ~ x1 + x2", data=df).lincom("x1 + x2")
>>> sorted(out)
['ci', 'df', 'distribution', 'estimate', 'expression', 'pvalue', 'se',
'statistic', 'z']
glance ¶
Return a 1-row DataFrame of model-level statistics, broom-style.
Columns (present subset depends on the model type)
nobs : int r_squared : float adj_r_squared : float f_statistic : float f_p_value : float aic, bic : float df_resid, df_model : int method : str Estimation method label.
See Also
tidy : long-format coefficient table.
fixef ¶
Estimated fixed effects of a sp.feols / fepois / feglm fit.
R fixest::fixef / Stata reghdfe, savefe: one Series per
absorbed effect, indexed by its levels, on the scale of the linear
index. Effects are identified up to one constant per connected set
of levels (per additional effect); the normalisation is fixest's
(see :mod:statspai.fixest._fixef). Sums of effects, and so
predictions, do not depend on it.
Returns:
| Type | Description |
|---|---|
dict of str to pd.Series
|
|
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> d = pd.DataFrame({"g": rng.integers(0, 5, 200), "x": rng.normal(size=200)})
>>> d["y"] = d.g + 0.5 * d.x + rng.normal(size=200)
>>> fit = sp.feols("y ~ x | g", d)
>>> fe = fit.fixef()["g"]
>>> len(fe)
5
predict ¶
predict(data: Optional[DataFrame] = None, what: str = 'mean', alpha: float = 0.05, *, newdata: Optional[DataFrame] = None) -> Union[ndarray, DataFrame]
Generate predictions from the fitted model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
DataFrame
|
New data for out-of-sample prediction, holding the variables of
the formula (the design -- |
None
|
what
|
(mean, link, confidence, prediction)
|
|
"mean"
|
alpha
|
float
|
One minus the coverage of the interval. |
0.05
|
newdata
|
DataFrame
|
Alias of |
None
|
Returns:
| Type | Description |
|---|---|
ndarray or DataFrame
|
The predictions ( |
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> df = pd.DataFrame({"x": rng.normal(size=200)})
>>> df["y"] = 1.0 + 0.5 * df["x"] + rng.normal(size=200)
>>> fit = sp.regress("y ~ x + I(x**2)", data=df)
>>> new = pd.DataFrame({"x": [0.0, 1.0]})
>>> fit.predict(new).shape
(2,)
>>> list(fit.predict(new, what="prediction").columns)
['yhat', 'se', 'lower', 'upper']
residuals ¶
Return model residuals if available
Returns:
| Type | Description |
|---|---|
ndarray or None
|
Residuals |
fitted_values ¶
Return fitted values if available
Returns:
| Type | Description |
|---|---|
ndarray or None
|
Fitted values |
next_steps ¶
Agent-native workflow guidance: what to do after fitting this model.
Returns a list of recommended next steps — diagnostics, robustness checks, sensitivity analysis, and export options — tailored to the model type (OLS, IV, panel, etc.).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
print_result
|
bool
|
Also print the formatted recommendations to stdout. Off by
default so calling |
False
|
Returns:
| Type | Description |
|---|---|
list of dict
|
Each dict has keys: |
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> df = pd.DataFrame({"x1": rng.normal(size=100), "x2": rng.normal(size=100)})
>>> df["y"] = 1 + df.x1 - df.x2 + rng.normal(size=100)
>>> result = sp.regress("y ~ x1 + x2", data=df)
>>> steps = result.next_steps(print_result=False)
>>> steps[0]["action"]
"sp.estat(result, 'all')"
violations ¶
Agent-native structured list of assumption / diagnostic issues.
Inspects stored diagnostics (first-stage F, standard error
finiteness, …) and returns any flagged concerns as dicts with
keys kind, severity, test, value, threshold,
message, recovery_hint, alternatives.
Returns:
| Type | Description |
|---|---|
list of dict
|
Empty list if nothing flagged. |
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> df = pd.DataFrame({"z": rng.normal(size=300), "c": rng.normal(size=300)})
>>> df["x"] = df.z + rng.normal(size=300)
>>> df["y"] = 1 + 0.5 * df.x + df.c + rng.normal(size=300)
>>> result = sp.iv("y ~ (x ~ z) + c", data=df)
>>> for v in result.violations():
... if v['severity'] == 'error':
... print(v['recovery_hint'])
to_agent_summary ¶
JSON-ready nested summary for agent consumption.
Unlike summary() (prose for humans) and tidy() (long-form
DataFrame), this returns a plain dict with coefficients,
scalar diagnostics, violations, and recommended next steps —
suitable for feeding into an LLM tool loop or logging.
Returns:
| Type | Description |
|---|---|
dict
|
Keys: |
See Also
to_dict :
Canonical flat agent payload — prefer
to_dict(detail="agent") for new code.
to_agent_summary is kept because it surfaces a richer
kind / model_type / robust triplet that to_dict
collapses into a single method field; two methods, two
intentionally different shapes.
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> df = pd.DataFrame({"x1": rng.normal(size=100), "x2": rng.normal(size=100)})
>>> df["y"] = 1 + df.x1 - df.x2 + rng.normal(size=100)
>>> result = sp.regress("y ~ x1", data=df)
>>> import json
>>> agent_payload = json.dumps(result.to_agent_summary(), default=str)
>>> agent_payload.startswith("{")
True
to_docx ¶
Export results to a Word (.docx) document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
Output path (.docx). |
required |
title
|
str
|
Table title. Defaults to model type. |
None
|
to_latex ¶
to_latex(path: Optional[str] = None, *, caption: Optional[str] = None, label: Optional[str] = None, siunitx: bool = False, threeparttable: bool = False, siunitx_preamble: bool = False, booktabs: bool = False, **kwargs: Any) -> str
Render the regression result as a publication-quality LaTeX table.
A thin wrapper over :func:~statspai.output.regtable (single
column). Produces a \begin{table} float with significance
stars and standard errors in parentheses; booktabs=True draws
\toprule / \midrule / \bottomrule rules.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
If given, the LaTeX source is also written to this file (UTF-8). The string is always returned. |
None
|
caption
|
str
|
|
None
|
label
|
str
|
|
None
|
siunitx
|
bool
|
Decimal-align numeric columns with |
False
|
threeparttable
|
bool
|
Wrap the table in |
False
|
siunitx_preamble
|
bool
|
Prepend a comment listing the required |
False
|
booktabs
|
bool
|
|
False
|
**kwargs
|
Any
|
Forwarded to :func: |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
LaTeX source. |
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> df = pd.DataFrame({"z": rng.normal(size=300), "c": rng.normal(size=300)})
>>> df["x"] = df.z + rng.normal(size=300)
>>> df["y"] = 1 + 0.5 * df.x + df.c + rng.normal(size=300)
>>> r = sp.regress("y ~ x + z", data=df)
>>> tex = r.to_latex(caption="Main results", label="tab:main",
... coef_labels={"x": "Treatment"}, template="aer")
>>> tex = r.to_latex(siunitx=True, threeparttable=True) # journal style
to_html ¶
Render the regression result as an HTML table.
A thin wrapper over :func:~statspai.output.regtable. Returns the
HTML string; also writes it to path when given. See
:meth:to_latex for the forwarded **kwargs.
to_markdown ¶
Render the regression result as a Markdown table.
A thin wrapper over :func:~statspai.output.regtable. Set
quarto=True for Quarto-flavoured output. Returns the Markdown
string; also writes it to path when given. See :meth:to_latex
for the forwarded **kwargs.
to_excel ¶
Write the regression result to a styled .xlsx workbook.
A thin wrapper over :func:~statspai.output.regtable with
booktabs-style cell borders (requires openpyxl). Returns
path. See :meth:to_latex for the forwarded **kwargs.
to_word ¶
Write the regression result to a publication-quality .docx.
A thin wrapper over :func:~statspai.output.regtable with AER/QJE
booktabs rules and Times New Roman typography (requires
python-docx). Returns path. Unlike :meth:to_docx (which
renders the broom-style coefficient grid), this routes through the
same publication table builder used for multi-model exports, so the
single-model output matches a one-column regtable. See
:meth:to_latex for the forwarded **kwargs.
plot ¶
Coefficient plot of this fit (sp.coefplot).
type is 'auto' or 'coefplot'; **kwargs go to
:func:statspai.coefplot (variables=, drop=["Intercept"],
alpha=, ax= ...). Returns (fig, ax).
to_dict ¶
Return a JSON-safe dict representation of the regression result.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
detail
|
(minimal, standard, agent)
|
Payload depth, bounded by approximate token budget:
|
"minimal"
|
Returns:
| Type | Description |
|---|---|
dict
|
JSON-safe and bounded — round-trips through |
Notes
Used by sp.agent.execute_tool to send results back to an
LLM, and useful for caching / pickling-free persistence.
result_card ¶
Auditable card: estimand, sample, specification, inference, provenance, configuration-level evidence, assumptions, limitations.
See :func:statspai.result_card.
cite ¶
Return the canonical citation for this estimator, if registered.
Mirrors :meth:CausalResult.cite so an agent can call .cite() on
any fitted result uniformly — and sp.bib_for(result) (which
duck-types on .cite) now works for regression results too.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
format
|
(bibtex, apa, json)
|
Same semantics as :meth: |
"bibtex"
|
Returns:
| Type | Description |
|---|---|
str | dict
|
|
Notes
Zero-hallucination (CLAUDE.md §10): BibTeX comes from the single source
of truth CausalResult._CITATIONS (mirroring :file:paper.bib); APA /
JSON forms are derived from that string, never generated. Resolution is
exact on model_info['citation_key'] → model_type → method
(normalised), so a textbook estimator with no canonical paper (OLS /
logit / probit / poisson) honestly returns a placeholder rather than a
fuzzy — and possibly wrong — match. Estimators that do have a canonical
reference (e.g. tobit, heckman) should set model_info['citation_key']
or carry a matching model_type.
to_appendix ¶
to_appendix(format: str = 'latex', *, include_assumptions: bool = True, include_diagnostics: bool = True, include_citation: bool = True, include_provenance: bool = True) -> str
Generate a Methods and Formulas appendix for this model.
Shares the curated, zero-hallucination methods table with
:class:CausalResult (CLAUDE.md §10). IV / 2SLS regressions resolve
to the instrumental-variables entry; other regression families that
are not in the causal methods table degrade to an explicit placeholder
plus the inference actually used and a provenance trace — never an
invented formula.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
format
|
(latex, markdown, text)
|
Output format. |
"latex"
|
include_assumptions
|
bool
|
Include the identifying-assumptions list (when registered). |
True
|
include_diagnostics
|
bool
|
Include the inference block read off |
True
|
include_citation
|
bool
|
Append the APA-style reference from :meth: |
True
|
include_provenance
|
bool
|
Append a one-line provenance trace (StatsPAI version + estimator identity + methods-spec key). |
True
|
Returns:
| Type | Description |
|---|---|
str
|
The assembled appendix. |
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> df = pd.DataFrame({"z": rng.normal(size=300), "c": rng.normal(size=300)})
>>> df["x"] = df.z + rng.normal(size=300)
>>> df["y"] = 1 + 0.5 * df.x + df.c + rng.normal(size=300)
>>> res = sp.ivreg("y ~ c + (x ~ z)", data=df)
>>> md = res.to_appendix(format="markdown")
>>> isinstance(md, str) and len(md) > 0
True
for_agent ¶
Agent-ready payload — alias for to_dict(detail="agent").
Kept for backward compatibility with code written before the
unified detail parameter. New code should prefer
to_dict(detail="agent") for explicit semantics.
brief ¶
One-line dashboard status string (≤ ~120 chars).
Surfaces the most-significant non-intercept coefficient so
agents scanning a list of regressions can spot the active
finding without paying a full to_dict round-trip.
to_json ¶
Serialise :meth:to_dict via json.dumps.
detail is forwarded to :meth:to_dict; pass "agent" to
include violations / next_steps / degradations in the JSON.
sensitivity ¶
Run the unified sensitivity dashboard on this result.
See :func:statspai.robustness.unified_sensitivity.