Exporting and persisting results

import numpy as np
import pandas as pd
import statsmodels.api as sm
import statsmodels.formula.api as smf
from pymargins import Margins

rng = np.random.default_rng(42)
n = 2000
df = pd.DataFrame({
    "age": rng.integers(20, 75, n),
    "female": rng.binomial(1, 0.52, n),
})
lp = -1.5 + 0.04 * df["age"] - 0.3 * df["female"]
df["y"] = rng.binomial(1, 1 / (1 + np.exp(-lp)))

fit = smf.glm("y ~ age + female", data=df,
              family=sm.families.Binomial()).fit()
m = Margins.log_scale(fit, at="overall")

Every MarginsResult can be printed, framed, or serialized to LaTeX / HTML for inclusion in papers and reports.

res = m.dydx("age", atexog={"female": [0, 1]})

print(res.summary(stars=True))      # text table with significance stars
res.to_frame()                      # pandas.DataFrame
print(res.to_latex())               # LaTeX tabular
print(res.to_html())                # HTML <table>
=========================================================================
                    Margins Result (delta, level=0.95)                   
=========================================================================
                     estimate  std err         z  P>|z|  [95% Conf. Int.]
-------------------------------------------------------------------------
female=[0, 1], age  0.0090***   0.0711  -66.1769  0.000    0.0079, 0.0104
=========================================================================

n = 2000
Note: std err is on the inference scale; estimate and CI are on the reporting scale.
κ: 0.079
Delta-vs-sim disagreement: 3.503%
\begin{tabular}{lrrrr}
\hline
\hline
 & estimate & std err & z & P>|z| & [95\% Conf. Int.] \\
\hline
female=[0, 1], age & 0.0090 & 0.0711 & -66.1769 & 0.000 & 0.0079, 0.0104 \\
\hline
\hline
\end{tabular}
<table class="pymargins-result">
<thead>
<tr><th></th><th>estimate</th><th>std err</th><th>z</th><th>P>|z|</th><th>[95% Conf. Int.]</th></tr>
</thead>
<tbody>
<tr><td>female=[0, 1], age</td><td>0.0090</td><td>0.0711</td><td>-66.1769</td><td>0.000</td><td>0.0079, 0.0104</td></tr>
</tbody>
</table>

Saving to CSV, Excel, or Parquet

to_frame() returns a tidy pandas.DataFrame, so any pandas export works out of the box:

df = res.to_frame()
df.to_csv("ame_results.csv", index=False)
df.to_excel("ame_results.xlsx", index=False)
df.to_parquet("ame_results.parquet")

The DataFrame includes scenario columns (e.g. age, female) when available, making it ready for downstream plotting or reporting without string parsing.

Long-term storage with to_disk / from_disk

For checkpointing or sharing results between scripts, use the built-in pickle persistence methods. They automatically materialize the result (so the saved object is self-contained) and include a version check on load:

# Save
res.to_disk("ame_results.pkl")

# Load in another session
from pymargins import MarginsResult
loaded = MarginsResult.from_disk("ame_results.pkl")
print(loaded.summary())
=======================================================
           Margins Result (delta, level=0.95)          
=======================================================
                    estimate  std err  [95% Conf. Int.]
-------------------------------------------------------
female=[0, 1], age    0.0090   0.0711    0.0079, 0.0104
=======================================================

n = 2000
Note: std err is on the inference scale; estimate and CI are on the reporting scale.
κ: 0.079
Delta-vs-sim disagreement: 3.503%
/home/hunter/Workspace/pymargins/pymargins/_result/_margins.py:271: UserWarning: Test statistics omitted from summary: Cannot run test: result has neither gradient nor draws.
  rows = self._summary_rows()

Materialised results support .summary(), .to_frame(), .to_latex(), and .to_html(), but they cannot recompute CIs at new confidence levels or run new hypothesis tests because the gradient and session reference are dropped during materialisation.

In-memory slimming with materialize

If you only need to reduce memory inside a single Python session (e.g. when accumulating many results in a loop), call materialize() directly:

slim = res.materialize()           # estimates/SE/CI only; drops gradients
print(slim.summary())
=======================================================
           Margins Result (delta, level=0.95)          
=======================================================
                    estimate  std err  [95% Conf. Int.]
-------------------------------------------------------
female=[0, 1], age    0.0090   0.0711    0.0079, 0.0104
=======================================================

n = 2000
Note: std err is on the inference scale; estimate and CI are on the reporting scale.
κ: 0.079
Delta-vs-sim disagreement: 3.503%

Materialised results still support arithmetic (+, -, *, /, .scaled(by=...)) for post-hoc combination. The only thing you lose is the ability to call .conf_int(level=...) when the original session used the delta method (recomputing CIs at new levels requires the gradient, which is dropped).