analyze_spatial_model
analyze_spatial_model(
df,
outcome=None,
covariates=None,
*,
gdf,
w=None,
model='durbin',
method='ml',
period=None,
entity=None,
time=None,
fixed_effects=None,
impacts=True,
n_draws=10000,
seed=20250620,
spat_diag=False,
title=None,
)Estimate a cross-sectional spatial econometric model with impact decomposition.
One period of the panel (the latest by default) is aligned to the geometry and weights, the requested :mod:spreg model is estimated, and — for models with a spatially lagged outcome or regressors — the per-covariate LeSage-Pace direct/indirect/total impacts are computed from betas + vm (Monte-Carlo standard errors for lag/Durbin models, analytic for SLX/Durbin-error).
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| df | pd.DataFrame | Long panel (or cross-section) holding the outcome and covariates per entity. | required |
| outcome | str | None | Dependent variable. Defaults to the outcome declared via :func:geometrics.set_roles. |
None |
| covariates | str | Sequence[str] | None | Regressor column(s). Default to the covariates declared via :func:geometrics.set_roles. |
None |
| gdf | gpd.GeoDataFrame | Entity geometry carrying the same entity ids as df. |
required |
| w | W | None | libpysal weights aligned to the gdf ids. None builds the default weights (queen contiguity for polygons) with a :class:~geometrics.GeometricsWarning. |
None |
| model | str | "ols", "lag" (SAR), "error" (SEM), "slx", "durbin" (SDM) or "durbin_error" (SDEM). |
'durbin' |
| method | str | "ml" (maximum likelihood) or "gm" (method of moments / GMM; not available for durbin_error). OLS-based models (ols / slx) ignore it. |
'ml' |
| period | Any | Period to model when df has a time dimension; None uses the latest period and records a note. |
None |
| entity | str | None | Panel identifiers; default to the ids declared via :func:geometrics.set_panel. |
None |
| time | str | None | Panel identifiers; default to the ids declared via :func:geometrics.set_panel. |
None |
| fixed_effects | str | None | Categorical column expanded to drop_first dummy regressors (e.g. state fixed effects). Dummies are never spatially lagged when their lag is collinear (full-rank check). |
None |
| impacts | bool | Compute the impact table where defined (lag/durbin: Monte-Carlo; slx/ durbin_error: analytic). OLS and pure error models have no impact decomposition (impacts is None). |
True |
| n_draws | int | Monte-Carlo draws for the impact standard errors. | 10000 |
| seed | int | None | Seed for the Monte-Carlo draws (reproducible by default). | 20250620 |
| spat_diag | bool | For model="ols" only: attach spreg’s spatial diagnostics to the fitted object (see :func:analyze_spatial_diagnostics for the full workflow). |
False |
| title | str | None | Header for the coefficient table. Defaults to the model and outcome labels. | None |
Returns
| Name | Type | Description |
|---|---|---|
| SpatialModelResult | Frozen result with the tidy coefficient frame (df), the Great Tables coefficient table (gt), the fitted spreg object (model_obj), the spatial parameters (rho / lam), fit scalars, the impact table (impacts) and w_spec. |
Raises
| Name | Type | Description |
|---|---|---|
| KeyError | If a requested column is not in df. |
|
| TypeError | If the outcome or a covariate is not numeric. | |
| ValueError | For an unknown model / method, the unsupported durbin_error + gm combination, an unknown period, or too few / degenerate observations. |
Examples
A spatial lag model on a small constructed lattice:
import geopandas as gpd
import numpy as np
import pandas as pd
from shapely.geometry import box
from geometrics.spatial_models import analyze_spatial_model
from geometrics.weights import make_weights
cells = [box(i % 4, i // 4, i % 4 + 1, i // 4 + 1) for i in range(16)]
gdf = gpd.GeoDataFrame(
{"id": [f"r{i}" for i in range(16)]}, geometry=cells, crs="EPSG:4326"
)
rng = np.random.default_rng(0)
df = pd.DataFrame({"id": gdf["id"], "x": rng.normal(size=16)})
df["y"] = 2.0 * df["x"] + rng.normal(scale=0.1, size=16)
res = analyze_spatial_model(
df, "y", ["x"], gdf=gdf, w=make_weights(gdf), model="lag",
entity="id", n_draws=200,
)
print(res.model, res.n_obs, res.impacts.shape)