Skip to content

Base classes

This page documents 11 public symbols. Each entry includes its purpose, import path, full API docstring, and the maintained example that exercises it.

Conceptual guide

BaseSpatialEstimator

Root class for all spatial estimators.

Property Value
Type class
Import from pygwrx.core import BaseSpatialEstimator
Signature BaseSpatialEstimator(*, distance_metric: 'str' = 'euclidean', random_state: 'Optional[int]' = None, verbose: 'bool' = False) -> 'None'
Maintained example examples/core/08_base_classes.py

BaseSpatialEstimator

BaseSpatialEstimator(
    *,
    distance_metric: str = "euclidean",
    random_state: Optional[int] = None,
    verbose: bool = False
)

Bases: ABC

Root class for all spatial estimators.

The base class uses a single NumPy/SciPy numerical implementation. PyGWRx uses NumPy/SciPy internally; future acceleration should be implemented behind the numerical routines rather than exposed as an estimator parameter.

Source code in src/pygwrx/core/base.py
def __init__(
    self,
    *,
    distance_metric: str = "euclidean",
    random_state: Optional[int] = None,
    verbose: bool = False,
) -> None:
    self._validate_spatial_estimator_parameters(
        distance_metric=distance_metric,
        random_state=random_state,
        verbose=verbose,
    )
    self.distance_metric = distance_metric.strip().lower()
    self.random_state = random_state
    self.verbose = bool(verbose)

    self._is_fitted = False
    self.n_samples_: Optional[int] = None
    self.n_features_in_: Optional[int] = None
    self.feature_names_in_: Optional[np.ndarray] = None

is_fitted_ property

is_fitted_: bool

Whether the estimator completed a successful fit.

BaseSpatialRegressor

Base class for geographically weighted spatial regressors.

Property Value
Type class
Import from pygwrx.core import BaseSpatialRegressor
Signature BaseSpatialRegressor(kernel: 'KernelLike' = 'gaussian', bandwidth: 'BandwidthLike' = 'cv', bandwidth_method: 'str' = 'cv', fit_intercept: 'bool' = True, distance_metric: 'str' = 'euclidean', adaptive: 'bool' = False, bandwidth_range: 'Optional[Tuple[float, float]]' = None, optimization_method: 'str' = 'golden_section', random_state: 'Optional[int]' = None, verbose: 'bool' = False) -> 'None'
Maintained example examples/core/08_base_classes.py

BaseSpatialRegressor

BaseSpatialRegressor(
    kernel: KernelLike = "gaussian",
    bandwidth: BandwidthLike = "cv",
    bandwidth_method: str = "cv",
    fit_intercept: bool = True,
    distance_metric: str = "euclidean",
    adaptive: bool = False,
    bandwidth_range: Optional[Tuple[float, float]] = None,
    optimization_method: str = "golden_section",
    random_state: Optional[int] = None,
    verbose: bool = False,
)

Bases: BaseSpatialEstimator

Base class for geographically weighted spatial regressors.

This class combines the common regression contract with kernel, bandwidth, local-parameter, prediction, fitted-state, and result- export behavior used throughout the pyGWRx regression family.

Source code in src/pygwrx/core/base.py
def __init__(
    self,
    kernel: KernelLike = "gaussian",
    bandwidth: BandwidthLike = "cv",
    bandwidth_method: str = "cv",
    fit_intercept: bool = True,
    distance_metric: str = "euclidean",
    adaptive: bool = False,
    bandwidth_range: Optional[Tuple[float, float]] = None,
    optimization_method: str = "golden_section",
    random_state: Optional[int] = None,
    verbose: bool = False,
) -> None:
    super().__init__(
        distance_metric=distance_metric,
        random_state=random_state,
        verbose=verbose,
    )
    if not isinstance(fit_intercept, (bool, np.bool_)):
        raise TypeError("fit_intercept must be boolean.")
    self.fit_intercept = bool(fit_intercept)
    self._reset_regression_state()

    self._validate_gwr_parameters(
        kernel=kernel,
        bandwidth=bandwidth,
        bandwidth_method=bandwidth_method,
        adaptive=adaptive,
        bandwidth_range=bandwidth_range,
        optimization_method=optimization_method,
    )
    self.kernel = kernel
    self.bandwidth = bandwidth
    self.bandwidth_method = bandwidth_method.strip().lower()
    self.adaptive = bool(adaptive)
    self.bandwidth_range = bandwidth_range
    self.optimization_method = optimization_method
    self._reset_gwr_state()

