Bootstrap Tests for GWR Non-stationarity (BootstrapGWR)¶
Family: Spatial inference
Install: pip install -e ".[all]"
Required data: X, y, coordinates
Primary operations: fit, summary, to_frame
New-location capability: Not applicable; the estimator performs coefficient-variability inference.
API reference Runnable source Choose a model
Why this model exists¶
Use BootstrapGWR when the main question is whether apparent local coefficient variation exceeds what would be expected under a specified null model.
One-sentence idea
BootstrapGWR repeatedly simulates or resamples under a null structure, refits GWR, and compares observed coefficient variability with the bootstrap distribution.
Statistical formulation¶
For coefficient \(k\), an observed spatial-variability statistic \(T_k\) is compared with bootstrap replicates \(T_k^{*(b)}\). A plus-one Monte Carlo p-value is
Optional localized tests compare observed local deviations with location-wise bootstrap distributions.
How pyGWRx fits the model¶
- Fit the observed GWR and calculate coefficient-variability statistics.
- Use the validated OLS null model and specify the bootstrap count.
- Generate bootstrap responses under the null.
- Refit GWR for every replicate, optionally reselecting the bandwidth.
- Calculate global and optional localized p-values.
- Summarize evidence for coefficient non-stationarity and retain bootstrap distributions when requested.
Constructor and important controls¶
BootstrapGWR(bandwidth: 'Union[float, int, str, None]' = 'aicc', adaptive: 'bool' = False, kernel: 'str' = 'bisquare', bandwidth_method: 'str' = 'aicc', bandwidth_range: 'Optional[Tuple[float, float]]' = None, optimization_method: 'str' = 'golden_section', fit_intercept: 'bool' = True, distance_metric: 'str' = 'euclidean', n_bootstrap: 'int' = 99, reselect_bandwidth: 'bool' = True, pvalue_method: 'str' = 'plus_one', localized_tail: 'str' = 'two-sided', store_local_bootstrap: 'bool' = False, random_state: 'Optional[Union[int, np.random.Generator]]' = None, verbose: 'bool' = False) -> 'None'
The API page documents every parameter and fitted attribute. In practice, start by deciding the data contract, neighbourhood definition, selection criterion, and prediction/inference goal before tuning secondary controls.
| Decision | Questions to answer |
|---|---|
| Data | Are rows independent observations, ordered stages, classes, counts, or multivariate features? |
| Distance | Are coordinates projected? Is time or contextual similarity part of the neighbourhood? |
| Bandwidth | Fixed distance or adaptive neighbours? Supplied value or selected criterion? |
| Inference | Are local uncertainty, non-stationarity tests, or only prediction required? |
| Validation | Does the split respect spatial and, where relevant, temporal dependence? |
Complete runnable example¶
The following is the exact maintained example used by the API-coverage checks.
# SPDX-FileCopyrightText: 2026 Jinghao Hu
# SPDX-License-Identifier: MIT
"""Run coefficient-wise bootstrap tests for spatial variability."""
from pygwrx import BootstrapGWR
from _common import print_model_result, spatial_regression
X, y, coords = spatial_regression(n=42, p=2)
model = BootstrapGWR(
bandwidth=22,
adaptive=True,
n_bootstrap=9,
reselect_bandwidth=False,
store_local_bootstrap=True,
random_state=0,
).fit(X, y, coords)
print_model_result(model)
print("modified_pvalues=", model.modified_p_values_)
print("localized_p_values_shape=", model.localized_p_values_.shape)
Run it from the examples/models directory or through python examples/run_all.py.
Reading the fitted result¶
Main outputs: Observed test statistics, modified/global p-values, optional localized p-values, bootstrap bandwidths, stored coefficient replicates, summaries, and result frames.
Available high-level methods detected in the current class are: fit(), summary(), to_frame().
A safe inspection sequence is:
# 1. Human-readable overview
print(model.summary()) if hasattr(model, "summary") else None
# 2. Location-indexed table when supported
frame = model.to_frame() if hasattr(model, "to_frame") else None
# 3. Explicitly inspect the model-specific state
print([name for name in vars(model) if name.endswith("_")])
Do not assume that every model exposes the same outputs. Regression, classification, transformation, descriptive-statistics, and inference models have different result semantics.
Diagnostics and interpretation¶
Check Monte Carlo resolution, random-seed reproducibility, sensitivity to bandwidth reselection, and the multiplicity of localized tests.
The common diagnostics layer can be used where the fitted model provides the required fields:
from pygwrx.diagnostics import diagnostics_frame, local_diagnostic_frame
print(diagnostics_frame([model], labels=["BootstrapGWR"]))
try:
print(local_diagnostic_frame(model).head())
except (AttributeError, NotImplementedError, ValueError) as exc:
print("This model exposes a different diagnostic contract:", exc)
See Diagnostics and inference for model-aware checks and interpretation rules.
Recommended visual checks¶
The figures are generated from deterministic examples and are illustrative; they are not benchmark claims.
Common mistakes¶
- Using too few replicates for precise p-values.
- Claiming stationarity because a low-powered test is non-significant.
- Ignoring multiple testing for localized p-values.
- Treating the fixed OLS null as interchangeable with unsupported spatial-error or spatial-lag nulls.
What to report in a paper or technical report¶
- The validated OLS null model and both coefficient-wise/global and localized statistics.
- Number of bootstrap replicates and random seed.
- Bandwidth reselection choice.
- Global and localized p-value treatment.
- Monte Carlo uncertainty and multiplicity correction.
References¶
- Harris et al. (2017), Introducing bootstrap methods to investigate coefficient non-stationarity
- Brunsdon, Fotheringham & Charlton (1996), Geographically Weighted Regression: A Method for Exploring Spatial Nonstationarity