analyze_spatial_model_by_weights
analyze_spatial_model_by_weights(
df,
outcome=None,
covariates=None,
*,
gdf,
weights=None,
baseline=None,
focal=None,
model='durbin',
period=None,
entity=None,
time=None,
fixed_effects=None,
n_draws=10000,
seed=20250620,
title=None,
)Re-estimate a spatial model under alternative weights and compare the impacts.
The weights-choice robustness check of the source paper (notebook c07): the same model is re-estimated under each spatial weights specification, and the focal regressor’s direct/indirect/total impacts are compared across specifications in a table and a three-facet dot-whisker figure (95% Monte-Carlo confidence intervals, baseline highlighted with a dashed reference line).
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 and regressors; default to the roles declared via :func:geometrics.set_roles. |
None |
| covariates | str | None | Dependent variable and regressors; default to the roles declared via :func:geometrics.set_roles. |
None |
| gdf | gpd.GeoDataFrame | Entity geometry carrying the same entity ids as df. |
required |
| weights | Mapping[str, W] | None | Mapping of specification name to libpysal weights. None builds the paper’s suite from the geometry: 4/6/8-nearest-neighbor, queen and rook contiguity, and inverse distance with powers 1 and 2 (all row-standardized). |
None |
| baseline | str | None | Name of the reference specification (highlighted in the figure). Defaults to the first key of weights. |
None |
| focal | str | None | Covariate whose impacts are compared. Defaults to the first covariate. | None |
| model | str | "lag", "slx", "durbin" (default) or "durbin_error" — a model with a defined impact decomposition. Estimated by ML. |
'durbin' |
| period | Any | Period to model; 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 dummies in each design. |
None |
| n_draws | int | Monte-Carlo draws for the impact standard errors (the RNG is re-seeded per weights specification, so rows are reproducible individually). | 10000 |
| seed | int | None | Seed for the Monte-Carlo draws. | 20250620 |
| title | str | None | Figure title. Defaults to a title naming the focal regressor. | None |
Returns
| Name | Type | Description |
|---|---|---|
| WeightsRobustnessResult | Frozen result with one row per specification (weights, rho, direct / indirect / total and their standard errors, aic, n_obs, w_spec), the dot-whisker figure and the comparison table. |
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 a model without impacts (ols / error), an empty weights mapping, an unknown baseline or focal, or degenerate data. |
Examples
Compare queen contiguity against 4-nearest-neighbor weights:
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_by_weights
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_by_weights(
df, "y", ["x"], gdf=gdf, model="lag", entity="id", n_draws=200,
weights={
"queen": make_weights(gdf, method="queen"),
"knn4": make_weights(gdf, method="knn", k=4),
},
)
print(res.baseline, list(res.df["weights"]))