Skip to content

Spatial CV API

SpatialBlockSplitter

h2ml.features.spatial_cv.SpatialBlockSplitter

K-fold splitter that groups spatially adjacent samples into blocks and holds out entire blocks as test sets.

Blocks are formed by quantile-binning coordinates on each axis (robust to uneven spatial distributions) and assigned to folds round-robin. Each fold's test set is one or more contiguous blocks.

Parameters:

Name Type Description Default
coords ndarray

(n_samples, 2) array of spatial coordinates (lat/lon, x/y, or any 2-D position).

required
n_splits int

Number of CV folds.

5
n_blocks_per_fold int

Number of blocks per test fold. Total blocks = n_splits × n_blocks_per_fold. More blocks give finer spatial granularity at the cost of smaller individual test sets.

5
random_state int

Seed for the block→fold shuffle (reproducible folds).

42
metric SpatialMetric

"euclidean" (projected coords) or "haversine" (lat/lon in decimal degrees).

'euclidean'
Example

coords = np.column_stack([lats, lons]) splitter = SpatialBlockSplitter(coords, n_splits=5, n_blocks_per_fold=5) for train_idx, test_idx in splitter.split(X): ... model.fit(X[train_idx], y[train_idx]) ... score = model.score(X[test_idx], y[test_idx])

clone_with_n_splits(n_splits, random_state=None)

Return a new splitter with n_splits folds, reusing the same coords and metric.

get_n_splits(X=None, y=None, groups=None)

Number of folds (sklearn splitter interface; X/y/groups ignored).

plot(lon_col=1, lat_col=0, save_path=None)

Two-panel scatter of block and fold assignments.

Thin wrapper over h2ml.plots.plot_spatial_blocks(self); see that function for details.

split(X, y=None, groups=None)

Yield (train_idx, test_idx) for each of n_splits folds.

Parameters:

Name Type Description Default
X ndarray

Array-like whose row count must match the calibration coords.

required
y Optional[ndarray]

Ignored (sklearn signature compatibility).

None
groups Optional[ndarray]

Ignored (sklearn signature compatibility).

None

Yields:

Type Description
tuple[ndarray, ndarray]

(train_idx, test_idx) integer index arrays per fold.

Raises:

Type Description
ValueError

If len(X) does not match the number of stored coords.

SPCVSplitter

h2ml.features.spatial_cv.SPCVSplitter

Two-stage spatial cross-validation splitter (SP-CV). Reference: Wang et al. 2023. Spatial+: A new cross-validation method to evaluate geospatial machine learning models.

Stage 1 — AHC blocks: Agglomerative Hierarchical Clustering (AHC) on spatial coordinates forms blocks that respect the autocorrelation structure of the data. The AHC distance threshold controls block granularity; if not provided it defaults to the 10th percentile of pairwise distances.

Stage 2 — Cluster Ensemble fold assignment: Each block is represented by its mean coordinates, covariates, and target value. Three independent KMeans runs (on location, covariates, and target) are combined via Hybrid Bipartite Graph Formulation (HBGF): a co-occurrence affinity matrix is built from the stacked membership matrices and SpectralClustering produces the final k folds.

The result is folds that are geographically separated and representative of the full covariate and label space.

Parameters:

Name Type Description Default
coords ndarray

(n_samples, 2) spatial coordinates (lat/lon or projected).

required
X ndarray

(n_samples, n_features) covariate matrix.

required
y ndarray

(n_samples,) target array.

required
n_splits int

Number of CV folds (k).

5
threshold Optional[float]

AHC distance threshold. Defaults to the 10th percentile of pairwise coordinate distances when None.

None
linkage LinkageCriterion

Linkage criterion for AHC ('ward', 'average', 'complete'). 'ward' minimises within-cluster variance and works well for compact geographic blocks.

'ward'
random_state int

Seed for KMeans and SpectralClustering reproducibility.

42
metric SpatialMetric

"euclidean" (projected coords) or "haversine" (lat/lon in decimal degrees). See the Note on linkage interaction.

'euclidean'
pca_components float

Variance fraction retained by PCA applied to block covariates before clustering. Default 0.95.

0.95
exact_max_samples int

Sample count below which exact scipy AHC is used; above it an approximate sklearn AHC (k-NN graph) is used. Default 5000.

5000
knn_neighbors int

k for the k-NN connectivity graph in approximate AHC. Default 15.

15
Note

'ward' linkage operates on Euclidean distances. When metric='haversine', ward is silently downgraded to 'average' (in both the exact and approximate AHC paths) because ward is undefined for non-Euclidean distances. For projected coords (km, m) use metric='euclidean' and ward linkage is valid.

Example

splitter = SPCVSplitter(coords, X, y, n_splits=5) for train_idx, test_idx in splitter.split(X): ... model.fit(X[train_idx], y[train_idx]) ... score = model.score(X[test_idx], y[test_idx])

clone_with_n_splits(n_splits, random_state=None)

Return a new splitter with n_splits folds, reusing the AHC block structure.

Stage 1 (AHC clustering) is skipped — block_id_ is copied directly. Stage 2 (fold assignment) is rerun with the new n_splits and random_state, so each HPO repeat gets different fold boundaries without repeating AHC.

get_n_splits(X=None, y=None, groups=None)

Number of folds (sklearn splitter interface; X/y/groups ignored).

plot(lon_col=1, lat_col=0, save_path=None)

Two-panel scatter of block and fold assignments.

Thin wrapper over h2ml.plots.plot_spatial_blocks(self); see that function for details.

split(X, y=None, groups=None)

Yield (train_idx, test_idx) for each of n_splits folds.

Parameters:

Name Type Description Default
X ndarray

Array-like whose row count must match the calibration coords.

required
y Optional[ndarray]

Ignored (sklearn signature compatibility).

None
groups Optional[ndarray]

Ignored (sklearn signature compatibility).

None

Yields:

Type Description
tuple[ndarray, ndarray]

(train_idx, test_idx) integer index arrays per fold.

Raises:

Type Description
ValueError

If len(X) does not match the number of stored coords.