to_frame

to_frame() -> pd.DataFrame

Return training-location coefficients and diagnostics as a DataFrame.

Source code in src/pygwrx/core/base.py
def to_frame(self) -> pd.DataFrame:
    """Return training-location coefficients and diagnostics as a DataFrame."""
    self._check_is_fitted()
    if self.X_train_ is None:
        raise RuntimeError("Training data are unavailable.")

    n = self.X_train_.shape[0]
    output: Dict[str, Any] = {}
    if self.coords_train_ is not None:
        for j in range(self.coords_train_.shape[1]):
            output[f"coord_{j}"] = self.coords_train_[:, j]

    if self.intercept_ is not None:
        values = np.asarray(self.intercept_).reshape(-1)
        if values.size == n:
            output["intercept"] = values

    if self.coef_ is not None:
        coef = np.asarray(self.coef_)
        if coef.ndim == 1:
            coef = coef.reshape(-1, 1)
        names = (
            [str(name) for name in self.feature_names_in_]
            if self.feature_names_in_ is not None
            and len(self.feature_names_in_) == coef.shape[1]
            else [f"x{j}" for j in range(coef.shape[1])]
        )
        for j, name in enumerate(names):
            output[f"coef_{name}"] = coef[:, j]

    for name, values in (
        ("fitted", self.fitted_values_),
        ("residual", self.residuals_),
        ("local_r2", self.local_r2_),
    ):
        if values is not None:
            array = np.asarray(values).reshape(-1)
            if array.size == n:
                output[name] = array
    return pd.DataFrame(output)

to_geodataframe

to_geodataframe(crs: Optional[Union[str, int]] = None)

Return training-location results as a point GeoDataFrame.

Source code in src/pygwrx/core/base.py
def to_geodataframe(self, crs: Optional[Union[str, int]] = None):
    """Return training-location results as a point GeoDataFrame."""
    from pygwrx.io import to_geodataframe

    frame = self.to_frame()
    if self.coords_train_ is None:
        raise RuntimeError("Training coordinates are unavailable.")
    data_columns = [
        column for column in frame.columns if not column.startswith("coord_")
    ]
    return to_geodataframe(
        frame[data_columns].to_numpy(dtype=float),
        None,
        self.coords_train_,
        feature_names=data_columns,
        crs=crs,
    )

BaseGWR

Base class for geographically weighted spatial regressors.

Property Value
Type class
Import from pygwrx.core import BaseGWR
Signature BaseGWR(kernel: 'KernelLike' = 'gaussian', bandwidth: 'BandwidthLike' = 'cv', bandwidth_method: 'str' = 'cv', fit_intercept: 'bool' = True, distance_metric: 'str' = 'euclidean', adaptive: 'bool' = False, bandwidth_range: 'Optional[Tuple[float, float]]' = None, optimization_method: 'str' = 'golden_section', random_state: 'Optional[int]' = None, verbose: 'bool' = False) -> 'None'
Maintained example examples/core/08_base_classes.py

BaseGWR module-attribute

BaseGWR = BaseSpatialRegressor

SpatiotemporalMixin

No summary is available.

Property Value
Type class
Import from pygwrx.core import SpatiotemporalMixin
Signature SpatiotemporalMixin()
Maintained example examples/core/08_base_classes.py

SpatiotemporalMixin

MultiscaleMixin

No summary is available.

Property Value
Type class
Import from pygwrx.core import MultiscaleMixin
Signature MultiscaleMixin()
Maintained example examples/core/08_base_classes.py

MultiscaleMixin

BaseSpatiotemporalRegressor

Base for spatiotemporal GWR-family regressors.

Property Value
Type class
Import from pygwrx.core import BaseSpatiotemporalRegressor
Signature BaseSpatiotemporalRegressor(kernel: 'KernelLike' = 'gaussian', bandwidth: 'BandwidthLike' = 'cv', bandwidth_method: 'str' = 'cv', fit_intercept: 'bool' = True, distance_metric: 'str' = 'euclidean', adaptive: 'bool' = False, bandwidth_range: 'Optional[Tuple[float, float]]' = None, optimization_method: 'str' = 'golden_section', random_state: 'Optional[int]' = None, verbose: 'bool' = False) -> 'None'
Maintained example examples/core/08_base_classes.py

BaseSpatiotemporalRegressor

