cv_cluster: Use environmental or spatial clustering to separate train and...

View source: R/cv_cluster.R

cv_clusterR Documentation

Use environmental or spatial clustering to separate train and test folds

Description

This function uses clustering methods to specify sets of similar environmental conditions based on the input covariates, or cluster of spatial coordinates of the sample data. Sample data (i.e. species data) corresponding to any of these groups or clusters are assigned to a fold. Clustering is done using kmeans for both approaches. The only requirement is x that leads to a clustering of the coordinates of sample data. Otherwise, by providing r, environmental clustering is done. Environmental clustering can also be spatially restricted with spatial_weight, and fold sizes or classes can be balanced with balance = TRUE; see Details.

Usage

cv_cluster(
  x,
  column = NULL,
  r = NULL,
  k = 5L,
  scale = TRUE,
  raster_cluster = FALSE,
  num_sample = 10000L,
  spatial_weight = 0,
  balance = FALSE,
  presence_bg = FALSE,
  k_multiplier = 5L,
  iteration = 100L,
  seed = NULL,
  biomod2 = TRUE,
  num_bins = 4L,
  report = interactive(),
  progress = interactive(),
  ...
)

Arguments

x

a simple features (sf) or SpatialPoints object of spatial sample data (e.g., species data or ground truth sample for image classification).

column

character (optional). Indicating the name of the column in which response variable (e.g. species data as a binary response i.e. 0s and 1s) is stored. It is used to report whether all the folds contain all the classes and, when balance = TRUE, to balance those classes across the folds. Continuous numeric responses are binned into quantiles using num_bins before records are counted.

r

a terra SpatRaster object of covariates to identify environmental groups. If provided, clustering will be done in environmental space rather than spatial coordinates of sample points. Only numeric (quantitative) covariates are supported; categorical (factor) layers are rejected because k-means relies on Euclidean distance.

k

integer value. The number of desired folds for cross-validation. The default is k = 5.

scale

logical; whether to scale the input rasters (recommended) for clustering.

raster_cluster

logical; if TRUE, the clustering is done over the entire raster layer, otherwise it will be over the extracted raster values of the sample points. See details for more information.

num_sample

integer; the number of samples from raster layers to build the clusters (when raster_cluster = FALSE).

spatial_weight

numeric in [0, 1]; only used (and only validated) for environmental clustering (when r is provided). It adds a soft spatial compactness pressure by blending the geographic coordinates into the environmental clustering. 0 (the default) does pure environmental clustering; larger values (e.g. 0.30.5) give environmentally coherent folds that are also geographically separated; 1 clusters on the coordinates alone. See ‘Details’.

balance

logical. If TRUE, the sample points are first grouped into k * k_multiplier clusters (see k_multiplier) and these small clusters are then assigned to k folds over iteration random attempts to balance the training/testing records (or the classes/bins of column when it is provided). If FALSE (default), the points are clustered directly into k folds, which keeps the folds compact but does not control their size or class balance.

presence_bg

logical; whether to treat column as species presence-background data (0s for background points and 1s for presences; see ‘Details’). When TRUE (and balance = TRUE), the balancing search equalises only the presence (1s) records across folds so the many background points cannot dominate the objective; the background points are still clustered spatially but ignored when scoring the balance. Requires a binary numeric column. The default is FALSE.

k_multiplier

integer. The multiplier controlling how many clusters are created before they are merged into folds (i.e. k * k_multiplier). Only used when balance = TRUE. Larger values give more balanced folds at the cost of less compact folds; smaller values keep the folds compact but less balanced. The default is 5.

iteration

integer value. The number of random attempts to assign the clusters to folds when balance = TRUE.

seed

integer; a random seed for reproducibility of the balancing search.

biomod2

logical. Creates a matrix of folds that can be directly used in the biomod2 package as a CV.user.table for cross-validation.

num_bins

integer; the number of quantile bins used to stratify a continuous numeric column. The default is 4. Set num_bins = NULL to disable binning and treat every unique value as a separate class (the behaviour prior to version 3.3). If quantile breaks are tied, fewer bins may be used. The raw response values are not modified; bins are only used for fold balancing and record summaries.

report

logical; whether to print the report of the records per fold. Defaults to interactive().

progress

logical; whether to shows a progress bar for random fold selection. Defaults to interactive().

...

additional arguments for stats::kmeans function, e.g. algorithm = "MacQueen".

Details

As k-means algorithms use Euclidean distance to estimate clusters, the input raster covariates should be quantitative variables. Since variables with wider ranges of values might dominate the clusters and bias the environmental clustering (Hastie et al., 2009), all the input rasters are first scaled and centred (scale = TRUE) within the function.

If raster_cluster = TRUE, the clustering is done in the raster space. In this approach the clusters will be consistent throughout the region and different sample datasets in the same region (for comparison). However, this may result in a cluster(s) that covers none of the species records (the spatial location of response samples), especially when species data is not dispersed throughout the region or the number of clusters (k or folds) is high. In this case, the number of folds is less than specified k. If raster_cluster = FALSE, the clustering will be done in species points and the number of the folds will be the same as k.

