Skip to content

GWLasso

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

Conceptual guide

GWLasso

Geographically weighted Lasso regression.

Property Value
Type class
Import from pygwrx.models import GWLasso
Signature GWLasso(kernel: 'Union[str, Callable]' = 'exponential', bandwidth: 'Union[float, int, str, None]' = 'cv', alpha: 'AlphaLike' = 'cv', alpha_grid: 'Optional[Sequence[float]]' = None, n_alphas: 'int' = 30, alpha_min_ratio: 'float' = 0.001, cv_folds: 'int' = 5, standardize: 'bool' = True, adaptive: 'bool' = False, bandwidth_range: 'Optional[Tuple[float, float]]' = None, n_bandwidths: 'int' = 8, max_iter: 'int' = 5000, tol: 'float' = 1e-06, active_tol: 'float' = 1e-08, fit_intercept: 'bool' = True, distance_metric: 'str' = 'euclidean', random_state: 'Optional[int]' = 0, verbose: 'bool' = False) -> 'None'
Maintained example examples/models/07_gw_lasso.py

GWLasso

GWLasso(
    kernel: Union[str, Callable] = "exponential",
    bandwidth: Union[float, int, str, None] = "cv",
    alpha: AlphaLike = "cv",
    alpha_grid: Optional[Sequence[float]] = None,
    n_alphas: int = 30,
    alpha_min_ratio: float = 0.001,
    cv_folds: int = 5,
    standardize: bool = True,
    adaptive: bool = False,
    bandwidth_range: Optional[Tuple[float, float]] = None,
    n_bandwidths: int = 8,
    max_iter: int = 5000,
    tol: float = 1e-06,
    active_tol: float = 1e-08,
    fit_intercept: bool = True,
    distance_metric: str = "euclidean",
    random_state: Optional[int] = 0,
    verbose: bool = False,
)

Bases: BaseSpatialRegressor

Geographically weighted Lasso regression.

At evaluation location :math:s, the model solves

.. math::

\frac{1}{2\sum_i w_i(s)}\sum_i w_i(s)
\left(y_i-\beta_0(s)-x_i^T\beta(s)\right)^2
+ \lambda(s)\|\beta^*(s)\|_1,

where :math:\beta^* denotes coefficients on locally standardised predictors. The intercept is never penalised. alpha="cv" selects a separate local penalty at every calibration or prediction location.

Parameters:

Name Type Description Default
kernel Union[str, Callable]

Spatial kernel name or callable. Wheeler's original implementation used an exponential kernel; all standard pyGWRx kernels are supported.

'exponential'
bandwidth Union[float, int, str, None]

Fixed distance, adaptive neighbour count, or a selection token. Use "cv" to select according to adaptive. "adaptive" is a convenience token that selects an adaptive-neighbour bandwidth by CV.

'cv'
alpha AlphaLike

Non-negative fixed Lasso penalty, or "cv" for a locally selected penalty. alpha=0 gives locally weighted least squares after the same weighting and intercept conventions.

'cv'
alpha_grid Optional[Sequence[float]]

Optional descending or ascending positive penalty candidates. When omitted, a local logarithmic path is generated from alpha_max.

None
n_alphas int

Number of generated local penalty candidates.

30
alpha_min_ratio float

Smallest generated penalty as a fraction of alpha_max.

0.001
cv_folds int

Number of deterministic shuffled folds for local penalty selection.

5
standardize bool

Standardise predictors using local weighted means and scales.

True
adaptive bool

Interpret a numeric bandwidth as an integer neighbour count.

False
bandwidth_range Optional[Tuple[float, float]]

Optional lower and upper bounds for bandwidth selection.

None
n_bandwidths int

Number of grid candidates used for bandwidth CV.

8
max_iter int

Maximum coordinate-descent iterations for every local Lasso.

5000
tol float

Coordinate-descent convergence tolerance.

1e-06
active_tol float

Absolute coefficient threshold used for local variable selection.

1e-08
fit_intercept bool

Estimate an unpenalised local intercept.

True
distance_metric str

Distance metric used by pyGWRx.

'euclidean'
random_state Optional[int]

Seed used for reproducible local CV folds.

0
verbose bool

Print bandwidth and fitting progress.

False

Attributes:

Name Type Description
coef_

Local coefficient matrix with shape (n_samples, n_features).

intercept_

Local intercept vector.

alpha_

Locally selected penalty values.

active_vars_

Active predictor indices at every location.

selection_frequency_

Fraction of locations selecting each predictor.

bandwidth_

