Skip to main content
Open llms.txtCopy tools

Spatial Cross-Validation

Use spatial validation when the claim is about generalizing to withheld places or regimes. Random CV can overstate quality when nearby pickup/dropoff rows share zone effects, road geometry, demand shocks, or weather conditions.

Build splits with cartoboost.validation. A split manifest records fold indices, coordinate and time assumptions, dependency versions, and a reproducibility hash. Store that hash with the benchmark artifact and reuse the exact folds for every candidate model.

Buffered spatial folds

Use projected coordinates when training rows near a held-out block must be removed from the training set:

import cartoboost
from cartoboost.geo import CoordinateMatrix
from cartoboost.validation import native_buffered_spatial_split

manifest = native_buffered_spatial_split(
CoordinateMatrix(pickup_x, pickup_y, crs="EPSG:2263"),
n_folds=5,
buffer_distance=500.0,
dataset_fingerprint="sha256:...",
coordinate_crs_note="EPSG:2263 projected pickup coordinates",
model_version=cartoboost.__version__,
dependency_versions={"cartoboost": cartoboost.__version__},
)
fold_id, train_idx, test_idx = manifest.folds()[0]

Latitude/longitude degree buffers are ambiguous. Project the coordinates first and record the CRS in coordinate_crs_note.

Grouped spatial folds

Use native_grouped_split when entire pickup zones, customers, lanes, or route families must be absent from training. Use a buffered manifest as well when nearby groups could leak signal through coordinates.

import cartoboost
from cartoboost.validation import native_grouped_split

manifest = native_grouped_split(
pickup_zone_ids,
n_folds=5,
dataset_fingerprint="sha256:...",
coordinate_crs_note="not_applicable",
model_version=cartoboost.__version__,
dependency_versions={"cartoboost": cartoboost.__version__},
)

If a fold leaves no usable training rows, the native constructor raises rather than weakening the requested validation design.

Temporal and spatial-temporal folds

Use native_temporal_split for rolling-origin forecasts and native_spatial_temporal_split when both location and time must be held out. Keep the training cutoff strictly before the forecast horizon and store the manifest hash alongside the forecast artifact.

Diagnostics

Residual Moran's I and the random-to-spatial score gap are supported diagnostics:

from cartoboost.metrics import residual_morans_i, spatial_cv_gap

gap = spatial_cv_gap(random_cv_rmse, buffered_cv_rmse)
residual_i = residual_morans_i(projected_pickup_xy_validation, residuals)

Use these diagnostics to explain a result, not to choose a model using holdout labels. For a complete comparison, report the split hash, target transform, feature access, baseline roster, RMSE/MAE, and fit/predict timing.