Note that the input raster layer should cover all the species points, otherwise an error will rise. The records with no raster value should be deleted prior to the analysis or another raster layer must be provided.

By default (balance = FALSE) the points are clustered directly into k groups, so the folds are compact but their sizes – and the number of records of each class – can be very uneven. When balance = TRUE, the points are instead grouped into a larger number of clusters (k * k_multiplier) that are then assigned to k folds over iteration random attempts, keeping the split that best balances the training/testing records (or the classes/bins of column when it is provided). This mirrors the balancing used by cv_spatial with selection = "random", and k_multiplier controls the trade-off between fold balance (higher values) and fold compactness (lower values).

For environmental clustering (when r is provided), spatial_weight adds a soft spatial compactness pressure by blending the coordinates into the covariates before clustering, so the k-means Euclidean distance becomes (1 - w) d^2_{env} + w \, d^2_{geo}: spatial_weight = 0 (default) is pure environmental clustering, larger values pull the environmental clusters to be more geographically compact, and spatial_weight = 1 clusters on the coordinates alone. This is a soft pressure – it favours, but does not guarantee, spatially contiguous folds. The coordinates are always standardised (so a spatial_weight = 1 clustering is not identical to the coordinate-only clustering obtained with r = NULL, which uses the raw coordinates), while the covariates are standardised only when scale = TRUE; spatial_weight is best calibrated with the default scale = TRUE. Coordinates should be projected (a warning is issued for lon/lat data).

For presence-background data (presence_bg = TRUE), column holds 1 for presences and 0 for background points – locations sampled across the study area to represent the available conditions rather than confirmed absences. When balance = TRUE the balancing then equalises only the presence records across folds, so the abundant background cannot dominate the split.

Value

An object of class S3. A list of objects including:

  • folds_list - a list containing the folds. Each fold has two vectors with the training (first) and testing (second) indices

  • folds_ids - a vector of values indicating the number of the fold for each observation (each number corresponds to the same point in x)

  • biomod_table - a matrix with the folds to be used in biomod2 package

  • k - number of the folds

  • column - the name of the column if provided

  • type - indicates whether spatial or environmental clustering was done.

  • spatial_weight - the spatial weight used for environmental clustering (NA for spatial clustering).

  • records - a table with the number of points in each category of training and testing

References

Valavi, R., Elith, J., Lahoz-Monfort, J. J., & Guillera-Arroita, G. (2019). blockCV: An R package for generating spatially or environmentally separated folds for k-fold cross-validation of species distribution models. Methods in Ecology and Evolution, 10(2), 225-232. doi:10.1111/2041-210X.13107.

Hastie, T., Tibshirani, R., & Friedman, J. (2009). The elements of statistical learning: Data mining, inference, and prediction ( 2nd ed., Vol. 1).

See Also

cv_buffer and cv_spatial; cv_plot to visualise, and cv_distance and cv_similarity to evaluate, the folds

Examples


library(blockCV)

# import presence-absence species data
points <- read.csv(system.file("extdata/", "species.csv", package = "blockCV"))
# make an sf object from data.frame
pa_data <- sf::st_as_sf(points, coords = c("x", "y"), crs = 7845)

# load raster data
path <- system.file("extdata/au/", package = "blockCV")
files <- list.files(path, full.names = TRUE)
covars <- terra::rast(files)

# spatial clustering
set.seed(6)
sc <- cv_cluster(x = pa_data,
                 column = "occ", # optional; name of the column with response
                 k = 5)

# environmental clustering
set.seed(6)
ec <- cv_cluster(r = covars, # if provided will be used for environmental clustering
                 x = pa_data,
                 column = "occ", # optional; name of the column with response
                 k = 5,
                 scale = TRUE)

# spatially constrained environmental clustering
set.seed(6)
sec <- cv_cluster(r = covars,
                  x = pa_data,
                  column = "occ",
                  k = 5,
                  scale = TRUE,
                  spatial_weight = 0.4) # blend geography into the environmental clusters

# spatial clustering with balanced folds
set.seed(6)
bc <- cv_cluster(x = pa_data,
                 column = "occ",
                 k = 5,
                 balance = TRUE, # balance the records across the folds
                 k_multiplier = 3) # cluster into k * k_multiplier groups, then merge into k folds

# presence-background data: balance folds based on presences
points_pb <- read.csv(system.file("extdata/", "species_pb.csv", package = "blockCV"))
pb_data <- sf::st_as_sf(points_pb, coords = c("x", "y"), crs = 7845)
# pb_data <- pb_data[c(which(pb_data$occ == 1)[1:50], which(pb_data$occ == 0)[1:200]), ]

bc_pb <- cv_cluster(x = pb_data,
                    column = "occ",
                    k = 5,
                    presence_bg = TRUE,
                    balance = TRUE,
                    k_multiplier = 5)



blockCV documentation built on Aug. 20, 2026, 5:10 p.m.