Selected fixed distance or adaptive neighbour count.

References

Wheeler, D. C. (2009). Simultaneous coefficient penalization and model selection in geographically weighted regression: The geographically weighted lasso. Environment and Planning A, 41(3), 722-742.

Mulot, M., & Erb, S. (2025). GWlasso: Geographically Weighted Lasso. CRAN package version 1.0.2.

Source code in src/pygwrx/models/gw_lasso.py
def __init__(
    self,
    kernel: Union[str, Callable] = "exponential",
    bandwidth: Union[float, int, str, None] = "cv",
    alpha: AlphaLike = "cv",
    alpha_grid: Optional[Sequence[float]] = None,
    n_alphas: int = 30,
    alpha_min_ratio: float = 1e-3,
    cv_folds: int = 5,
    standardize: bool = True,
    adaptive: bool = False,
    bandwidth_range: Optional[Tuple[float, float]] = None,
    n_bandwidths: int = 8,
    max_iter: int = 5000,
    tol: float = 1e-6,
    active_tol: float = 1e-8,
    fit_intercept: bool = True,
    distance_metric: str = "euclidean",
    random_state: Optional[int] = 0,
    verbose: bool = False,
) -> None:
    adaptive_effective = bool(adaptive)
    if isinstance(bandwidth, str) and bandwidth.strip().lower() == "adaptive":
        adaptive_effective = True

    super().__init__(
        kernel=kernel,
        bandwidth=bandwidth,
        bandwidth_method="cv",
        fit_intercept=fit_intercept,
        distance_metric=distance_metric,
        adaptive=adaptive_effective,
        bandwidth_range=bandwidth_range,
        optimization_method="grid",
        random_state=random_state,
        verbose=verbose,
    )
    self.alpha = alpha
    self.alpha_grid = alpha_grid
    self.n_alphas = n_alphas
    self.alpha_min_ratio = alpha_min_ratio
    self.cv_folds = cv_folds
    self.standardize = standardize
    self.n_bandwidths = n_bandwidths
    self.max_iter = max_iter
    self.tol = tol
    self.active_tol = active_tol
    self._validate_lasso_parameters()
    self._reset_gw_lasso_state()

fit

fit(
    X: Union[ndarray, DataFrame],
    y: Union[ndarray, Series],
    coords: Union[ndarray, DataFrame],
) -> "GWLasso"

Fit local geographically weighted Lasso models.

Source code in src/pygwrx/models/gw_lasso.py
def fit(
    self,
    X: Union[np.ndarray, pd.DataFrame],
    y: Union[np.ndarray, pd.Series],
    coords: Union[np.ndarray, pd.DataFrame],
) -> "GWLasso":
    """Fit local geographically weighted Lasso models."""
    self._reset_gw_lasso_state()
    try:
        X_arr, y_arr, coords_arr = self._validate_inputs(X, y, coords)
        if X_arr.shape[0] < 4:
            raise ValueError("GWLasso requires at least four observations.")
        self._store_training_data(X_arr, y_arr, coords_arr)
        self.kernel_func_ = get_kernel_function(self.kernel)
        distances = compute_distance_matrix(
            coords_arr,
            coords_arr,
            metric=self.distance_metric,
        )
        self.bandwidth_ = self._resolve_bandwidth(
            X_arr,
            y_arr,
            distances,
        )
        (
            self.coef_,
            self.intercept_,
            self.alpha_,
            self.active_vars_,
            self.local_objective_,
            self.n_iter_,
            self.converged_,
            self.local_alpha_cv_score_,
        ) = self._fit_at_locations(
            X_arr,
            y_arr,
            distances,
            seed_start=0,
        )
        self.fitted_values_ = self.intercept_ + np.einsum(
            "ij,ij->i",
            X_arr,
            self.coef_,
        )
        self.residuals_ = y_arr - self.fitted_values_
        selected = np.abs(self.coef_) > float(self.active_tol)
        self.selection_frequency_ = np.mean(selected, axis=0)
        self.mean_active_variables_ = float(np.mean(np.sum(selected, axis=1)))
        approximate_params = self.mean_active_variables_ + (
            1.0 if self.fit_intercept else 0.0
        )
        self.diagnostics_ = compute_diagnostics(
            y_arr,
            self.fitted_values_,
            n_features=approximate_params,
        )
        self.diagnostics_.update(
            {
                "mean_active_variables": self.mean_active_variables_,
                "all_local_fits_converged": bool(np.all(self.converged_)),
                "bandwidth": float(self.bandwidth_),
                "adaptive": bool(self.adaptive),
                "mean_alpha": float(np.mean(self.alpha_)),
            }
        )
        self.parameter_names_ = self._feature_names()
        self._mark_fitted()
        return self
    except Exception:
        self._reset_gw_lasso_state()
        raise

