Take a spatial sample based on a weights dataset.
Usage
wt_sample(x, size, weights, ...)
# S3 method for class 'sfc'
wt_sample(x, size, weights, ...)
# S3 method for class 'SpatVector'
wt_sample(x, size, weights = NULL, ...)
# S3 method for class 'sf'
wt_sample(
x,
size,
weights = NULL,
power = 1,
method = "random",
area_weight = 0,
replace = TRUE,
of_largest_polygon = TRUE,
...
)
# S3 method for class 'SpatRaster'
wt_sample(
x,
size,
weights = NULL,
power = 1,
method = "random",
replace = TRUE,
...
)Arguments
- x
A spatial dataset containing either vector data (
sf,sfc,SpatVector) or raster data (SpatRaster). This dataset both describes the extent of the sampling area and contains the feature used to weight the sampling.- size
Number of points to sample.
- weights
If
xis of classsf,SpatVectororSpatRaster, specifies the column by which to weight the sampling. Can also beNULLin which case sampling will be based on the first column or layer in the dataset. Ifxis of classsfc, is used to specify the weights vector directly, assfcobjects contain no information about features.- ...
If
xis of classsf, further arguments passed to the custom function passed tomethodif a function was provided. Otherwise, arguments passed tost_sample.sf.- power
Numeric value that scales the impact of weighting.
power = 0draws an unweighted sample0 < power < 1reduces the impact of weightingpower = 1draws normal weighted samplepower > 1increases the impact of weighting
- method
How to generate points from sampled polygons/cells.
"centroid"computes the geographic center."random"performs random polygon sampling. Ifxis a vector dataset, usesst_sample(..., type = "random"). Can be very slow for larger polygons. Ifxis a raster dataset, generates uniformly distributed raster values within the cell extent usingrunif."random_parallel"is a parallelized alternative to"random". Only available ifxconsists of vector data and thefuture.applypackage is installed. This can be very useful if traditional random spatial sampling is too slow. Only available for polygon sampling."random_cpp"is a C++ alternative to"random". It is much faster than both other random methods but I wrote it myself so there's a reasonable chance it produces junk. Only available for polygon sampling.Can also be a function or a purrr-style lambda taking at least one argument (the sampled points/polygons) and returning an object that can be coerced to
sfc. Ifxis aSpatRaster, the function can take an additional argument (the weights raster passed toweights). Further optional arguments to these custom functions can be provided using....
Defaults to
"centroid"for raster data and"random"for vector data. Generally,"centroid"makes more sense for regular high-resolution data (e.g. grids) while"random"is more natural for irregular low-resolution data (e.g. administrative divisions).- area_weight
Weight scaling applied to compensate for polygon size. If not 0, computes an additional weight based on the polygon area. Smaller polygons are weighted less than larger polygons to avoid a sort of "double weighting" where busy (i.e. economically stronger or more populated) areas are divided into more and smaller divisions. Defaults to 0, i.e. no area weighting. Ignored if
xis aSpatRaster.- replace
Passed to the
replaceargument insample. IfTRUE, allows the sampling to select the same polygons/cells multiple times. In this case,methodshould be set to"random"or a custom function if sampling identical locations is not desired. Defaults toFALSEfor raster data andTRUEfor vector data. See also themethodargument.- of_largest_polygon
Passed to
st_centroid. Ignored ifmethodis not"centroid". IfTRUEandxconsists of multipolygons, computes the centroid only of the largest polygon. Generally, this should beTRUEto prevent sampling outside of the polygon boundaries.
Examples
library(ggplot2)
library(sf)
#> Linking to GEOS 3.12.1, GDAL 3.8.4, PROJ 9.4.0; sf_use_s2() is TRUE
library(terra)
# Retrieve weights data
bel_pop <- wp_data("BEL")
# Demonstrate different weighting powers
samp_0 <- wt_sample(bel_pop, size = 1000, power = 0)
samp_5 <- wt_sample(bel_pop, size = 1000, power = 0.5)
samp_10 <- wt_sample(bel_pop, size = 1000, power = 1)
samp_15 <- wt_sample(bel_pop, size = 1000, power = 1.5)
groups <- paste("Weight:", rep(seq(0, 1.5, 0.5), each = length(samp_0)))
geom <- c(samp_0, samp_5, samp_10, samp_15)
gr_samp <- st_sf(group = groups, geometry = geom)
ggplot(gr_samp) +
geom_sf() +
facet_wrap(~group) +
theme_void()
# Demonstrate impact of method
bel_pop_agg <- aggregate(bel_pop, fact = 30)
n <- nrow(as.data.frame(bel_pop_agg))
samp_cent <- wt_sample(bel_pop_agg, size = n, method = "centroid")
samp_rand <- wt_sample(bel_pop_agg, size = n, method = "random")
plot(bel_pop_agg, main = "Red dots = centroid, green dots = random")
plot(samp_cent, add = TRUE, pch = 16, col = "red")
plot(samp_rand, add = TRUE, pch = 16, col = "green")
bel_pop_agg <- project(as.polygons(bel_pop_agg), "EPSG:3035")
# Random sampling can be sped up by using parallelization
# This only works for polygons
if (requireNamespace("future.apply")) {
wt_sample(bel_pop_agg, size = n, method = "random_parallel")
}
#> Geometry set for 36 features
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 3850320 ymin: 3030500 xmax: 4000022 ymax: 3141552
#> Projected CRS: ETRS89-extended / LAEA Europe
#> First 5 geometries:
#> POINT (3938234 3110710)
#> POINT (3936725 3109539)
#> POINT (3928676 3099564)
#> POINT (3932532 3106660)
#> POINT (3923066 3106341)
# ... or by using C++
wt_sample(bel_pop_agg, size = n, method = "random_cpp")
#> Geometry set for 36 features
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 3853743 ymin: 3039158 xmax: 4017302 ymax: 3138570
#> Projected CRS: ETRS89-extended / LAEA Europe
#> First 5 geometries:
#> POINT (3900729 3086620)
#> POINT (3893619 3077160)
#> POINT (3976659 3082146)
#> POINT (3930415 3123362)
#> POINT (3929091 3123687)
if (FALSE) { # \dontrun{
library(tidycensus)
co_pop <- get_decennial(
geography = "tract",
variables = "P1_001N",
state = "CO",
year = 2020,
geometry = TRUE
)
# The `area_weight` argument can be useful if polygon sizes are of
# drastically different sizes
co_unweighted <- wt_sample(co_pop["value"], size = 100, power = 0)
co_area_weighted <- wt_sample(co_pop["value"], size = 100, power = 0, area_weight = 1)
plot(st_geometry(co_pop))
plot(co_unweighted, pch = 16)
plot(co_area_weighted, pch = 16)} # }
