Currently, there are 9 functions associated with the
sample verb in the sgsR package:
| Algorithm | Description | Reference |
|---|---|---|
sample_srs() |
Simple random | |
sample_systematic() |
Systematic | |
sample_strat() |
Stratified | Queinnec, White, & Coops (2021) |
sample_sys_strat() |
Systematic Stratified | |
sample_nc() |
Nearest centroid | Melville & Stone (2016) |
sample_clhs() |
Conditioned Latin hypercube | Minasny & McBratney (2006) |
sample_balanced() |
Balanced sampling | Grafström, A. Lisic, J (2018) |
sample_ahels() |
Adapted hypercube evaluation of a legacy sample | Malone, Minasny, & Brungard (2019) |
sample_existing() |
Sub-sampling an existing sample |
sample_srsWe have demonstrated a simple example of using the
sample_srs() function in vignette("sgsR"). We
will demonstrate additional examples below.
raster
The input required for sample_srs() is a
raster. This means that sraster and
mraster are supported for this function.
#--- perform simple random sampling ---#
sample_srs(
raster = sraster, # input sraster
nSamp = 200, # number of desired sample units
plot = TRUE
) # plot#> Simple feature collection with 200 features and 0 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431170 ymin: 5337710 xmax: 438530 ymax: 5343210
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> geometry
#> 1 POINT (432830 5343190)
#> 2 POINT (435230 5342790)
#> 3 POINT (438030 5338250)
#> 4 POINT (437690 5341770)
#> 5 POINT (437970 5338970)
#> 6 POINT (434370 5341030)
#> 7 POINT (435570 5341310)
#> 8 POINT (435310 5340730)
#> 9 POINT (432850 5342730)
#> 10 POINT (438530 5341150)
sample_srs(
raster = mraster, # input mraster
nSamp = 200, # number of desired sample units
access = access, # define access road network
mindist = 200, # minimum distance sample units must be apart from one another
buff_inner = 50, # inner buffer - no sample units within this distance from road
buff_outer = 200, # outer buffer - no sample units further than this distance from road
plot = TRUE
) # plot#> Simple feature collection with 200 features and 0 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431150 ymin: 5337730 xmax: 438550 ymax: 5343230
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> geometry
#> 1 POINT (434750 5343070)
#> 2 POINT (435490 5341950)
#> 3 POINT (437750 5338690)
#> 4 POINT (433710 5340370)
#> 5 POINT (438330 5341150)
#> 6 POINT (432470 5340850)
#> 7 POINT (433430 5342250)
#> 8 POINT (431850 5338610)
#> 9 POINT (437170 5338050)
#> 10 POINT (435890 5342570)
sample_systematicThe sample_systematic() function applies systematic
sampling across an area with the cellsize parameter
defining the resolution of the tessellation. The tessellation shape can
be modified using the square parameter. Assigning
TRUE (default) to the square parameter results
in a regular grid and assigning FALSE results in a
hexagonal grid.
The location of sample units can also be adjusted using the
locations parameter, where centers takes the
center, corners takes all corners, and random
takes a random location within each tessellation. Random start points
and translations are applied when the function is called.
#--- perform grid sampling ---#
sample_systematic(
raster = sraster, # input sraster
cellsize = 1000, # grid distance
plot = TRUE
) # plot#> Simple feature collection with 38 features and 0 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431484.5 ymin: 5337778 xmax: 438510 ymax: 5343165
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> geometry
#> 1 POINT (432408.6 5338327)
#> 2 POINT (433376.2 5338074)
#> 3 POINT (434343.7 5337821)
#> 4 POINT (431693.8 5339547)
#> 5 POINT (432661.4 5339295)
#> 6 POINT (434596.4 5338789)
#> 7 POINT (435564 5338536)
#> 8 POINT (436531.5 5338284)
#> 9 POINT (437499 5338031)
#> 10 POINT (438466.6 5337778)
#--- perform grid sampling ---#
sample_systematic(
raster = sraster, # input sraster
cellsize = 500, # grid distance
square = FALSE, # hexagonal tessellation
location = "random", # randomly sample within tessellation
plot = TRUE
) # plot#> Simple feature collection with 174 features and 0 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431213.7 ymin: 5337728 xmax: 438559.7 ymax: 5343238
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> geometry
#> 1 POINT (438549.8 5342372)
#> 2 POINT (438504.2 5342656)
#> 3 POINT (438478 5342049)
#> 4 POINT (438276.9 5341076)
#> 5 POINT (438373.2 5340040)
#> 6 POINT (438559.7 5339515)
#> 7 POINT (438450.5 5338404)
#> 8 POINT (438520.5 5337742)
#> 9 POINT (438094.3 5342299)
#> 10 POINT (438275.8 5341303)
sample_systematic(
raster = sraster, # input sraster
cellsize = 500, # grid distance
access = access, # define access road network
buff_outer = 200, # outer buffer - no sample units further than this distance from road
square = FALSE, # hexagonal tessellation
location = "corners", # take corners instead of centers
plot = TRUE
)#> Simple feature collection with 631 features and 0 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431296.7 ymin: 5337762 xmax: 438559.5 ymax: 5343216
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> geometry
#> 1 POINT (431296.7 5340859)
#> 2 POINT (431388.7 5342589)
#> 3 POINT (431296.7 5340859)
#> 4 POINT (431538.7 5340702)
#> 5 POINT (431523.4 5340413)
#> 6 POINT (431388.7 5342589)
#> 7 POINT (431630.7 5342431)
#> 8 POINT (431673.3 5338526)
#> 9 POINT (431658 5338238)
#> 10 POINT (431523.4 5340413)
sample_stratThe sample_strat() contains two methods to
perform sampling:
"Queinnec" - Hierarchical sampling using a focal
window to isolate contiguous groups of stratum pixels, which was
originally developed by Martin Queinnec.
"random" - Traditional stratified random sampling.
This method ignores much of the functionality of the
algorithm to allow users the capability to use standard stratified
random sampling approaches without the use of a focal window to locate
contiguous stratum cells.
method = "Queinnec"Queinnec, M., White, J. C., & Coops, N. C. (2021). Comparing airborne and spaceborne photon-counting LiDAR canopy structural estimates across different boreal forest types. Remote Sensing of Environment, 262(August 2020), 112510.
This algorithm uses moving window (wrow and
wcol parameters) to filter the input sraster
to prioritize sample unit allocation to where stratum pixels are
spatially grouped, rather than dispersed individuals across the
landscape.
Sampling is performed using 2 rules:
Rule 1 - Sample within spatially grouped stratum
pixels. Moving window defined by wrow and
wcol.
Rule 2 - If no additional sample units exist to
satisfy desired sample size(nSamp), individual stratum
pixels are sampled.
The rule applied to a select each sample unit is defined in the
rule attribute of output samples. We give a few examples
below:
#--- perform stratified sampling random sampling ---#
sample_strat(
sraster = sraster, # input sraster
nSamp = 200
) # desired sample size # plot
#> Simple feature collection with 200 features and 3 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431170 ymin: 5337750 xmax: 438490 ymax: 5343210
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> strata type rule geometry
#> x 1 new rule1 POINT (434570 5342430)
#> x1 1 new rule1 POINT (438370 5339510)
#> x2 1 new rule1 POINT (433810 5341030)
#> x3 1 new rule1 POINT (438410 5338190)
#> x4 1 new rule1 POINT (435130 5342750)
#> x5 1 new rule1 POINT (437850 5343110)
#> x6 1 new rule1 POINT (433510 5341010)
#> x7 1 new rule1 POINT (435930 5342670)
#> x8 1 new rule1 POINT (435870 5342310)
#> x9 1 new rule1 POINT (434630 5341050)In some cases, users might want to include an existing
sample within the algorithm. In order to adjust the total number of
sample units needed per stratum to reflect those already present in
existing, we can use the intermediate function
extract_strata().
This function uses the sraster and existing
sample units and extracts the stratum for each. These sample units can
be included within sample_strat(), which adjusts total
sample units required per class based on representation in
existing.
#--- extract strata values to existing samples ---#
e.sr <- extract_strata(
sraster = sraster, # input sraster
existing = existing
) # existing samples to add strata value toTIP!
sample_strat() requires the sraster input
to have an attribute named strata and will give an error if
it doesn’t.
sample_strat(
sraster = sraster, # input sraster
nSamp = 200, # desired sample size
access = access, # define access road network
existing = e.sr, # existing sample with strata values
mindist = 200, # minimum distance sample units must be apart from one another
buff_inner = 50, # inner buffer - no sample units within this distance from road
buff_outer = 200, # outer buffer - no sample units further than this distance from road
plot = TRUE
) # plot#> Simple feature collection with 400 features and 3 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431190 ymin: 5337710 xmax: 438530 ymax: 5343230
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> strata type rule geometry
#> 1 1 existing existing POINT (437830 5341110)
#> 2 1 existing existing POINT (437250 5338030)
#> 3 1 existing existing POINT (435410 5342590)
#> 4 1 existing existing POINT (436090 5342370)
#> 5 1 existing existing POINT (433410 5340870)
#> 6 1 existing existing POINT (433810 5340570)
#> 7 1 existing existing POINT (437870 5343090)
#> 8 1 existing existing POINT (436570 5337730)
#> 9 1 existing existing POINT (437610 5339250)
#> 10 1 existing existing POINT (437830 5338010)
The code in the example above defined the mindist
parameter, which specifies the minimum euclidean distance that new
sample units must be apart from one another.
Notice that the sample units have type and
rule attributes which outline whether they are
existing or new, and whether
rule1 or rule2 were used to select them. If
type is existing (a user provided
existing sample), rule will be
existing as well as seen above.
sample_strat(
sraster = sraster, # input
nSamp = 200, # desired sample size
access = access, # define access road network
existing = e.sr, # existing samples with strata values
include = TRUE, # include existing sample in nSamp total
buff_outer = 200, # outer buffer - no samples further than this distance from road
plot = TRUE
) # plot#> Simple feature collection with 200 features and 3 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431190 ymin: 5337730 xmax: 438470 ymax: 5343210
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> strata type rule geometry
#> 1 1 existing existing POINT (437830 5341110)
#> 2 1 existing existing POINT (437250 5338030)
#> 3 1 existing existing POINT (435410 5342590)
#> 4 1 existing existing POINT (436090 5342370)
#> 5 1 existing existing POINT (433410 5340870)
#> 6 1 existing existing POINT (433810 5340570)
#> 7 1 existing existing POINT (437870 5343090)
#> 8 1 existing existing POINT (436570 5337730)
#> 9 1 existing existing POINT (437610 5339250)
#> 10 1 existing existing POINT (437830 5338010)
The include parameter determines whether
existing sample units should be included in the total
sample size defined by nSamp. By default, the
include parameter is set as FALSE.
method = "randomStratified random sampling with equal probability for all cells
(using default algorithm values for mindist and no use of
access functionality). In essence this method perform the
sample_srs algorithm for each stratum separately to meet
the specified sample size.
#--- perform stratified sampling random sampling ---#
sample_strat(
sraster = sraster, # input sraster
method = "random", # stratified random sampling
nSamp = 200, # desired sample size
plot = TRUE
) # plot#> Simple feature collection with 200 features and 2 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431110 ymin: 5337750 xmax: 438490 ymax: 5343230
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> strata type geometry
#> x 1 new POINT (434630 5342970)
#> x1 1 new POINT (437450 5339370)
#> x2 1 new POINT (432970 5343030)
#> x3 1 new POINT (434470 5341790)
#> x4 1 new POINT (436110 5342670)
#> x5 1 new POINT (435270 5342810)
#> x6 1 new POINT (435850 5342370)
#> x7 1 new POINT (437730 5342590)
#> x8 1 new POINT (433690 5341230)
#> x9 1 new POINT (434050 5341290)
sample_sys_stratsample_sys_strat() function implements systematic
stratified sampling on an sraster. This function uses the
same functionality as sample_systematic() but takes an
sraster as input and performs sampling on each stratum
iteratively.
#--- perform grid sampling on each stratum separately ---#
sample_sys_strat(
sraster = sraster, # input sraster with 4 strata
cellsize = 1000, # grid size
plot = TRUE # plot output
)
#> Warning: [readStart] source already open for reading
#> Processing strata : 1
#> Warning: [extract] source already open for reading
#> Processing strata : 2
#> Warning: [extract] source already open for reading
#> Processing strata : 3
#> Warning: [extract] source already open for reading
#> Processing strata : 4
#> Warning: [extract] source already open for reading#> Simple feature collection with 39 features and 1 field
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431100.9 ymin: 5337717 xmax: 438491.4 ymax: 5343157
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> strata geometry
#> 1 1 POINT (432259.4 5338109)
#> 2 1 POINT (432120.8 5340934)
#> 3 1 POINT (434343.5 5338919)
#> 4 1 POINT (435084.4 5338247)
#> 5 1 POINT (433533.3 5341003)
#> 6 1 POINT (435015.1 5339660)
#> 7 1 POINT (436496.9 5338317)
#> 8 1 POINT (437909.4 5338386)
#> 9 1 POINT (434135.6 5343157)
#> 10 1 POINT (435617.4 5341813)
Just like with sample_systematic() we can specify where
we want our samples to fall within our tessellations. We specify
location = "corners" below. Note that the tesselations are
all saved to a list file when details = TRUE should the
user want to save them.
sample_sys_strat(
sraster = sraster, # input sraster with 4 strata
cellsize = 500, # grid size
square = FALSE, # hexagon tessellation
location = "corners", # samples on tessellation corners
plot = TRUE # plot output
)
#> Processing strata : 1
#> Warning: [extract] source already open for reading
#> Processing strata : 2
#> Warning: [extract] source already open for reading
#> Processing strata : 3
#> Warning: [extract] source already open for reading
#> Processing strata : 4
#> Warning: [extract] source already open for reading#> Simple feature collection with 1188 features and 1 field
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431135.3 ymin: 5337702 xmax: 438542.8 ymax: 5343205
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> strata geometry
#> 1 1 POINT (432943.4 5343041)
#> 2 1 POINT (432943.4 5343041)
#> 3 1 POINT (433705.9 5342998)
#> 4 1 POINT (434261.3 5343155)
#> 5 1 POINT (432943.4 5343041)
#> 6 1 POINT (433705.9 5342998)
#> 7 1 POINT (434261.3 5343155)
#> 8 1 POINT (433913.1 5342797)
#> 9 1 POINT (433705.9 5342998)
#> 10 1 POINT (433705.9 5342998)
This sampling approach could be especially useful incombination with
strat_poly() to ensure consistency of sampling accross
specific management units.
#--- read polygon coverage ---#
poly <- system.file("extdata", "inventory_polygons.shp", package = "sgsR")
fri <- sf::st_read(poly)
#> Reading layer `inventory_polygons' from data source
#> `/tmp/RtmpZ425gb/Rinst1396490a568e/sgsR/extdata/inventory_polygons.shp'
#> using driver `ESRI Shapefile'
#> Simple feature collection with 632 features and 3 fields
#> Geometry type: MULTIPOLYGON
#> Dimension: XY
#> Bounding box: xmin: 431100 ymin: 5337700 xmax: 438560 ymax: 5343240
#> Projected CRS: UTM_Zone_17_Northern_Hemisphere
#--- stratify polygon coverage ---#
#--- specify polygon attribute to stratify ---#
attribute <- "NUTRIENTS"
#--- specify features within attribute & how they should be grouped ---#
#--- as a single vector ---#
features <- c("poor", "rich", "medium")
#--- get polygon stratification ---#
srasterpoly <- strat_poly(
poly = fri,
attribute = attribute,
features = features,
raster = sraster
)
#--- systematatic stratified sampling for each stratum ---#
sample_sys_strat(
sraster = srasterpoly, # input sraster from strat_poly() with 3 strata
cellsize = 500, # grid size
square = FALSE, # hexagon tessellation
location = "random", # randomize plot location
plot = TRUE # plot output
)
#> Processing strata : 1
#> Warning: [extract] source already open for reading
#> Processing strata : 2
#> Warning: [extract] source already open for reading
#> Processing strata : 3
#> Warning: [extract] source already open for reading
#> Simple feature collection with 171 features and 1 field
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431115.5 ymin: 5337781 xmax: 438559.6 ymax: 5343189
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> strata geometry
#> 1 1 POINT (438094.4 5342855)
#> 2 1 POINT (437724.1 5342565)
#> 3 1 POINT (437737.4 5342087)
#> 4 1 POINT (437585.2 5342509)
#> 5 1 POINT (437423.2 5341565)
#> 6 1 POINT (437905.9 5340732)
#> 7 1 POINT (436055.4 5342987)
#> 8 1 POINT (437973.3 5340321)
#> 9 1 POINT (438151.1 5339630)
#> 10 1 POINT (435715.2 5342890)sample_ncsample_nc() function implements the Nearest Centroid
sampling algorithm described in Melville &
Stone (2016). The algorithm uses kmeans clustering where the number
of clusters (centroids) is equal to the desired sample size
(nSamp).
Cluster centers are located, which then prompts the nearest neighbour
mraster pixel for each cluster to be selected (assuming
default k parameter). These nearest neighbours are the
output sample units.
#--- perform simple random sampling ---#
sample_nc(
mraster = mraster, # input
nSamp = 25, # desired sample size
plot = TRUE
)
#> K-means being performed on 3 layers with 25 centers.#> Simple feature collection with 25 features and 4 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431550 ymin: 5337810 xmax: 438450 ymax: 5343170
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> zq90 pzabove2 zsd kcenter geometry
#> 12742 12.60 52.0 3.53 1 POINT (432290 5342550)
#> 13536 15.40 89.8 3.65 2 POINT (433250 5342510)
#> 24800 4.63 31.9 1.05 3 POINT (434730 5341910)
#> 30328 6.92 13.4 1.84 4 POINT (433390 5341610)
#> 79890 15.70 95.3 2.77 5 POINT (432450 5338950)
#> 26025 19.60 67.6 5.90 6 POINT (436850 5341850)
#> 65511 16.60 65.2 4.60 7 POINT (435810 5339730)
#> 3753 18.50 85.0 5.19 8 POINT (431550 5343030)
#> 90994 11.00 17.3 3.17 9 POINT (438190 5338370)
#> 87961 6.12 58.2 1.42 10 POINT (437210 5338530)
Altering the k parameter leads to a multiplicative
increase in output sample units where total output samples = \(nSamp * k\).
#--- perform simple random sampling ---#
samples <- sample_nc(
mraster = mraster, # input
k = 2, # number of nearest neighbours to take for each kmeans center
nSamp = 25, # desired sample size
plot = TRUE
)
#> K-means being performed on 3 layers with 25 centers.Visualizing what the kmeans centers and sample units looks like is
possible when using details = TRUE. The $kplot
output provides a quick visualization of where the centers are based on
a scatter plot of the first 2 layers in mraster. Notice
that the centers are well distributed in covariate space and chosen
sample units are the closest pixels to each center (nearest
neighbours).
#--- perform simple random sampling with details ---#
details <- sample_nc(
mraster = mraster, # input
nSamp = 25, # desired sample number
details = TRUE
)
#> K-means being performed on 3 layers with 25 centers.
#--- plot ggplot output ---#
details$kplotsample_clhssample_clhs() function implements conditioned Latin
hypercube (clhs) sampling methodology from the clhs
package.
TIP!
A number of other functions in the sgsR package help to
provide guidance on clhs sampling including calculate_pop()
and calculate_lhsOpt(). Check out these functions to better
understand how sample numbers could be optimized.
The syntax for this function is similar to others shown above,
although parameters like iter, which define the number of
iterations within the Metropolis-Hastings process are important to
consider. In these examples we use a low iter value for
efficiency. Default values for iter within the
clhs package are 10,000.
sample_clhs(
mraster = mraster, # input
nSamp = 200, # desired sample size
plot = TRUE, # plot
iter = 100
) # number of iterationsThe cost parameter defines the mraster
covariate, which is used to constrain the clhs sampling. An example
could be the distance a pixel is from road access
(e.g. from calculate_distance() see example below), terrain
slope, the output from calculate_coobs(), or many
others.
#--- cost constrained examples ---#
#--- calculate distance to access layer for each pixel in mr ---#
mr.c <- calculate_distance(
raster = mraster, # input
access = access, # define access road network
plot = TRUE
) # plotsample_clhs(
mraster = mr.c, # input
nSamp = 250, # desired sample size
iter = 100, # number of iterations
cost = "dist2access", # cost parameter - name defined in calculate_distance()
plot = TRUE
) # plotsample_balancedThe sample_balanced() algorithm performs a balanced
sampling methodology from the stratifyR / SamplingBigData
packages.
#> Simple feature collection with 200 features and 0 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431110 ymin: 5337810 xmax: 438530 ymax: 5343210
#> Projected CRS: +proj=utm +zone=17 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
#> First 10 features:
#> geometry
#> 1 POINT (435930 5343210)
#> 2 POINT (434770 5343190)
#> 3 POINT (431610 5343130)
#> 4 POINT (431550 5343110)
#> 5 POINT (431870 5343110)
#> 6 POINT (433650 5343110)
#> 7 POINT (431590 5343070)
#> 8 POINT (431790 5343050)
#> 9 POINT (438090 5343010)
#> 10 POINT (432210 5342970)
sample_balanced(
mraster = mraster, # input
nSamp = 100, # desired sample size
algorithm = "lcube", # algorithm type
access = access, # define access road network
buff_inner = 50, # inner buffer - no sample units within this distance from road
buff_outer = 200
) # outer buffer - no sample units further than this distance from road
#> Simple feature collection with 100 features and 0 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431530 ymin: 5337710 xmax: 438430 ymax: 5343230
#> Projected CRS: +proj=utm +zone=17 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
#> First 10 features:
#> geometry
#> 1 POINT (435310 5343230)
#> 2 POINT (431850 5343170)
#> 3 POINT (433090 5343050)
#> 4 POINT (435410 5343050)
#> 5 POINT (432410 5343030)
#> 6 POINT (434670 5342970)
#> 7 POINT (438010 5342970)
#> 8 POINT (435550 5342930)
#> 9 POINT (437910 5342910)
#> 10 POINT (432190 5342890)sample_ahelsThe sample_ahels() function performs the adapted
Hypercube Evaluation of a Legacy Sample (ahels) algorithm
usingexisting sample data and an mraster. New
sample units are allocated based on quantile ratios between the
existing sample and mraster covariate
dataset.
This algorithm was adapted from that presented in the paper below, which we highly recommend.
Malone BP, Minansy B, Brungard C. 2019. Some methods to improve the utility of conditioned Latin hypercube sampling. PeerJ 7:e6451 DOI 10.7717/peerj.6451
This algorithm:
Determines the quantile distributions of existing
sample units and mraster covariates.
Determines quantiles where there is a disparity between sample units and covariates.
Prioritizes sampling within those quantile to improve representation.
To use this function, user must first specify the number of quantiles
(nQuant) followed by either the nSamp (total
number of desired sample units to be added) or the
threshold (sampling ratio vs. covariate coverage ratio for
quantiles - default is 0.9) parameters.
#--- remove `type` variable from existing - causes plotting issues ---#
existing <- existing %>% select(-type)
sample_ahels(
mraster = mraster,
existing = existing, # existing sample
plot = TRUE
) # plot#> Simple feature collection with 287 features and 7 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431110 ymin: 5337730 xmax: 438470 ymax: 5343230
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> type.x zq90 pzabove2 zsd strata type.y rule geometry
#> 1 existing 5.77 54.1 1.31 1 new rule1 POINT (437830 5341110)
#> 2 existing 8.16 83.7 1.73 1 new rule1 POINT (437250 5338030)
#> 3 existing 3.64 43.7 0.68 1 new rule1 POINT (435410 5342590)
#> 4 existing 6.08 45.4 1.49 1 new rule1 POINT (436090 5342370)
#> 5 existing 3.28 7.4 0.61 1 new rule1 POINT (433410 5340870)
#> 6 existing 2.88 4.7 0.47 1 new rule1 POINT (433810 5340570)
#> 7 existing 2.31 0.4 0.32 1 new rule1 POINT (437870 5343090)
#> 8 existing 8.51 46.0 2.22 1 new rule1 POINT (436570 5337730)
#> 9 existing 3.51 10.4 0.66 1 new rule1 POINT (437610 5339250)
#> 10 existing 6.38 3.9 1.49 1 new rule1 POINT (437830 5338010)
TIP!
Notice that no threshold, nSamp, or
nQuant were defined. That is because the default setting
for threshold = 0.9 and nQuant = 10.
The first matrix output shows the quantile ratios between the sample and the covariates. A value of 1.0 indicates that the sample is representative of quantile coverage. Values > 1.0 indicate over representation of sample units, while < 1.0 indicate under representation.
sample_ahels(
mraster = mraster,
existing = existing, # existing sample
nQuant = 20, # define 20 quantiles
nSamp = 300
) # desired sample size#> Simple feature collection with 500 features and 7 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431130 ymin: 5337710 xmax: 438550 ymax: 5343230
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> type.x zq90 pzabove2 zsd strata type.y rule geometry
#> 1 existing 5.77 54.1 1.31 1 new rule1 POINT (437830 5341110)
#> 2 existing 8.16 83.7 1.73 1 new rule1 POINT (437250 5338030)
#> 3 existing 3.64 43.7 0.68 1 new rule1 POINT (435410 5342590)
#> 4 existing 6.08 45.4 1.49 1 new rule1 POINT (436090 5342370)
#> 5 existing 3.28 7.4 0.61 1 new rule1 POINT (433410 5340870)
#> 6 existing 2.88 4.7 0.47 1 new rule1 POINT (433810 5340570)
#> 7 existing 2.31 0.4 0.32 1 new rule1 POINT (437870 5343090)
#> 8 existing 8.51 46.0 2.22 1 new rule1 POINT (436570 5337730)
#> 9 existing 3.51 10.4 0.66 1 new rule1 POINT (437610 5339250)
#> 10 existing 6.38 3.9 1.49 1 new rule1 POINT (437830 5338010)
Notice that the total number of samples is 500. This value is the sum
of existing units (200) and number of sample units defined by
nSamp = 300.
sample_existingAcknowledging that existing sample networks are common
is important. There is significant investment into these samples, and in
order to keep inventories up-to-date, we often need to collect new data
for sample units. The sample_existing algorithm provides
the user with methods for sub-sampling an existing sample
network should the financial / logistical resources not be available to
collect data at all sample units. The functions allows users to choose
between algorithm types using (type = "clhs" - default,
type = "balanced", type = "srs",
type = "strat"). Differences in type result in calling
internal sample_existing_*() functions
(sample_existing_clhs() (default),
sample_existing_balanced(),
sample_existing_srs(),
sample_existing_strat()). These functions are not exported
to be used stand-alone, however they employ the same functionality as
their sample_clhs() etc counterparts.
While using sample_existing(), should the user wish to
specify algorithm specific parameters
(e.g. algorithm = "lcube" in sample_balanced()
or allocation = "equal" in sample_strat()),
they can specify within sample_existing() as if calling the
function directly.
I give applied examples for all methods below that are based on the following scenario:
We have a systematic sample where sample units are 200m apart.
We know we only have resources to sample 300 of them.
We have some ALS data available (mraster), which we
can use to improve knowledge of the metric populations.
See our existing sample for the scenario below.
#--- generate existing samples and extract metrics ---#
existing <- sample_systematic(raster = mraster, cellsize = 200, plot = TRUE)sample_existing(type = "clhs")The algorithm is unique in that it has two fundamental approaches:
existing and the attributes it
contains.#--- sub sample using ---#
sample_existing(existing = e, nSamp = 300, type = "clhs")
#> Simple feature collection with 300 features and 3 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431124.3 ymin: 5337724 xmax: 438555.2 ymax: 5343191
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> zq90 pzabove2 zsd geometry
#> 457 19.40 94.7 4.31 POINT (434436.9 5339880)
#> 790 21.60 89.7 5.84 POINT (438108 5341391)
#> 840 12.50 97.7 2.75 POINT (437026.9 5338353)
#> 526 13.10 81.8 3.68 POINT (435871.9 5341397)
#> 554 23.30 85.9 6.53 POINT (436140.4 5341486)
#> 656 9.27 6.6 2.40 POINT (435327.9 5338536)
#> 593 20.00 69.7 6.07 POINT (435420.1 5339609)
#> 187 3.13 15.6 0.58 POINT (434087.6 5343190)
#> 616 18.10 77.5 5.29 POINT (436048.3 5340413)
#> 321 17.30 66.1 5.05 POINT (433453.7 5340151)raster distributionsOur systematic sample of ~900 plots is fairly comprehensive, however
we can generate a true population distribution through the inclusion of
the ALS metrics in the sampling process. The metrics will be included in
internal latin hypercube sampling to help guide sub-sampling of
existing.
#--- sub sample using ---#
sample_existing(
existing = existing, # our existing sample
nSamp = 300, # desired sample size
raster = mraster, # include mraster metrics to guide sampling of existing
plot = TRUE
) # plot
#> Simple feature collection with 300 features and 3 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431125.5 ymin: 5337726 xmax: 438554 ymax: 5343197
#> Projected CRS: +proj=utm +zone=17 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
#> First 10 features:
#> zq90 pzabove2 zsd geometry
#> 91350 11.50 70.800003 3.28 POINT (432202 5340333)
#> 91505 2.96 8.400001 0.53 POINT (434442.6 5342116)
#> 91631 24.40 92.900002 4.98 POINT (434258.3 5339970)
#> 91811 18.10 77.500000 5.29 POINT (436048.3 5340413)
#> 91890 2.63 3.500000 0.51 POINT (437752.9 5342465)
#> 91626 14.20 90.000000 3.23 POINT (435157.3 5341756)
#> 91876 8.81 43.400002 2.40 POINT (435956.1 5339339)
#> 91445 19.50 93.000000 2.92 POINT (433905.5 5341939)
#> 92068 11.80 81.300003 2.87 POINT (437384.2 5338173)
#> 91529 12.70 95.500000 2.96 POINT (435070.8 5342919)The sample distribution again mimics the population distribution quite well! Now lets try using a cost variable to constrain the sub-sample.
#--- create distance from roads metric ---#
dist <- calculate_distance(raster = mraster, access = access)#--- sub sample using ---#
sample_existing(
existing = existing, # our existing sample
nSamp = 300, # desired sample size
raster = dist, # include mraster metrics to guide sampling of existing
cost = 4, # either provide the index (band number) or the name of the cost layer
plot = TRUE
) # plot
#> Simple feature collection with 300 features and 4 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431127.8 ymin: 5337728 xmax: 438554 ymax: 5343194
#> Projected CRS: +proj=utm +zone=17 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
#> First 10 features:
#> zq90 pzabove2 zsd dist2access geometry
#> 91709 4.17 7.7 0.90 58.393480 POINT (434434.6 5338986)
#> 91363 13.30 91.7 2.95 33.625379 POINT (433369.6 5342208)
#> 91399 16.00 59.3 5.32 5.079995 POINT (432559.3 5340153)
#> 91453 13.80 80.0 2.97 428.703683 POINT (433186.3 5340509)
#> 91791 2.18 0.4 0.28 19.278584 POINT (435150.4 5339073)
#> 91844 20.80 65.6 6.48 100.047996 POINT (436137 5340144)
#> 92082 9.66 87.0 2.31 142.899143 POINT (437562.8 5338083)
#> 91276 18.70 89.5 5.03 102.821643 POINT (432295.3 5341853)
#> 92020 9.00 75.5 2.11 202.311298 POINT (436488.6 5337728)
#> 91205 0.00 0.0 0.00 371.489332 POINT (431133.5 5342214)Finally, should the user wish to further constrain the sample based
on access like other sampling approaches in
sgsR that is also possible.
#--- ensure access and existing are in the same CRS ---#
sf::st_crs(existing) <- sf::st_crs(access)
#--- sub sample using ---#
sample_existing(
existing = existing, # our existing sample
nSamp = 300, # desired sample size
raster = dist, # include mraster metrics to guide sampling of existing
cost = 4, # either provide the index (band number) or the name of the cost layer
access = access, # roads layer
buff_inner = 50, # inner buffer - no sample units within this distance from road
buff_outer = 300, # outer buffer - no sample units further than this distance from road
plot = TRUE
) # plot
#> Simple feature collection with 300 features and 4 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431130.1 ymin: 5337727 xmax: 438548.3 ymax: 5343193
#> Projected CRS: +proj=utm +zone=17 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
#> First 10 features:
#> zq90 pzabove2 zsd dist2access geometry
#> 91551 16.40 88.0 3.15 118.73293 POINT (437034.9 5341483)
#> 91281 9.91 70.2 2.58 65.89128 POINT (433997.7 5343012)
#> 91642 2.71 17.4 0.44 61.56608 POINT (437922.4 5338798)
#> 91373 6.02 75.5 1.36 72.46007 POINT (434711.2 5342205)
#> 91394 13.20 49.5 3.76 125.46901 POINT (434350.5 5341043)
#> 91353 12.80 73.4 3.04 60.62854 POINT (434712.3 5342652)
#> 91293 19.50 94.8 3.18 56.90434 POINT (432649.2 5340332)
#> 91383 12.60 90.9 2.56 279.17631 POINT (433182.9 5339168)
#> 91523 7.22 21.8 2.28 74.83604 POINT (435239.2 5338805)
#> 91290 18.80 69.8 5.80 287.98527 POINT (433008.8 5341046)TIP!
The greater constraints we add to sampling, the less likely we will have strong correlations between the population and sample, so its always important to understand these limitations and plan accordingly.
sample_existing(type = "balanced")When type = "balanced" users can define all parameters
that are found within sample_balanced(). This means that
one can change the algorithm, p etc.
sample_existing(existing = e, nSamp = 300, type = "balanced")
#> Simple feature collection with 300 features and 3 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431130.1 ymin: 5337730 xmax: 438559.7 ymax: 5343197
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> zq90 pzabove2 zsd geometry
#> 1 19.50 77.0 5.90 POINT (431135.8 5343108)
#> 2 17.40 92.3 2.30 POINT (431404.4 5343197)
#> 3 18.80 88.8 4.82 POINT (431314.5 5343019)
#> 13 21.20 80.6 6.03 POINT (431671.8 5342839)
#> 15 16.10 93.5 2.24 POINT (431402.1 5342303)
#> 22 8.55 59.3 2.28 POINT (431580.7 5342213)
#> 23 14.30 76.3 3.61 POINT (431490.8 5342034)
#> 24 13.60 82.8 3.86 POINT (431400.9 5341856)
#> 25 11.40 46.6 3.25 POINT (431311 5341677)
#> 28 16.20 79.6 3.78 POINT (432029.1 5342659)sample_existing(existing = e, nSamp = 300, type = "balanced", algorithm = "lcube")
#> Simple feature collection with 300 features and 3 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431124.3 ymin: 5337724 xmax: 438557.5 ymax: 5343193
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> zq90 pzabove2 zsd geometry
#> 1 19.5 77.0 5.90 POINT (431135.8 5343108)
#> 4 19.7 81.2 6.20 POINT (431224.6 5342840)
#> 6 16.9 85.1 4.02 POINT (431583 5343107)
#> 14 20.7 85.9 4.66 POINT (431581.9 5342660)
#> 19 19.2 88.5 4.18 POINT (431850.4 5342749)
#> 23 14.3 76.3 3.61 POINT (431490.8 5342034)
#> 24 13.6 82.8 3.86 POINT (431400.9 5341856)
#> 26 16.3 68.4 4.03 POINT (432208.9 5343016)
#> 27 13.1 66.1 3.13 POINT (432119 5342838)
#> 36 17.9 76.7 5.16 POINT (431309.9 5341230)sample_existing(type = "srs")The simplest, type = srs, randomly selects sample
units.
sample_existing(existing = e, nSamp = 300, type = "srs")
#> Simple feature collection with 300 features and 3 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431122.1 ymin: 5337724 xmax: 438550.6 ymax: 5343190
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> zq90 pzabove2 zsd geometry
#> 1 5.11 22.6 1.19 POINT (433010 5341494)
#> 2 12.80 73.4 3.04 POINT (434712.3 5342652)
#> 3 14.80 87.0 3.41 POINT (438201.3 5342911)
#> 4 16.50 94.9 3.37 POINT (433902.1 5340597)
#> 5 10.70 46.1 3.11 POINT (435515.7 5342024)
#> 6 11.90 21.9 3.61 POINT (435243.7 5340594)
#> 7 14.00 94.2 3.24 POINT (433537.9 5338093)
#> 8 27.00 90.3 7.19 POINT (433269.4 5338005)
#> 9 14.20 71.1 3.78 POINT (438291.2 5343090)
#> 10 16.40 95.3 3.61 POINT (438464.1 5340764)sample_existing(type = "strat")When type = "strat", existing must have an
attribute named strata (just like how
sample_strat() requires a strata layer). If it
doesnt exist you will get an error. Lets define an sraster
so that we are compliant.
sraster <- strat_kmeans(mraster = mraster, nStrata = 4)
e_strata <- extract_strata(sraster = sraster, existing = e)When we do have a strata attribute, the function works very much the
same as sample_strat() in that is allows the user to define
the allocation method ("prop" - defaults,
"optim", "manual", "equal").
#--- proportional stratified sampling of existing ---#
sample_existing(existing = e_strata, nSamp = 300, type = "strat", allocation = "prop")
#> Simple feature collection with 301 features and 4 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431123.2 ymin: 5337726 xmax: 438555.2 ymax: 5343194
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> strata zq90 pzabove2 zsd geometry
#> 1 3 24.9 92.8 6.17 POINT (432560.5 5340600)
#> 2 3 19.2 80.8 6.02 POINT (431403.2 5342750)
#> 3 3 22.1 88.3 4.78 POINT (432739.1 5340510)
#> 4 3 21.6 89.7 5.84 POINT (438108 5341391)
#> 5 3 22.2 89.2 5.92 POINT (438555.2 5341390)
#> 6 3 19.2 90.6 5.00 POINT (431669.5 5341944)
#> 7 3 17.0 57.1 5.70 POINT (434529.1 5340953)
#> 8 3 19.2 95.6 5.15 POINT (432914.3 5339079)
#> 9 3 20.3 89.1 5.43 POINT (431128.9 5340425)
#> 10 3 19.4 59.4 6.17 POINT (433819.1 5343102)TIP!
Remember that when allocation = "equal", the
nSamp value will be allocated for each strata.
We get 400 sample units in our output below because we have 4 strata
and nSamp = 100.
#--- equal stratified sampling of existing ---#
sample_existing(existing = e_strata, nSamp = 100, type = "strat", allocation = "equal")
#> Simple feature collection with 400 features and 4 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431125.5 ymin: 5337726 xmax: 438559.7 ymax: 5343197
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> strata zq90 pzabove2 zsd geometry
#> 1 3 20.4 93.2 5.98 POINT (432016.5 5337740)
#> 2 3 27.3 92.2 8.30 POINT (433271.6 5338899)
#> 3 3 16.5 45.6 4.86 POINT (437394.5 5342198)
#> 4 3 22.0 91.7 6.23 POINT (433806.5 5338182)
#> 5 3 18.8 90.9 5.01 POINT (433632.4 5340061)
#> 6 3 21.9 94.7 7.45 POINT (437214.7 5341841)
#> 7 3 24.9 52.5 7.90 POINT (437396.8 5343092)
#> 8 3 17.9 76.7 5.16 POINT (431309.9 5341230)
#> 9 3 20.8 94.6 6.06 POINT (431664.9 5340155)
#> 10 3 19.2 80.8 6.02 POINT (431403.2 5342750)#--- manual stratified sampling of existing with user defined weights ---#
s <- sample_existing(existing = e_strata, nSamp = 100, type = "strat", allocation = "manual", weights = c(0.2, 0.6, 0.1, 0.1))We can check the proportion of samples from each strata with:
Finally, type = "optim allows for the user to define a
raster metric to be used to optimize within strata
variances.
#--- manual stratified sampling of existing with user defined weights ---#
sample_existing(existing = e_strata, nSamp = 100, type = "strat", allocation = "optim", raster = mraster, metric = "zq90")
#> Simple feature collection with 100 features and 4 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 431127.8 ymin: 5337735 xmax: 438554 ymax: 5343191
#> Projected CRS: UTM Zone 17, Northern Hemisphere
#> First 10 features:
#> strata zq90 pzabove2 zsd geometry
#> 1 3 20.0 92.8 4.64 POINT (435780.8 5340771)
#> 2 3 18.7 89.5 5.03 POINT (432295.3 5341853)
#> 3 3 20.9 80.8 6.66 POINT (435783.1 5341665)
#> 4 3 21.7 86.5 6.73 POINT (437478.6 5340141)
#> 5 3 21.7 86.3 4.52 POINT (436405.6 5340233)
#> 6 3 20.5 78.0 6.36 POINT (436765.2 5340947)
#> 7 3 17.1 66.4 5.73 POINT (437480.9 5341035)
#> 8 3 19.2 95.6 5.15 POINT (432914.3 5339079)
#> 9 3 20.4 91.9 4.69 POINT (435331.3 5339878)
#> 10 3 21.8 85.7 6.29 POINT (431844.7 5340513)We see from the output that we get 300 sample units that are a
sub-sample of existing. The plotted output shows cumulative
frequency distributions of the population (all existing
samples) and the sub-sample (the 300 samples we requested).