predict_parameters

predict_parameters(
    coords: Union[ndarray, DataFrame],
) -> GWLassoPredictionResult

Estimate local coefficients at arbitrary coordinates.

Source code in src/pygwrx/models/gw_lasso.py
def predict_parameters(
    self,
    coords: Union[np.ndarray, pd.DataFrame],
) -> GWLassoPredictionResult:
    """Estimate local coefficients at arbitrary coordinates."""
    self._check_is_fitted()
    if self.X_train_ is None or self.y_train_ is None or self.coords_train_ is None:
        raise RuntimeError("Stored training data are required for prediction.")
    from pygwrx.core.utils import validate_coords

    coords_arr = validate_coords(coords)
    distances = compute_distance_matrix(
        coords_arr,
        self.coords_train_,
        metric=self.distance_metric,
    )
    (
        coefficients,
        intercepts,
        alphas,
        active,
        _,
        _,
        _,
        _,
    ) = self._fit_at_locations(
        self.X_train_,
        self.y_train_,
        distances,
        seed_start=1_000_000,
    )
    return GWLassoPredictionResult(
        predictions=None,
        coefficients=coefficients,
        intercepts=intercepts,
        alphas=alphas,
        active_variables=tuple(active),
        coords=coords_arr,
        feature_names=self._feature_names(),
    )

predict

predict(
    X: Union[ndarray, DataFrame],
    coords: Union[ndarray, DataFrame],
) -> np.ndarray

Predict by calibrating a weighted Lasso at each new location.

Source code in src/pygwrx/models/gw_lasso.py
def predict(
    self,
    X: Union[np.ndarray, pd.DataFrame],
    coords: Union[np.ndarray, pd.DataFrame],
) -> np.ndarray:
    """Predict by calibrating a weighted Lasso at each new location."""
    self._check_is_fitted()
    X_arr, coords_arr = self._validate_prediction_inputs(X, coords)
    result = self.predict_parameters(coords_arr)
    return result.intercepts + np.einsum(
        "ij,ij->i",
        X_arr,
        result.coefficients,
    )

get_variable_importance

get_variable_importance() -> np.ndarray

Return local selection frequency for every predictor.

Source code in src/pygwrx/models/gw_lasso.py
def get_variable_importance(self) -> np.ndarray:
    """Return local selection frequency for every predictor."""
    self._check_is_fitted()
    if self.selection_frequency_ is None:
        raise RuntimeError("selection_frequency_ is unavailable.")
    return self.selection_frequency_.copy()

to_frame

to_frame() -> pd.DataFrame

Return fitted local coefficients, selections, and residuals.

Source code in src/pygwrx/models/gw_lasso.py
def to_frame(self) -> pd.DataFrame:
    """Return fitted local coefficients, selections, and residuals."""
    self._check_is_fitted()
    if (
        self.coef_ is None
        or self.intercept_ is None
        or self.alpha_ is None
        or self.coords_train_ is None
        or self.fitted_values_ is None
        or self.residuals_ is None
        or self.active_vars_ is None
    ):
        raise RuntimeError("Fitted GWLasso results are incomplete.")
    result = GWLassoPredictionResult(
        predictions=self.fitted_values_,
        coefficients=self.coef_,
        intercepts=self.intercept_,
        alphas=self.alpha_,
        active_variables=tuple(self.active_vars_),
        coords=self.coords_train_,
        feature_names=self._feature_names(),
    ).to_frame()
    result["residual"] = self.residuals_
    result["objective"] = self.local_objective_
    result["converged"] = self.converged_
    return result

Runnable examples used on this page

examples/models/07_gw_lasso.py
# SPDX-FileCopyrightText: 2026 Jinghao Hu
# SPDX-License-Identifier: MIT

"""Fit geographically weighted Lasso with a fixed local penalty."""

# 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))

from _common import print_model_result, spatial_regression

from pygwrx import GWLasso

X, y, coords = spatial_regression(n=48, p=3)
model = GWLasso(
    bandwidth=24, adaptive=True, alpha=0.06, max_iter=1000, random_state=0
).fit(X, y, coords)
print_model_result(model)
print("selection_frequency=", model.selection_frequency_)
print("predictions=", model.predict(X.iloc[:3], coords.iloc[:3]))