statspai.spatial¶
spatial ¶
Spatial econometrics — StatsPAI's answer to R's spatialreg + spdep + mgwr
and Python's PySAL.
Three layers, flat-imported for convenience:
Weights
W, queen_weights, rook_weights, knn_weights,
distance_band, kernel_weights, block_weights.
Exploratory spatial data analysis (ESDA)
moran, moran_local, geary, getis_ord_g, getis_ord_local,
join_counts, moran_plot, lisa_cluster_map.
Regression
- ML estimators:
sar,sem,sdm,slx,sac - Diagnostics:
lm_tests,moran_residuals - Effects:
impacts(LeSage-Pace direct / indirect / total)
All regression estimators accept a :class:W object, a scipy.sparse
matrix, or an (n, n) ndarray for the weights argument.
Examples:
>>> import numpy as np
>>> import pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> n = 100
>>> coords = rng.uniform(0, 10, size=(n, 2))
>>> df = pd.DataFrame({"x1": rng.normal(size=n), "x2": rng.normal(size=n)})
>>> df["y"] = 1 + 0.5 * df["x1"] - 0.3 * df["x2"] + rng.normal(size=n)
>>> w = sp.knn_weights(coords, k=6); w.transform = "R"
>>> moran = sp.moran(df["y"], w, permutations=99, seed=0)
>>> result = sp.sar(w, data=df, formula='y ~ x1 + x2')
>>> list(result.params.index)
['const', 'x1', 'x2', 'rho']
>>> eff = sp.impacts(result, n_sim=200, seed=0)
>>> list(eff.columns)
['Direct', 'SE_Direct', 'Indirect', 'SE_Indirect', 'Total', 'SE_Total']
>>> lms = sp.lm_tests("y ~ x1 + x2", df, w)
>>> sorted(lms)
['LM_err', 'LM_lag', 'Robust_LM_err', 'Robust_LM_lag', 'SARMA']
SpatialDiDResult
dataclass
¶
Bases: ResultProtocolMixin
Result object for :func:spatial_did.
The object intentionally exposes both a spatial-DiD-specific surface
(direct_effect, spillover_effect, total_effect) and a
broom/modelsummary-compatible surface (tidy(), glance(),
params, std_errors).
Examples:
>>> import statspai as sp
>>> import numpy as np, pandas as pd
>>> rng = np.random.default_rng(0)
>>> n_units, n_time = 12, 6
>>> W = np.zeros((n_units, n_units)) # ring spatial weights over units
>>> for i in range(n_units):
... W[i, (i + 1) % n_units] = 1
... W[i, (i - 1) % n_units] = 1
>>> rows = []
>>> for u in range(n_units):
... fe = rng.normal()
... for t in range(n_time):
... d = 1 if (u < 6 and t >= 3) else 0 # half treated from t>=3
... y = 1.0 + fe + 0.3 * t + 1.5 * d + rng.normal(scale=0.3)
... rows.append({"unit": u, "time": t, "treat": d, "y": y})
>>> df = pd.DataFrame(rows)
>>> res = sp.spatial_did(df, y="y", treat="treat", unit="unit",
... time="time", W=W)
>>> isinstance(res, sp.SpatialDiDResult)
True
>>> res.n_obs
72
plot ¶
Plot coefficient, exposure, or spatial event-study diagnostics.
SpatialIVResult
dataclass
¶
Bases: ResultProtocolMixin
Container for :func:spatial_iv Kelejian-Prucha S2SLS estimates.
Attributes:
| Name | Type | Description |
|---|---|---|
rho |
float
|
Spatial autoregressive coefficient on |
rho_se |
float
|
Standard error of |
coefficients |
DataFrame
|
Full coefficient table with |
n_obs |
int
|
Number of observations after dropping missing rows. |
Examples:
>>> import statspai as sp
>>> import numpy as np, pandas as pd
>>> rng = np.random.default_rng(0)
>>> n = 60
>>> W = np.zeros((n, n)) # ring network, row-normalised
>>> for i in range(n):
... W[i, (i + 1) % n] = 1
... W[i, (i - 1) % n] = 1
>>> W = W / W.sum(1, keepdims=True)
>>> x = rng.normal(size=n)
>>> z = rng.normal(size=n) # excluded instrument
>>> d = 0.5 * x + 0.8 * z + rng.normal(size=n) # endogenous regressor
>>> y = 1.0 + 1.5 * d + 0.3 * x + rng.normal(size=n)
>>> df = pd.DataFrame({"y": y, "d": d, "x": x, "z": z})
>>> res = sp.spatial_iv(df, y="y", endog=["d"], exog=["x"], W=W,
... instruments=["z"])
>>> isinstance(res, sp.SpatialIVResult)
True
>>> res.n_obs
60
SpatialModel ¶
Unified spatial regression estimator.
Uses concentrated ML: profile out β and σ², optimise over ρ (or λ) in one dimension using eigenvalues of W.
The engine behind :func:sp.sar / :func:sp.sem / :func:sp.sdm.
Construct it with a dense (n, n) weights matrix W, the data
and a formula, then call :meth:fit to obtain an
EconometricResults carrying the spatial parameter (rho for
SAR / SDM, lambda for SEM).
Examples:
>>> import numpy as np
>>> import pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> n = 50
>>> W = np.zeros((n, n)) # nearest-neighbour chain weights
>>> for i in range(n - 1):
... W[i, i + 1] = W[i + 1, i] = 1.0
>>> df = pd.DataFrame({"x": rng.normal(size=n)})
>>> df["y"] = 1.0 + 0.5 * df["x"] + rng.normal(size=n)
>>> model = sp.SpatialModel(W, df, "y ~ x", model_type="sar")
>>> res = model.fit()
>>> type(res).__name__
'EconometricResults'
>>> model.model_type
'sar'
fit ¶
fit() -> EconometricResults
Fit by maximum likelihood with :func:sp.sar / :func:sp.sem /
:func:sp.sdm, so the class and the functions report one set of
estimates and standard errors.
Notes
Through 1.40.2 the class kept its own concentrated-likelihood
fit with the information-matrix formulas the functions had
replaced: the rho SE omitted tr(G'G), the beta SEs
treated rho as known, the lambda SE used
tr(G^2) + tr(G)^2 / n, and alpha never reached the
intervals.
W ¶
Spatial weights matrix with CSR-sparse backing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
neighbors
|
dict[int, list[int]]
|
Mapping observation id -> list of neighbour ids. |
required |
weights
|
dict[int, list[float]]
|
Matching weight values. If |
None
|
id_order
|
sequence
|
Explicit ordering of observation ids. Defaults to |
None
|
Notes
w.transform re-weights the weights as constructed (never a
previous transform): "O" original, "B" binary, "R" row
standardised (spdep style "W"), "V" variance stabilising
(spdep "S": w_ij / sqrt(sum_j w_ij^2) rescaled to sum n),
"D" globally standardised to sum 1 (spdep "U"). Each matches
spdep::nb2listw(style=, glist=) and libpysal's transform.
Examples:
>>> import statspai as sp
>>> # A 4-node chain graph 0-1-2-3
>>> neighbors = {0: [1], 1: [0, 2], 2: [1, 3], 3: [2]}
>>> w = sp.W(neighbors)
>>> w.n
4
>>> w.islands
[]
>>> w.transform = "R" # row-standardize the weights
>>> float(w.full()[1].sum()) # each row now sums to 1
1.0
spatial_did ¶
spatial_did(data: DataFrame, y: str, treat: str, unit: str, time: str, W: Any, covariates: Optional[Sequence[str]] = None, cluster: Optional[str] = None, alpha: float = 0.05, *, se_type: str = 'cluster', coords: Optional[Tuple[str, str]] = None, lat: Optional[str] = None, lon: Optional[str] = None, distance_matrix: Optional[ndarray] = None, conley_cutoff: Optional[float] = None, conley_kernel: str = 'bartlett', unit_order: Optional[Sequence[Any]] = None, normalize_W: bool = True, event_study: bool = False, event_window: Optional[Tuple[int, int]] = None, event_base: int = -1) -> SpatialDiDResult
Spatial DiD with direct and spillover treatment effects.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
DataFrame
|
Long panel with one row per unit-period. |
required |
y
|
str
|
Outcome, treatment, unit-id, and time-id columns. |
required |
treat
|
str
|
Outcome, treatment, unit-id, and time-id columns. |
required |
unit
|
str
|
Outcome, treatment, unit-id, and time-id columns. |
required |
time
|
str
|
Outcome, treatment, unit-id, and time-id columns. |
required |
W
|
ndarray, sparse matrix, or :class:`statspai.spatial.W`
|
Spatial weights matrix over units. If a StatsPAI |
required |
covariates
|
sequence of str
|
Additional controls included after absorbing unit and time effects. |
None
|
cluster
|
str
|
Cluster variable for |
None
|
alpha
|
float
|
Significance level for confidence intervals. |
0.05
|
se_type
|
('cluster', 'robust', 'conley')
|
Covariance estimator. |
"cluster"
|
coords
|
tuple(str, str)
|
Convenience pair |
None
|
lat
|
str
|
Latitude/longitude columns in degrees. |
None
|
lon
|
str
|
Latitude/longitude columns in degrees. |
None
|
distance_matrix
|
ndarray
|
Unit-by-unit distances in the same units as |
None
|
conley_cutoff
|
float
|
Spatial cutoff for Conley-HAC standard errors. |
None
|
conley_kernel
|
('uniform', 'bartlett')
|
|
"uniform"
|
unit_order
|
sequence
|
Explicit row/column order of |
None
|
normalize_W
|
bool
|
Row-normalise weights before constructing |
True
|
event_study
|
bool
|
Estimate direct and spillover event-study paths by relative time. |
False
|
event_window
|
tuple(int, int)
|
Inclusive event-time window. Defaults to observed support capped at
[-5, 5] when |
None
|
event_base
|
int
|
Omitted relative-time period. |
-1
|
Returns:
| Type | Description |
|---|---|
SpatialDiDResult
|
Direct, spillover, total effects with diagnostics, plotting, and export helpers. |
References
delgado2015difference
Examples:
>>> import statspai as sp
>>> import numpy as np, pandas as pd
>>> rng = np.random.default_rng(0)
>>> n_units, n_time = 12, 6
>>> W = np.zeros((n_units, n_units)) # ring spatial weights over units
>>> for i in range(n_units):
... W[i, (i + 1) % n_units] = 1
... W[i, (i - 1) % n_units] = 1
>>> rows = []
>>> for u in range(n_units):
... fe = rng.normal()
... for t in range(n_time):
... d = 1 if (u < 6 and t >= 3) else 0 # half treated from t>=3
... y = 1.0 + fe + 0.3 * t + 1.5 * d + rng.normal(scale=0.3)
... rows.append({"unit": u, "time": t, "treat": d, "y": y})
>>> df = pd.DataFrame(rows)
>>> res = sp.spatial_did(df, y="y", treat="treat", unit="unit",
... time="time", W=W)
>>> res.coefficients["variable"].tolist()
['treat', 'W_treat']
>>> res.n_obs
72
getis_ord_g ¶
getis_ord_g(y: Any, w: W, permutations: int = 999, seed: Optional[int] = None) -> SpatialStatistic
Global Getis-Ord G — overall concentration of high (or low) values.
The global G statistic summarises whether high values of y are
globally concentrated among neighbouring units. It requires non-negative
y. Larger-than-expected G indicates clustering of high values; smaller
indicates clustering of low values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y
|
array_like
|
Non-negative variable of interest, length |
required |
w
|
W
|
Spatial weights object defining the neighbourhood structure. |
required |
permutations
|
int
|
Number of random permutations for the pseudo p-value, empirical
variance and z-score. |
999
|
seed
|
int
|
Seed for the permutation RNG for reproducibility. |
None
|
Returns:
| Type | Description |
|---|---|
SpatialStatistic
|
Result with |
Raises:
| Type | Description |
|---|---|
ValueError
|
If any element of |
Examples:
>>> import statspai as sp
>>> import numpy as np
>>> coords = np.random.default_rng(0).random((50, 2))
>>> w = sp.knn_weights(coords, k=5)
>>> y = np.random.default_rng(4).random(50) # non-negative
>>> res = sp.getis_ord_g(y, w, seed=0)
>>> res.value > 0
True
See Also
getis_ord_local : Local Gi / Gi* hotspot statistics.
References
Getis, A. and Ord, J. K. (1992). The analysis of spatial association by use of distance statistics. Geographical Analysis, 24(3), 189-206. [@getis1992analysis]
getis_ord_local ¶
getis_ord_local(y: Any, w: W, star: bool = True, permutations: int = 999, seed: Optional[int] = None) -> Dict[str, ndarray]
Local Getis-Ord Gi / Gi* — hotspot and coldspot detection.
Computes a standardised local statistic for each unit measuring whether it
is surrounded by high values (a hotspot, large positive z) or low values
(a coldspot, large negative z). With star=True the focal unit is
included in its own neighbourhood (Gi*); with star=False it is
excluded (Gi).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y
|
array_like
|
Variable of interest, length |
required |
w
|
W
|
Spatial weights object; densified internally to an |
required |
star
|
bool
|
If True compute Gi* (self-included); otherwise Gi (self-excluded). |
True
|
permutations
|
int
|
Accepted for API symmetry; the current implementation returns the analytic standardised statistic. |
999
|
seed
|
int
|
Seed placeholder for API symmetry. |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
|
Examples:
>>> import statspai as sp
>>> import numpy as np
>>> coords = np.random.default_rng(0).random((40, 2))
>>> w = sp.knn_weights(coords, k=4)
>>> y = np.random.default_rng(5).random(40)
>>> out = sp.getis_ord_local(y, w, star=True)
>>> out["Gs"].shape
(40,)
See Also
getis_ord_g : Global G statistic. moran_local : LISA, a cross-product local statistic.
References
Getis, A. and Ord, J. K. (1992). The analysis of spatial association by use of distance statistics. Geographical Analysis, 24(3), 189-206. [@getis1992analysis]
moran_local ¶
moran_local(y: Any, w: W, permutations: int = 999, seed: Optional[int] = None) -> Dict[str, Any]
Local Moran's I (LISA) — per-location spatial association.
Decomposes global Moran's I into a contribution I_i for each spatial
unit, identifying local clusters (high-high / low-low) and spatial
outliers (high-low / low-high). Each I_i gets a conditional
permutation pseudo p-value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y
|
array_like
|
Variable of interest, length |
required |
w
|
W
|
Spatial weights object; |
required |
permutations
|
int
|
Number of conditional permutations for the per-location pseudo
p-values. |
999
|
seed
|
int
|
Seed for the permutation RNG for reproducibility. |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Examples:
>>> import statspai as sp
>>> import numpy as np
>>> coords = np.random.default_rng(0).random((40, 2))
>>> w = sp.knn_weights(coords, k=4)
>>> y = np.random.default_rng(2).standard_normal(40)
>>> out = sp.moran_local(y, w, permutations=499, seed=0)
>>> out["Is"].shape
(40,)
See Also
moran : Global Moran's I.
References
Anselin, L. (1995). Local indicators of spatial association---LISA. Geographical Analysis, 27(2), 93-115. [@anselin1995local]
lisa_cluster_map ¶
lisa_cluster_map(y: Any, w: W, gdf: Any, ax: Optional[Any] = None, p_threshold: float = 0.05) -> Any
Classify each observation HH/LL/HL/LH/Not significant and colour on a GDF.
Requires geopandas (install with pip install geopandas); the
gdf must align row-for-row with y and w.
Examples:
>>> import statspai as sp
>>> import numpy as np
>>> rng = np.random.default_rng(0)
>>> coords = rng.uniform(size=(60, 2))
>>> w = sp.knn_weights(coords, k=5)
>>> y = coords[:, 0] + rng.normal(scale=0.3, size=60)
>>> import geopandas as gpd
>>> from shapely.geometry import Point
>>> pts = [Point(xy) for xy in coords]
>>> gdf = gpd.GeoDataFrame(geometry=pts)
>>> ax = sp.lisa_cluster_map(y, w, gdf)
>>> ax.figure.savefig("lisa.png")
moran_plot ¶
moran_plot(y: Any, w: W, ax: Optional[Any] = None) -> Any
Moran scatter: z vs spatial lag Wz. Slope of OLS line = Moran's I.
Examples:
gwr_bandwidth ¶
gwr_bandwidth(coords: Any, y: Any, X: Any, kernel: KernelName = 'bisquare', fixed: bool = False, criterion: Criterion = 'AICc', bw_min: Optional[float] = None, bw_max: Optional[float] = None, add_constant: bool = True, tol: float = 0.0001) -> float
Select a GWR bandwidth by golden-section search.
Minimises criterion of :func:statspai.spatial.gwr.gwr over the
bandwidth, as R GWmodel::bw.gwr does.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
coords
|
(n, 2) array-like
|
Projected point coordinates. |
required |
y
|
(n,) array-like
|
Outcome. |
required |
X
|
(n, p) array-like
|
Regressors (without a constant unless |
required |
kernel
|
('bisquare', 'gaussian', 'exponential')
|
Kernel passed to :func: |
'bisquare'
|
fixed
|
bool
|
|
False
|
criterion
|
('AICc', 'AIC', 'BIC', 'CV')
|
Score to minimise; |
'AICc'
|
bw_min
|
float
|
Search interval. Defaults: |
None
|
bw_max
|
float
|
Search interval. Defaults: |
None
|
add_constant
|
bool
|
Passed to :func: |
True
|
tol
|
float
|
The search stops when two interior criterion values differ by at
most |
1e-4
|
Returns:
| Type | Description |
|---|---|
float
|
The selected bandwidth. |
Notes
A probed bandwidth that admits no GWR fit (one neighbour or less) scores
+inf, with a RuntimeWarning; if no probe can be fitted the first
error is raised.
Examples:
>>> import numpy as np
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> coords = rng.uniform(0, 10, size=(60, 2))
>>> X = rng.normal(size=(60, 1))
>>> y = 1 + (0.5 + 0.1 * coords[:, 0]) * X[:, 0] + rng.normal(0, 0.3, 60)
>>> bw = sp.gwr_bandwidth(coords, y, X)
>>> bool(bw > 0)
True
References
brunsdon1996geographically; gollini2015gwmodel; kiefer1953sequential.
spatial_iv ¶
spatial_iv(data: DataFrame, y: str, endog: Sequence[str], exog: Sequence[str], W: Any, instruments: Optional[Sequence[str]] = None, include_WY: bool = True, alpha: float = 0.05) -> SpatialIVResult
Spatial 2SLS estimator.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
DataFrame
|
|
required |
y
|
str
|
|
required |
endog
|
sequence of str
|
Names of additional endogenous regressors. |
required |
exog
|
sequence of str
|
Names of exogenous regressors (included instruments). |
required |
W
|
ndarray or :class:`spatial.W`
|
Spatial weights matrix (n_obs x n_obs). Should be row-normalised. |
required |
instruments
|
sequence of str
|
Extra excluded instruments beyond the spatial lags of X. |
None
|
include_WY
|
bool
|
If True, include WY as a regressor (spatial autoregressive coefficient ρ). |
True
|
alpha
|
float
|
Significance level of the normal confidence intervals in
|
0.05
|
Returns:
| Type | Description |
|---|---|
SpatialIVResult
|
|
References
kelejian1998generalized
Examples:
>>> import statspai as sp
>>> import numpy as np, pandas as pd
>>> rng = np.random.default_rng(0)
>>> n = 60
>>> W = np.zeros((n, n)) # ring network, row-normalised
>>> for i in range(n):
... W[i, (i + 1) % n] = 1
... W[i, (i - 1) % n] = 1
>>> W = W / W.sum(1, keepdims=True)
>>> x = rng.normal(size=n)
>>> z = rng.normal(size=n) # excluded instrument for the endogenous d
>>> d = 0.5 * x + 0.8 * z + rng.normal(size=n)
>>> y = 1.0 + 1.5 * d + 0.3 * x + rng.normal(size=n)
>>> df = pd.DataFrame({"y": y, "d": d, "x": x, "z": z})
>>> res = sp.spatial_iv(df, y="y", endog=["d"], exog=["x"], W=W,
... instruments=["z"])
>>> res.coefficients["variable"].tolist()
['d', 'rho (WY)', '(Intercept)', 'x']
>>> res.n_obs
60
sar ¶
sar(W: ArrayOrW, data: DataFrame, formula: str, row_normalize: bool = True, alpha: float = 0.05, weights: Optional[Any] = None) -> EconometricResults
Spatial Autoregressive (Lag) Model: Y = ρWY + Xβ + ε.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
W
|
ndarray, scipy.sparse matrix, or statspai.spatial.weights.W
|
n x n spatial weights matrix, rows in the order of |
required |
data
|
DataFrame
|
Data with the variables named in |
required |
formula
|
str
|
Model formula |
required |
row_normalize
|
bool
|
Divide each row of |
True
|
weights
|
None
|
Not supported, and refused with |
None
|
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> n = 30
>>> W = np.zeros((n, n)) # ring contiguity: each unit linked to neighbours
>>> for i in range(n):
... W[i, (i - 1) % n] = 1.0
... W[i, (i + 1) % n] = 1.0
>>> x = rng.normal(size=n)
>>> df = pd.DataFrame({"y": 1.0 + 0.8 * x + rng.normal(scale=0.5, size=n),
... "x": x})
>>> res = sp.sar(W, data=df, formula="y ~ x")
>>> list(res.params.index)
['const', 'x', 'rho']
References
anselin1988spatial
sdm ¶
sdm(W: ArrayOrW, data: DataFrame, formula: str, row_normalize: bool = True, alpha: float = 0.05) -> EconometricResults
Spatial Durbin Model: Y = ρWY + Xβ + WXθ + ε.
Reports LeSage & Pace direct / indirect / total effects in the
diagnostics when n is small enough for the dense (I - ρW)^{-1}.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
W
|
ndarray, scipy.sparse matrix, or statspai.spatial.weights.W
|
n x n spatial weights matrix, rows in the order of |
required |
data
|
DataFrame
|
Data with the variables named in |
required |
formula
|
str
|
Model formula |
required |
row_normalize
|
bool
|
Divide each row of |
True
|
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> n = 30
>>> W = np.zeros((n, n))
>>> for i in range(n):
... W[i, (i - 1) % n] = 1.0
... W[i, (i + 1) % n] = 1.0
>>> x = rng.normal(size=n)
>>> df = pd.DataFrame({"y": 1.0 + 0.8 * x + rng.normal(scale=0.5, size=n),
... "x": x})
>>> res = sp.sdm(W, data=df, formula="y ~ x")
>>> list(res.params.index) # own + spatially-lagged covariate + rho
['const', 'x', 'W_x', 'rho']
References
lesage2009introduction
sem ¶
sem(W: ArrayOrW, data: DataFrame, formula: str, row_normalize: bool = True, alpha: float = 0.05) -> EconometricResults
Spatial Error Model: Y = Xβ + u, u = λWu + ε.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
W
|
ndarray, scipy.sparse matrix, or statspai.spatial.weights.W
|
n x n spatial weights matrix, rows in the order of |
required |
data
|
DataFrame
|
Data with the variables named in |
required |
formula
|
str
|
Model formula |
required |
row_normalize
|
bool
|
Divide each row of |
True
|
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> n = 30
>>> W = np.zeros((n, n))
>>> for i in range(n):
... W[i, (i - 1) % n] = 1.0
... W[i, (i + 1) % n] = 1.0
>>> x = rng.normal(size=n)
>>> df = pd.DataFrame({"y": 1.0 + 0.8 * x + rng.normal(scale=0.5, size=n),
... "x": x})
>>> res = sp.sem(W, data=df, formula="y ~ x")
>>> list(res.params.index)
['const', 'x', 'lambda']
References
anselin1988spatial
lm_tests ¶
lm_tests(formula: str, data: DataFrame, W: Any, row_normalize: bool = True) -> Dict[str, Tuple[float, float]]
Anselin (1988) Lagrange multiplier battery.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
formula
|
str
|
|
required |
data
|
DataFrame
|
|
required |
W
|
ndarray, scipy.sparse, or ``statspai.spatial.weights.W``
|
|
required |
row_normalize
|
bool
|
|
True
|
Returns:
| Type | Description |
|---|---|
dict
|
|
Examples:
>>> import statspai as sp
>>> import numpy as np
>>> import pandas as pd
>>> rng = np.random.default_rng(0)
>>> n = 80
>>> coords = rng.uniform(size=(n, 2))
>>> w = sp.knn_weights(coords, k=5)
>>> x1 = rng.normal(size=n)
>>> y = 1.0 + 0.5 * x1 + rng.normal(scale=0.5, size=n)
>>> df = pd.DataFrame({"y": y, "x1": x1})
>>> out = sp.lm_tests("y ~ x1", df, w)
>>> sorted(out.keys())
['LM_err', 'LM_lag', 'Robust_LM_err', 'Robust_LM_lag', 'SARMA']
moran_residuals ¶
moran_residuals(residuals: ndarray, W: Any, row_normalize: bool = True, X: Optional[ndarray] = None) -> Tuple[float, float]
Moran's I applied to regression residuals (quick LM-err companion).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
residuals
|
ndarray
|
|
required |
W
|
ndarray, scipy.sparse, or ``statspai.spatial.weights.W``
|
|
required |
row_normalize
|
bool
|
|
True
|
X
|
ndarray
|
The regression's design matrix, including its constant. When
supplied, the p-value uses Cliff and Ord's null for regression
residuals -- the one .. versionchanged:: 1.27.0
The statistic was always exact (5e-16 against |
None
|
Examples:
gns ¶
gns(W: ArrayOrW, data: DataFrame, formula: str, row_normalize: bool = True, alpha: float = 0.05) -> EconometricResults
General nesting spatial model (Manski-type): spatial lag of y,
of the regressors, and of the error.
y = rho W y + Xb + WXt + u, u = lambda W u + e by maximum
likelihood, OIM standard errors as Stata spregress, ml dvarlag(W)
errorlag(W) ivarlag(W: x...). The model nests SAR, SEM, SDM, SDEM and
SAC; it is weakly identified in small samples (rho and lambda
trade off), so read the standard errors of the two before the point
estimates.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
W
|
ndarray, scipy.sparse matrix, or statspai.spatial.weights.W
|
|
required |
data
|
DataFrame
|
|
required |
formula
|
str
|
|
required |
row_normalize
|
bool
|
|
True
|
alpha
|
float
|
|
0.05
|
Returns:
| Type | Description |
|---|---|
EconometricResults
|
|
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> n = 40
>>> W = np.zeros((n, n))
>>> for i in range(n):
... W[i, (i - 1) % n] = W[i, (i + 1) % n] = 1.0
>>> x = rng.normal(size=n)
>>> df = pd.DataFrame({"y": 1 + x + rng.normal(size=n), "x": x})
>>> list(sp.gns(W, df, "y ~ x").params.index)
['const', 'x', 'W_x', 'rho', 'lambda']
sdem ¶
sdem(W: ArrayOrW, data: DataFrame, formula: str, row_normalize: bool = True, alpha: float = 0.05) -> EconometricResults
Spatial Durbin error model: y = Xb + WXt + u, u = lambda W u + e.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
W
|
ndarray, scipy.sparse matrix, or statspai.spatial.weights.W
|
n x n spatial weights, rows in the order of |
required |
data
|
DataFrame
|
|
required |
formula
|
str
|
|
required |
row_normalize
|
bool
|
|
True
|
alpha
|
float
|
|
0.05
|
Returns:
| Type | Description |
|---|---|
EconometricResults
|
|
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> n = 40
>>> W = np.zeros((n, n))
>>> for i in range(n):
... W[i, (i - 1) % n] = W[i, (i + 1) % n] = 1.0
>>> x = rng.normal(size=n)
>>> df = pd.DataFrame({"y": 1 + x + rng.normal(size=n), "x": x})
>>> list(sp.sdem(W, df, "y ~ x").params.index)
['const', 'x', 'W_x', 'lambda']
sar_gmm ¶
sar_gmm(W: Any, data: DataFrame, formula: str, row_normalize: bool = True, robust: Optional[str] = None, w_lags: int = 1) -> EconometricResults
Kelejian-Prucha (1998) 2SLS for SAR with spatial-lag instruments.
Instruments: [X, W X, …, W^w_lags X] (dropping constant duplicates).
w_lags=1 (default) matches spreg.GM_Lag default.
Endogenous regressor: W Y.
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> n = 40
>>> W = np.zeros((n, n)) # ring contiguity: each unit linked to neighbours
>>> for i in range(n):
... W[i, (i - 1) % n] = 1.0
... W[i, (i + 1) % n] = 1.0
>>> x = rng.normal(size=n)
>>> df = pd.DataFrame({"y": 1.0 + 0.8 * x + rng.normal(scale=0.5, size=n),
... "x": x})
>>> res = sp.sar_gmm(W, data=df, formula="y ~ x")
>>> list(res.params.index)
['const', 'x', 'rho']
References
kelejian1998generalized
sarar_gmm ¶
sarar_gmm(W: Any, data: DataFrame, formula: str, row_normalize: bool = True, robust: Optional[str] = None, sig2n_k: bool = False, w_lags: int = 2) -> EconometricResults
SARAR (spatial lag + spatial error) by generalized spatial 2SLS.
The Kelejian-Prucha (1998) GS2SLS estimator for
y = rho W y + X beta + u, u = lambda W u + e, in the three steps
of Kelejian and Prucha (1998):
- 2SLS of
yon[W y, X]with instrumentsH = [X, W X, W^2 X](lags of the non-constant columns). lambdafrom the Kelejian-Prucha (1999) generalized moments on the 2SLS residuals (unweighted nonlinear least squares).- Spatial Cochrane-Orcutt: 2SLS of
y - lambda W yon[(I - lambda W) W y, (I - lambda W) X], instruments[(I - lambda W) X, W X, W^2 X]. With a row-standardisedWthese span the same space asH, the instruments Kelejian and Prucha (1998) use in the third step; only the regressors are filtered.
beta, rho and their standard errors come from step 3. The GM
step does not deliver a standard error for lambda; it is reported
as NaN (R spatialreg::gstsls likewise reports no standard error
for lambda).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
W
|
array-like, sparse matrix or :class:`W`
|
Spatial weights. |
required |
data
|
DataFrame
|
|
required |
formula
|
str
|
|
required |
row_normalize
|
bool
|
Row-standardise |
True
|
robust
|
(None, 'het')
|
|
None
|
sig2n_k
|
bool
|
Divide the residual sum of squares by |
False
|
w_lags
|
int
|
Spatial lags of |
2
|
Returns:
| Type | Description |
|---|---|
EconometricResults
|
|
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> n = 40
>>> W = np.zeros((n, n)) # ring contiguity: each unit linked to neighbours
>>> for i in range(n):
... W[i, (i - 1) % n] = 1.0
... W[i, (i + 1) % n] = 1.0
>>> x = rng.normal(size=n)
>>> df = pd.DataFrame({"y": 1.0 + 0.8 * x + rng.normal(scale=0.5, size=n),
... "x": x})
>>> res = sp.sarar_gmm(W, data=df, formula="y ~ x")
>>> list(res.params.index)
['const', 'x', 'rho', 'lambda']
References
kelejian1998generalized
sem_gmm ¶
sem_gmm(W: Any, data: DataFrame, formula: str, row_normalize: bool = True, robust: Optional[str] = None) -> EconometricResults
Kelejian-Prucha (1999) GMM for the spatial-error parameter λ.
Stage 1 — OLS on y = Xβ + u ⇒ residuals u.
Stage 2 — minimise sum of squared KP moment residuals over (λ, σ²).
Stage 3 — GLS with (I - λ̂ W) → final β̂.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
robust
|
(None, 'het')
|
When |
None
|
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> n = 40
>>> W = np.zeros((n, n)) # ring contiguity: each unit linked to neighbours
>>> for i in range(n):
... W[i, (i - 1) % n] = 1.0
... W[i, (i + 1) % n] = 1.0
>>> x = rng.normal(size=n)
>>> df = pd.DataFrame({"y": 1.0 + 0.8 * x + rng.normal(scale=0.5, size=n),
... "x": x})
>>> res = sp.sem_gmm(W, data=df, formula="y ~ x")
>>> list(res.params.index)
['const', 'x', 'lambda']
impacts ¶
Direct, indirect and total impacts of a spatial regression, with SEs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
result
|
EconometricResults
|
Output of |
required |
n_sim
|
int
|
Number of Monte-Carlo draws for simulated SEs. Not used for SLX / SDEM. |
1000
|
seed
|
int
|
RNG seed. Not used for SLX / SDEM. |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame with one row per non-constant regressor and columns
|
|
``Direct``, ``SE_Direct``, ``Indirect``, ``SE_Indirect``, ``Total``,
|
|
``SE_Total``. ``attrs['se_method']`` is ``'simulation'`` or
|
|
``'analytic'``; ``attrs['n_draws_discarded']`` counts the draws whose
|
|
spatial parameter fell outside the admissible interval
|
|
``(1 / omega_min, 1 / omega_max)`` of the eigenvalues of ``W`` (real
|
|
parts), which are dropped as ``spatialreg`` drops them.
|
|
Notes
The total impact is (1/n) 1' S_k 1 (LeSage and Pace 2009). For a
row-standardised W it equals beta_k / (1 - rho) in a SAR
model; for any other W it does not. spatialreg::impacts on a
lagsarlm fit with weights that are not row-standardised reports
beta_k / (1 - rho) all the same (spatialreg 1.4.3, checked on a
binary ring), so its indirect and total impacts differ from these
there; its direct impacts agree.
Through 1.40.2 the admissible interval was fixed at (-0.999, 0.999),
right only for a row-standardised W with smallest eigenvalue -1:
draws past 1 / omega_max of an unstandardised W were kept and
inflated the SEs, and valid draws below -0.999 were dropped.
Examples:
>>> import numpy as np
>>> import pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(7)
>>> n = 120
>>> coords = rng.uniform(size=(n, 2))
>>> w = sp.knn_weights(coords, k=6)
>>> w.transform = "R"
>>> W = w.sparse.toarray()
>>> x = rng.standard_normal(n)
>>> y = np.linalg.solve(np.eye(n) - 0.5 * W,
... 1 + 2 * x + rng.standard_normal(n))
>>> res = sp.sar(w, pd.DataFrame({"y": y, "x": x}), "y ~ x")
>>> imp = sp.impacts(res, n_sim=200, seed=0)
>>> list(imp.columns)
['Direct', 'SE_Direct', 'Indirect', 'SE_Indirect', 'Total', 'SE_Total']
>>> list(imp.index)
['x']
sac ¶
sac(W: ArrayOrW, data: DataFrame, formula: str, row_normalize: bool = True, alpha: float = 0.05) -> EconometricResults
SAC / SARAR: combined spatial lag + spatial error model.
y = rho W y + X b + u, u = lambda W u + e, e ~ N(0, sigma^2 I).
(b, sigma^2) are profiled out and (rho, lambda) maximise the
concentrated log-likelihood. Standard errors invert the observed
information of the full log-likelihood in (b, rho, lambda, sigma^2)
(Stata spregress, ml dvarlag(W) errorlag(W), default vce(oim)),
so they account for the covariance between the regression and the
spatial parameters. Through 1.39 the regression SEs treated rho and
lambda as known and the spatial SEs read the diagonal of a
numerical Hessian of the concentrated likelihood; both were too small.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
W
|
ndarray, scipy.sparse matrix, or statspai.spatial.weights.W
|
n x n spatial weights, rows in the order of |
required |
data
|
DataFrame
|
|
required |
formula
|
str
|
|
required |
row_normalize
|
bool
|
|
True
|
alpha
|
float
|
|
0.05
|
Returns:
| Type | Description |
|---|---|
EconometricResults
|
|
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> n = 30
>>> W = np.zeros((n, n))
>>> for i in range(n):
... W[i, (i - 1) % n] = 1.0
... W[i, (i + 1) % n] = 1.0
>>> x = rng.normal(size=n)
>>> df = pd.DataFrame({"y": 1.0 + 0.8 * x + rng.normal(scale=0.5, size=n),
... "x": x})
>>> res = sp.sac(W, data=df, formula="y ~ x")
>>> list(res.params.index) # both spatial coefficients estimated jointly
['const', 'x', 'rho', 'lambda']
References
anselin1988spatial
slx ¶
slx(W: ArrayOrW, data: DataFrame, formula: str, row_normalize: bool = True, alpha: float = 0.05) -> EconometricResults
Spatial Lag of X (SLX) model: Y = Xβ + WXθ + ε.
No autoregressive term. Estimated by ordinary least squares on the design matrix augmented with spatially-lagged covariates (skip the constant).
Examples:
>>> import numpy as np, pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> n = 30
>>> W = np.zeros((n, n))
>>> for i in range(n):
... W[i, (i - 1) % n] = 1.0
... W[i, (i + 1) % n] = 1.0
>>> x = rng.normal(size=n)
>>> df = pd.DataFrame({"y": 1.0 + 0.8 * x + rng.normal(scale=0.5, size=n),
... "x": x})
>>> res = sp.slx(W, data=df, formula="y ~ x")
>>> list(res.params.index)
['const', 'x', 'W_x']
References
anselin1988spatial
spatial_panel ¶
spatial_panel(data: DataFrame, formula: str, entity: str, time: str, W: Any, model: ModelKind = 'sar', effects: EffectKind = 'fe', row_normalize: bool = True, vce: str = 'information', twoways_lag: str = 'splm') -> SpatialPanelResult
Fit a spatial panel model by concentrated ML (Elhorst 2014).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
DataFrame
|
Long-format panel; must be balanced. |
required |
formula
|
str
|
|
required |
entity
|
str
|
Column names identifying entity and time dimensions. |
required |
time
|
str
|
Column names identifying entity and time dimensions. |
required |
W
|
sparse matrix, ndarray, or :class:`statspai.spatial.weights.W`
|
N × N spatial weights matrix aligned with |
required |
model
|
('sar', 'sem', 'sdm', 'sac')
|
|
"sar"
|
effects
|
('fe', 'twoways', 're')
|
|
"fe"
|
row_normalize
|
bool
|
Row-standardise |
True
|
vce
|
('information', 'oim')
|
|
"information"
|
twoways_lag
|
('splm', 'within')
|
Spatial lag regressor of SAR / SDM under |
"splm"
|
Returns:
| Type | Description |
|---|---|
SpatialPanelResult
|
|
Examples:
>>> import numpy as np
>>> import pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> N, T = 8, 6
>>> W = np.zeros((N, N)) # ring contiguity weights
>>> for i in range(N):
... W[i, (i - 1) % N] = 1.0
... W[i, (i + 1) % N] = 1.0
>>> rows = []
>>> for i in range(N):
... fe = rng.normal()
... for t in range(T):
... x = rng.normal()
... y = fe + 0.5 * x + rng.normal(0, 0.3)
... rows.append({"id": i, "year": t, "y": y, "x": x})
>>> df = pd.DataFrame(rows)
>>> res = sp.spatial_panel(
... df, "y ~ x", entity="id", time="year", W=W, model="sar",
... )
>>> res.spatial_param
'rho'
>>> (res.N, res.T)
(8, 6)
>>> bool(np.isfinite(res.params["x"]))
True
distance_to_feature ¶
distance_to_feature(points_gdf: Any, target_gdf: Any, unit: str = 'km', allow_geographic: bool = False) -> Series
Distance from each point to the nearest target feature.
The canonical use is "distance from each county seat to the canal", the continuous treatment-intensity variable in a historical-GIS design.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points_gdf
|
GeoDataFrame
|
Point features. |
required |
target_gdf
|
GeoDataFrame
|
Target layer of any geometry type; the nearest distance to the union
of its features is returned. Points inside a target polygon get |
required |
unit
|
('km', 'm')
|
Output unit. |
'km'
|
allow_geographic
|
bool
|
Opt out of the projected-CRS requirement. |
False
|
Returns:
| Type | Description |
|---|---|
Series
|
Named |
Raises:
| Type | Description |
|---|---|
ValueError
|
On any of the CRS / geometry problems listed in
:func: |
Examples:
line_length_in_polygon ¶
line_length_in_polygon(lines_gdf: Any, polygons_gdf: Any, polygon_id: Optional[str] = None, unit: str = 'km', allow_geographic: bool = False) -> DataFrame
Length of linear features falling inside each polygon.
The canonical use is "kilometres of canal (or railway, or road) per county", the exposure variable in a historical-GIS panel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lines_gdf
|
GeoDataFrame
|
Linear features. Must be |
required |
polygons_gdf
|
GeoDataFrame
|
Areal units. Must be |
required |
polygon_id
|
str
|
Column in |
None
|
unit
|
('km', 'm')
|
Output unit. |
'km'
|
allow_geographic
|
bool
|
Opt out of the projected-CRS requirement. Only set this if you have verified the CRS units are metres. |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
One row per polygon with the id column and |
Raises:
| Type | Description |
|---|---|
ValueError
|
If either frame has no CRS, a geographic CRS (and |
Examples:
share_within_buffer ¶
share_within_buffer(points_gdf: Any, lines_gdf: Any, buffer_km: float = 10.0, group_col: Optional[str] = None, allow_geographic: bool = False) -> Any
Share of point features lying within a buffer of the linear features.
The canonical use is "share of market towns within 10 km of the canal", either overall or per county.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points_gdf
|
GeoDataFrame
|
Point features (e.g. market towns). |
required |
lines_gdf
|
GeoDataFrame
|
Linear features to buffer (e.g. the canal). |
required |
buffer_km
|
float
|
Buffer radius in kilometres. Must be strictly positive. |
10.0
|
group_col
|
str
|
Column in |
None
|
allow_geographic
|
bool
|
Opt out of the projected-CRS requirement. |
False
|
Returns:
| Type | Description |
|---|---|
float or DataFrame
|
Without |
Raises:
| Type | Description |
|---|---|
ValueError
|
On non-positive |
Examples:
block_weights ¶
block_weights(regimes: Sequence[Any]) -> W
Block (regime) spatial weights — full connectivity within each group.
Builds a weights object in which every unit is a neighbour of every other unit sharing the same regime label, and of no unit outside it. Useful for encoding membership in a region, cluster, or treatment block as a spatial structure.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
regimes
|
array_like
|
Length- |
required |
Returns:
| Type | Description |
|---|---|
W
|
Spatial weights object with block-diagonal connectivity. |
Examples:
distance_band ¶
distance_band(coords: ndarray, threshold: float, binary: bool = True) -> W
Distance-band spatial weights — connect units within a fixed radius.
Every unit is connected to all other units within Euclidean distance
threshold. Weights are either binary (1 for every neighbour) or
inverse-distance (1/d).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
coords
|
ndarray
|
|
required |
threshold
|
float
|
Distance band radius. Units within this distance become neighbours. Choose at least the maximum nearest-neighbour distance to avoid islands (units with no neighbours). |
required |
binary
|
bool
|
If True all neighbour weights are |
True
|
Returns:
| Type | Description |
|---|---|
W
|
Spatial weights object; neighbour counts vary by local density. |
Examples:
>>> import statspai as sp
>>> import numpy as np
>>> coords = np.random.default_rng(0).random((30, 2))
>>> w = sp.distance_band(coords, threshold=0.3, binary=False)
>>> w.n
30
See Also
knn_weights : Fixed neighbour count instead of fixed radius.
kernel_weights ¶
kernel_weights(coords: ndarray, bandwidth: float, kernel: Literal['gaussian', 'bisquare', 'triangular'] = 'gaussian', fixed: bool = True) -> W
Kernel (distance-decay) spatial weights from point coordinates.
Assigns each neighbour a continuous weight that decays with distance
according to a kernel function. Supports a fixed bandwidth (same radius
everywhere) or an adaptive bandwidth (the bandwidth-th nearest
neighbour distance, varying with local density).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
coords
|
ndarray
|
|
required |
bandwidth
|
float
|
With |
required |
kernel
|
('gaussian', 'bisquare', 'triangular')
|
Kernel shape. |
"gaussian"
|
fixed
|
bool
|
Fixed (True) versus adaptive (False) bandwidth. |
True
|
Returns:
| Type | Description |
|---|---|
W
|
Spatial weights object with continuous kernel weights. The fixed
bisquare is spdep's |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Examples:
>>> import statspai as sp
>>> import numpy as np
>>> coords = np.random.default_rng(0).random((30, 2))
>>> w = sp.kernel_weights(coords, bandwidth=0.4, kernel="bisquare")
>>> w.n
30
See Also
distance_band : Binary / inverse-distance fixed-radius weights. knn_weights : Uniform k-nearest-neighbour weights.
knn_weights ¶
knn_weights(coords: ndarray, k: int = 5) -> W
k-nearest-neighbour spatial weights from point coordinates.
Each unit is connected to its k closest units by Euclidean distance
(the unit itself is excluded). The resulting graph is generally asymmetric
— being someone's nearest neighbour is not reciprocal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
coords
|
ndarray
|
|
required |
k
|
int
|
Number of nearest neighbours per unit. Must satisfy |
5
|
Returns:
| Type | Description |
|---|---|
W
|
Spatial weights object with exactly |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Examples:
>>> import statspai as sp
>>> import numpy as np
>>> coords = np.random.default_rng(0).random((30, 2))
>>> w = sp.knn_weights(coords, k=4)
>>> len(w.neighbors[0])
4
See Also
distance_band : Connect all units within a fixed radius. kernel_weights : Continuous distance-decay weights.
queen_weights ¶
queen_weights(gdf: Any) -> W
Queen-contiguity spatial weights from polygon geometries.
Two areal units are queen-contiguous if their geometries share at least
one boundary point (an edge or a single vertex). Requires geopandas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
gdf
|
GeoDataFrame
|
Layer of polygon geometries (accessed via |
required |
Returns:
| Type | Description |
|---|---|
W
|
Spatial weights object whose neighbour lists encode queen contiguity. |
Raises:
| Type | Description |
|---|---|
ImportError
|
If |
Examples:
>>> import statspai as sp
>>> import geopandas as gpd
>>> gdf = gpd.read_file("counties.shp")
>>> w = sp.queen_weights(gdf)
See Also
rook_weights : Edge-only contiguity (excludes shared vertices).
rook_weights ¶
rook_weights(gdf: Any) -> W
Rook-contiguity spatial weights from polygon geometries.
Two areal units are rook-contiguous if their geometries share a boundary
segment of positive length (a shared edge); units touching only at a
single vertex are not neighbours. Requires geopandas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
gdf
|
GeoDataFrame
|
Layer of polygon geometries. |
required |
Returns:
| Type | Description |
|---|---|
W
|
Spatial weights object whose neighbour lists encode rook contiguity. |
Raises:
| Type | Description |
|---|---|
ImportError
|
If |
Examples:
>>> import statspai as sp
>>> import geopandas as gpd
>>> w = sp.rook_weights(gpd.read_file("counties.shp"))
See Also
queen_weights : Contiguity that also counts shared vertices.