BaseSpatiotemporalRegressor(
    kernel: KernelLike = "gaussian",
    bandwidth: BandwidthLike = "cv",
    bandwidth_method: str = "cv",
    fit_intercept: bool = True,
    distance_metric: str = "euclidean",
    adaptive: bool = False,
    bandwidth_range: Optional[Tuple[float, float]] = None,
    optimization_method: str = "golden_section",
    random_state: Optional[int] = None,
    verbose: bool = False,
)

Bases: SpatiotemporalMixin, BaseSpatialRegressor

Base for spatiotemporal GWR-family regressors.

Source code in src/pygwrx/core/base.py
def __init__(
    self,
    kernel: KernelLike = "gaussian",
    bandwidth: BandwidthLike = "cv",
    bandwidth_method: str = "cv",
    fit_intercept: bool = True,
    distance_metric: str = "euclidean",
    adaptive: bool = False,
    bandwidth_range: Optional[Tuple[float, float]] = None,
    optimization_method: str = "golden_section",
    random_state: Optional[int] = None,
    verbose: bool = False,
) -> None:
    super().__init__(
        distance_metric=distance_metric,
        random_state=random_state,
        verbose=verbose,
    )
    if not isinstance(fit_intercept, (bool, np.bool_)):
        raise TypeError("fit_intercept must be boolean.")
    self.fit_intercept = bool(fit_intercept)
    self._reset_regression_state()

    self._validate_gwr_parameters(
        kernel=kernel,
        bandwidth=bandwidth,
        bandwidth_method=bandwidth_method,
        adaptive=adaptive,
        bandwidth_range=bandwidth_range,
        optimization_method=optimization_method,
    )
    self.kernel = kernel
    self.bandwidth = bandwidth
    self.bandwidth_method = bandwidth_method.strip().lower()
    self.adaptive = bool(adaptive)
    self.bandwidth_range = bandwidth_range
    self.optimization_method = optimization_method
    self._reset_gwr_state()

BaseMultiscaleRegressor

Base for one-bandwidth-per-coefficient regressors.

Property Value
Type class
Import from pygwrx.core import BaseMultiscaleRegressor
Signature BaseMultiscaleRegressor(*args: 'Any', **kwargs: 'Any') -> 'None'
Maintained example examples/core/08_base_classes.py

BaseMultiscaleRegressor

BaseMultiscaleRegressor(*args: Any, **kwargs: Any)

Bases: MultiscaleMixin, BaseSpatialRegressor

Base for one-bandwidth-per-coefficient regressors.

Source code in src/pygwrx/core/base.py
def __init__(self, *args: Any, **kwargs: Any) -> None:
    super().__init__(*args, **kwargs)
    self._reset_multiscale_state()

BaseSpatialClassifier

Base class for spatial classifiers such as GWDA.

Property Value
Type class
Import from pygwrx.core import BaseSpatialClassifier
Signature BaseSpatialClassifier(**kwargs: 'Any') -> 'None'
Maintained example examples/core/08_base_classes.py

BaseSpatialClassifier

BaseSpatialClassifier(**kwargs: Any)

Bases: BaseSpatialEstimator

Base class for spatial classifiers such as GWDA.

Source code in src/pygwrx/core/base.py
def __init__(self, **kwargs: Any) -> None:
    super().__init__(**kwargs)
    self.classes_: Optional[np.ndarray] = None
    self.diagnostics_: Optional[Dict[str, Any]] = None

BaseSpatialTransformer

Root class for all spatial estimators.

Property Value
Type class
Import from pygwrx.core import BaseSpatialTransformer
Signature BaseSpatialTransformer(*, distance_metric: 'str' = 'euclidean', random_state: 'Optional[int]' = None, verbose: 'bool' = False) -> 'None'
Maintained example examples/core/08_base_classes.py

BaseSpatialTransformer

BaseSpatialTransformer(
    *,
    distance_metric: str = "euclidean",
    random_state: Optional[int] = None,
    verbose: bool = False
)

Bases: BaseSpatialEstimator

Source code in src/pygwrx/core/base.py
def __init__(
    self,
    *,
    distance_metric: str = "euclidean",
    random_state: Optional[int] = None,
    verbose: bool = False,
) -> None:
    self._validate_spatial_estimator_parameters(
        distance_metric=distance_metric,
        random_state=random_state,
        verbose=verbose,
    )
    self.distance_metric = distance_metric.strip().lower()
    self.random_state = random_state
    self.verbose = bool(verbose)

    self._is_fitted = False
    self.n_samples_: Optional[int] = None
    self.n_features_in_: Optional[int] = None
    self.feature_names_in_: Optional[np.ndarray] = None

