API reference

Stata-style margins for StatsModels with delta-method standard errors.

For a fitted model with parameter vector \(\hat\beta\), estimated covariance \(\widehat V(\hat\beta)\), and a (possibly vector-valued) statistic \(g(\beta)\), the delta method gives

\[\widehat{\operatorname{Var}}\bigl[g(\hat\beta)\bigr] \;\approx\; G\,\widehat V\,G^\top, \qquad G = \left.\frac{\partial g}{\partial \beta}\right|_{\hat\beta}.\]

Statistics

This module supports every statistic discussed in Richard Williams’ Using the margins command notes (Margins01):

AAP

\((1/n)\sum_i f(x_i^\top\beta)\) (avg adj. prediction)

APM

\(f(\bar x^\top\beta)\) (prediction at means)

APR

AAP with some \(x\) fixed at representative values

AME

\((1/n)\sum_i \partial f(x_i^\top\beta)/\partial x_{ij}\)

MEM

\(\partial f(\bar x^\top\beta)/\partial x_j\) (ME at means)

MER

AME with some \(x\) held at representative values

where \(f\) is the response-scale map (identity for OLS, inverse link for GLMs, etc.).

Patsy integration

Rather than hand-differentiating each model’s link / linear-predictor combination, we build every statistic as a function of \(\beta\) using StatsModels’ own model.predict(params, exog). Patsy does the heavy lifting of propagating perturbations through interactions, polynomials, splines, and categorical encodings: when the user says “perturb x1”, we perturb the column of the data frame and let patsy.dmatrix(design_info, ...) rebuild the design matrix. This way I(x1**2), x1:x2, C(group), bs(x1, df=4) all update correctly and automatically.

Examples

Fit a logit, then ask for the average marginal effect of age and the adjusted-prediction profile across age for each sex:

import numpy as np, pandas as pd
import statsmodels.formula.api as smf
from smmargins import Margins

fit = smf.logit("voted ~ age + income + C(educ) + female + age:female",
                data=df).fit()
M = Margins(fit)

M.dydx("age")                                  # AME of age
M.dydx("age", at="mean")                       # MEM
M.dydx("age", atexog={"female": [0, 1]})       # MER, by sex
M.predict(atexog={"age": list(range(20, 91, 10)),
                  "female": [0, 1]})           # plottable table

For a 2x2 difference-in-differences on the response (probability) scale:

res = M.did("group", "preexist_Y",
            group_levels=["A", "B"], condition_levels=[0, 1],
            atexog={"age": 60, "female": 0})
print(res)            # cells, simple effects, DiD
res.did.estimate      # the DiD point estimate
res.cells.vcov        # 4x4 joint covariance of the cell predictions

See demo_margins.py and demo_did.py for end-to-end walkthroughs.

Margins(results[, data, level, use_t, analytic])

Compute adjusted predictions and marginal effects for a StatsModels fit.

MarginsResult(estimate, vcov[, labels, ...])

Container for margin estimates with delta-method standard errors.

DiDResult(cells, simple_effects, did, joint)

Bundle of results from Margins.did().

_central_jacobian(func, x[, rel_step])

Jacobian of func at x via central differences.