BaseSpatialStatistics

Root class for all spatial estimators.

Property Value
Type class
Import from pygwrx.core import BaseSpatialStatistics
Signature BaseSpatialStatistics(*, distance_metric: 'str' = 'euclidean', random_state: 'Optional[int]' = None, verbose: 'bool' = False) -> 'None'
Maintained example examples/core/08_base_classes.py

BaseSpatialStatistics

BaseSpatialStatistics(
    *,
    distance_metric: str = "euclidean",
    random_state: Optional[int] = None,
    verbose: bool = False
)

Bases: BaseSpatialEstimator

Source code in src/pygwrx/core/base.py
def __init__(
    self,
    *,
    distance_metric: str = "euclidean",
    random_state: Optional[int] = None,
    verbose: bool = False,
) -> None:
    self._validate_spatial_estimator_parameters(
        distance_metric=distance_metric,
        random_state=random_state,
        verbose=verbose,
    )
    self.distance_metric = distance_metric.strip().lower()
    self.random_state = random_state
    self.verbose = bool(verbose)

    self._is_fitted = False
    self.n_samples_: Optional[int] = None
    self.n_features_in_: Optional[int] = None
    self.feature_names_in_: Optional[np.ndarray] = None

BaseSpatialInference

Root class for all spatial estimators.

Property Value
Type class
Import from pygwrx.core import BaseSpatialInference
Signature BaseSpatialInference(*, distance_metric: 'str' = 'euclidean', random_state: 'Optional[int]' = None, verbose: 'bool' = False) -> 'None'
Maintained example examples/core/08_base_classes.py

BaseSpatialInference

BaseSpatialInference(
    *,
    distance_metric: str = "euclidean",
    random_state: Optional[int] = None,
    verbose: bool = False
)

Bases: BaseSpatialEstimator

Source code in src/pygwrx/core/base.py
def __init__(
    self,
    *,
    distance_metric: str = "euclidean",
    random_state: Optional[int] = None,
    verbose: bool = False,
) -> None:
    self._validate_spatial_estimator_parameters(
        distance_metric=distance_metric,
        random_state=random_state,
        verbose=verbose,
    )
    self.distance_metric = distance_metric.strip().lower()
    self.random_state = random_state
    self.verbose = bool(verbose)

    self._is_fitted = False
    self.n_samples_: Optional[int] = None
    self.n_features_in_: Optional[int] = None
    self.feature_names_in_: Optional[np.ndarray] = None

Runnable examples used on this page

examples/core/08_base_classes.py
# SPDX-FileCopyrightText: 2026 Jinghao Hu
# SPDX-License-Identifier: MIT

"""Implement minimal concrete estimators from every public base class/mixin."""

from __future__ import annotations

# Allow this script to run directly from any working directory.
import sys
from pathlib import Path

_PROJECT_ROOT = Path(__file__).resolve().parents[2]
_EXAMPLES_ROOT = _PROJECT_ROOT / "examples"
_SRC_ROOT = _PROJECT_ROOT / "src"
for _path in (_SRC_ROOT, _EXAMPLES_ROOT):
    if str(_path) not in sys.path:
        sys.path.insert(0, str(_path))

import numpy as np
import pandas as pd

from pygwrx.core import (
    BaseGWR,
    BaseMultiscaleRegressor,
    BaseSpatialClassifier,
    BaseSpatialEstimator,
    BaseSpatialInference,
    BaseSpatialRegressor,
    BaseSpatialStatistics,
    BaseSpatialTransformer,
    BaseSpatiotemporalRegressor,
    MultiscaleMixin,
    SpatiotemporalMixin,
)


class MeanRegressor(BaseSpatialRegressor):
    """Minimal concrete spatial regressor for base-contract demonstration."""

    def fit(self, X, y, coords, **kwargs):
        Xa, ya, ca = self._validate_inputs(X, y, coords)
        self._store_training_data(Xa, ya, ca)
        self.mean_ = float(np.mean(ya))
        self._mark_fitted()
        return self

    def predict(self, X, coords, **kwargs):
        Xa, _ = self._validate_prediction_inputs(X, coords)
        return np.full(Xa.shape[0], self.mean_)


class TinyGWR(BaseSpatialRegressor):
    """Minimal concrete GWR-style regressor."""

    def fit(self, X, y, coords, **kwargs):
        Xa, ya, ca = self._validate_inputs(X, y, coords)
        self._store_training_data(Xa, ya, ca)
        self.bandwidth_ = 1.0
        self.coef_ = np.zeros_like(Xa)
        self.intercept_ = np.full(len(ya), ya.mean())
        self.fitted_values_ = self.intercept_.copy()
        self.residuals_ = ya - self.fitted_values_
        self._mark_fitted()
        return self

    def predict(self, X, coords, **kwargs):
        Xa, _ = self._validate_prediction_inputs(X, coords)
        return np.full(len(Xa), self.y_train_.mean())


class TimeRegressor(SpatiotemporalMixin, MeanRegressor):
    """Concrete demonstration of the spatiotemporal mixin."""


class MultiRegressor(MultiscaleMixin, MeanRegressor):
    """Concrete demonstration of the multiscale mixin."""


class ConcreteSTR(BaseSpatiotemporalRegressor, MeanRegressor):
    """Concrete base spatiotemporal regressor."""

    fit = MeanRegressor.fit
    predict = MeanRegressor.predict


class ConcreteMSR(BaseMultiscaleRegressor, MeanRegressor):
    """Concrete base multiscale regressor."""

    fit = MeanRegressor.fit
    predict = MeanRegressor.predict


class MajorityClassifier(BaseSpatialClassifier):
    """Minimal majority-class spatial classifier."""

    def fit(self, X, y, coords, **kwargs):
        self._validate_spatial_inputs(X, coords, reset=True)
        values, counts = np.unique(y, return_counts=True)
        self.classes_ = values
        self.majority_ = values[np.argmax(counts)]
        self._mark_fitted()
        return self

    def predict(self, X, coords, **kwargs):
        Xa, _ = self._validate_spatial_inputs(X, coords, reset=False)
        return np.repeat(self.majority_, len(Xa))

    def predict_proba(self, X, coords, **kwargs):
        prediction = self.predict(X, coords)
        return np.column_stack(
            [prediction == class_value for class_value in self.classes_]
        ).astype(float)


class IdentityTransformer(BaseSpatialTransformer):
    """Minimal identity spatial transformer."""

    def fit(self, X, coords, **kwargs):
        self._validate_spatial_inputs(X, coords, reset=True)
        self._mark_fitted()
        return self

    def transform(self, X, coords, **kwargs):
        Xa, _ = self._validate_spatial_inputs(X, coords, reset=False)
        return Xa


class ColumnStatistics(BaseSpatialStatistics):
    """Minimal column-mean spatial statistics estimator."""

    def fit(self, X, coords, **kwargs):
        Xa, ca = self._validate_spatial_inputs(X, coords, reset=True)
        self.means_ = Xa.mean(axis=0)
        self.coords_train_ = ca
        self._mark_fitted()
        return self

    def to_frame(self):
        self._check_is_fitted()
        return pd.DataFrame({"mean": self.means_})


class BasicInference(BaseSpatialInference):
    """Minimal inference result container."""

    def fit(self, X, y, coords, **kwargs):
        self.n_samples_ = len(y)
        self._mark_fitted()
        return self

    def summary(self):
        self._check_is_fitted()
        return f"n_samples={self.n_samples_}"


# BaseGWR remains an identity alias for backward compatibility.
assert BaseGWR is BaseSpatialRegressor


X = pd.DataFrame({"x": [0.0, 1.0, 2.0, 3.0]})
y = np.array([1.0, 2.0, 2.0, 3.0])
coords = np.column_stack((np.arange(4), np.zeros(4)))

for model in (
    MeanRegressor(),
    TinyGWR(bandwidth=1.0),
    TimeRegressor(),
    MultiRegressor(),
    ConcreteSTR(),
    ConcreteMSR(),
):
    model.fit(X, y, coords)
    print(type(model).__name__, model.predict(X.iloc[:2], coords[:2]))

print("root_estimator=", BaseSpatialEstimator.__name__)
classifier = MajorityClassifier().fit(X, np.array([0, 1, 1, 1]), coords)
print("classifier=", classifier.predict(X, coords), classifier.predict_proba(X, coords))
print("transformer=", IdentityTransformer().fit(X, coords).transform(X, coords))
print("statistics=", ColumnStatistics().fit(X, coords).to_frame())
print("inference=", BasicInference().fit(X, y, coords).summary())