# Sampling

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_srs`

We 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: 431130 ymin: 5337770 xmax: 438550 ymax: 5343230
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>                  geometry
    #> 1  POINT (432650 5337810)
    #> 2  POINT (432170 5342870)
    #> 3  POINT (436370 5340790)
    #> 4  POINT (433550 5342290)
    #> 5  POINT (431230 5338390)
    #> 6  POINT (432810 5341270)
    #> 7  POINT (435150 5341590)
    #> 8  POINT (432150 5340030)
    #> 9  POINT (437170 5340470)
    #> 10 POINT (435510 5342230)

    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: 431170 ymin: 5337730 xmax: 438550 ymax: 5343230
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>                  geometry
    #> 1  POINT (433310 5341470)
    #> 2  POINT (433850 5340290)
    #> 3  POINT (432090 5342750)
    #> 4  POINT (433610 5340590)
    #> 5  POINT (435390 5342870)
    #> 6  POINT (437150 5341470)
    #> 7  POINT (438130 5340010)
    #> 8  POINT (438390 5338250)
    #> 9  POINT (434730 5338870)
    #> 10 POINT (433550 5342970)

## `sample_systematic`

The `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 36 features and 0 fields
    #> Geometry type: POINT
    #> Dimension:     XY
    #> Bounding box:  xmin: 431264.3 ymin: 5337701 xmax: 438503.6 ymax: 5343142
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>                    geometry
    #> 1  POINT (431264.3 5341941)
    #> 2  POINT (431435.9 5340956)
    #> 3  POINT (431607.4 5339971)
    #> 4  POINT (431950.4 5338000)
    #> 5    POINT (432078 5343098)
    #> 6  POINT (432249.5 5342112)
    #> 7    POINT (432421 5341127)
    #> 8  POINT (432592.6 5340142)
    #> 9  POINT (432764.1 5339157)
    #> 10 POINT (432935.6 5338172)

    #--- 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 175 features and 0 fields
    #> Geometry type: POINT
    #> Dimension:     XY
    #> Bounding box:  xmin: 431110.1 ymin: 5337763 xmax: 438525.7 ymax: 5343237
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>                    geometry
    #> 1  POINT (431465.6 5337820)
    #> 2  POINT (431246.7 5338754)
    #> 3  POINT (431120.5 5339520)
    #> 4  POINT (431609.6 5338443)
    #> 5  POINT (431374.2 5339918)
    #> 6  POINT (431889.8 5338178)
    #> 7  POINT (431365.8 5339720)
    #> 8  POINT (431322.5 5340593)
    #> 9  POINT (431420.5 5341324)
    #> 10 POINT (431110.1 5342267)

    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 624 features and 0 fields
    #> Geometry type: POINT
    #> Dimension:     XY
    #> Bounding box:  xmin: 431268.1 ymin: 5337768 xmax: 438550.4 ymax: 5343230
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>                    geometry
    #> 1  POINT (438202.6 5337861)
    #> 2  POINT (438396.2 5338075)
    #> 3  POINT (438396.2 5338075)
    #> 4  POINT (438307.6 5338350)
    #> 5  POINT (438501.2 5338564)
    #> 6  POINT (438202.6 5337861)
    #> 7  POINT (437920.4 5337921)
    #> 8  POINT (438202.6 5337861)
    #> 9  POINT (438501.2 5338564)
    #> 10 POINT (438412.6 5338839)

## `sample_strat`

The `sample_strat()` contains two `method`s 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: 431130 ymin: 5337750 xmax: 438490 ymax: 5343130
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>    strata type  rule               geometry
    #> x       1  new rule1 POINT (436870 5339290)
    #> x1      1  new rule1 POINT (437650 5338370)
    #> x2      1  new rule1 POINT (437670 5343130)
    #> x3      1  new rule1 POINT (437030 5337930)
    #> x4      1  new rule1 POINT (433910 5342970)
    #> x5      1  new rule1 POINT (436590 5339250)
    #> x6      1  new rule1 POINT (437950 5340250)
    #> x7      1  new rule1 POINT (432830 5343070)
    #> x8      1  new rule1 POINT (435550 5338950)
    #> x9      1  new rule1 POINT (438370 5338230)

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 to

TIP!

`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: 431150 ymin: 5337730 xmax: 438530 ymax: 5343210
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>    strata     type     rule               geometry
    #> 1       1 existing existing POINT (433370 5341630)
    #> 2       1 existing existing POINT (438510 5339270)
    #> 3       1 existing existing POINT (435530 5342670)
    #> 4       1 existing existing POINT (434530 5342330)
    #> 5       1 existing existing POINT (435470 5342090)
    #> 6       1 existing existing POINT (434290 5343150)
    #> 7       1 existing existing POINT (438050 5341110)
    #> 8       1 existing existing POINT (433350 5341410)
    #> 9       1 existing existing POINT (433790 5340590)
    #> 10      1 existing existing POINT (437790 5343130)

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: 431150 ymin: 5337810 xmax: 438530 ymax: 5343210
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>    strata     type     rule               geometry
    #> 1       1 existing existing POINT (433370 5341630)
    #> 2       1 existing existing POINT (438510 5339270)
    #> 3       1 existing existing POINT (435530 5342670)
    #> 4       1 existing existing POINT (434530 5342330)
    #> 5       1 existing existing POINT (435470 5342090)
    #> 6       1 existing existing POINT (434290 5343150)
    #> 7       1 existing existing POINT (438050 5341110)
    #> 8       1 existing existing POINT (433350 5341410)
    #> 9       1 existing existing POINT (433790 5340590)
    #> 10      1 existing existing POINT (437790 5343130)

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 = "random`

Stratified 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: 431150 ymin: 5337710 xmax: 438550 ymax: 5343190
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>    strata type               geometry
    #> x       1  new POINT (434710 5340070)
    #> x1      1  new POINT (437830 5339630)
    #> x2      1  new POINT (436630 5339430)
    #> x3      1  new POINT (434770 5341590)
    #> x4      1  new POINT (433550 5341090)
    #> x5      1  new POINT (434130 5340850)
    #> x6      1  new POINT (434310 5341550)
    #> x7      1  new POINT (434730 5341150)
    #> x8      1  new POINT (432050 5340790)
    #> x9      1  new POINT (437570 5343170)

## `sample_sys_strat`

`sample_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 37 features and 1 field
    #> Geometry type: POINT
    #> Dimension:     XY
    #> Bounding box:  xmin: 431252.5 ymin: 5337713 xmax: 438052.6 ymax: 5343148
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>    strata                 geometry
    #> 1       1 POINT (436542.3 5337962)
    #> 2       1 POINT (437468.2 5338340)
    #> 3       1 POINT (438016.6 5339643)
    #> 4       1   POINT (432254 5340533)
    #> 5       1   POINT (433180 5340911)
    #> 6       1   POINT (434106 5341288)
    #> 7       1 POINT (435031.9 5341666)
    #> 8       1 POINT (435957.9 5342043)
    #> 9       1 POINT (437809.9 5342799)
    #> 10      1 POINT (432802.4 5341837)

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 1085 features and 1 field
    #> Geometry type: POINT
    #> Dimension:     XY
    #> Bounding box:  xmin: 431113.6 ymin: 5337702 xmax: 438527.9 ymax: 5343231
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>    strata                 geometry
    #> 1       1 POINT (437824.9 5337916)
    #> 2       1 POINT (436985.7 5337702)
    #> 3       1 POINT (437824.9 5337916)
    #> 4       1   POINT (437903 5338194)
    #> 5       1 POINT (438182.7 5338265)
    #> 6       1 POINT (436985.7 5337702)
    #> 7       1 POINT (437063.8 5337980)
    #> 8       1 POINT (437343.6 5338051)
    #> 9       1 POINT (438182.7 5338265)
    #> 10      1 POINT (438260.8 5338543)

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
    #>   `C:\Users\goodb\AppData\Local\Temp\Rtmp8iA5Id\Rinst214c547c7592\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: 431153.4 ymin: 5337757 xmax: 438529.6 ymax: 5343217
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>    strata                 geometry
    #> 1       1 POINT (438040.9 5342867)
    #> 2       1 POINT (438316.1 5342475)
    #> 3       1 POINT (435351.4 5343001)
    #> 4       1 POINT (437757.9 5342450)
    #> 5       1 POINT (433968.3 5343217)
    #> 6       1 POINT (434954.7 5342911)
    #> 7       1 POINT (435640.5 5342568)
    #> 8       1 POINT (437946.7 5342078)
    #> 9       1 POINT (433513.3 5343023)
    #> 10      1   POINT (435005 5342534)

## `sample_nc`

`sample_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: 431150 ymin: 5338110 xmax: 438510 ymax: 5343190
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>        zq90 pzabove2  zsd kcenter               geometry
    #> 57393 26.50     85.7 8.38       1 POINT (437570 5340170)
    #> 34611 16.10     73.6 4.25       2 POINT (436990 5341390)
    #> 67385  8.54     40.4 2.25       3 POINT (435990 5339630)
    #> 89570 18.50     86.2 5.09       4 POINT (432090 5338430)
    #> 35122 11.90     89.6 2.73       5 POINT (432290 5341350)
    #> 92977 13.10     72.9 3.39       6 POINT (433090 5338250)
    #> 37981 19.80     92.2 4.25       7 POINT (437250 5341210)
    #> 66397 17.80     93.3 3.44       8 POINT (431150 5339670)
    #> 23870 14.60     88.4 3.51       9 POINT (438510 5341970)
    #> 57357 15.00     49.2 4.32      10 POINT (436850 5340170)

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.

    #--- total samples = nSamp * k (25 * 2) = 50 ---#
    nrow(samples)
    #> [1] 50

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$kplot

## `sample_clhs`

`sample_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 iterations

The `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
    ) # plot
    #>
    |---------|---------|---------|---------|
    =========================================

    sample_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
    ) # plot

## `sample_balanced`

The `sample_balanced()` algorithm performs a balanced sampling methodology from the `stratifyR / SamplingBigData` packages.

    sample_balanced(
      mraster = mraster, # input
      nSamp = 200, # desired sample size
      plot = TRUE
    ) # plot

    #> Simple feature collection with 200 features and 0 fields
    #> Geometry type: POINT
    #> Dimension:     XY
    #> Bounding box:  xmin: 431150 ymin: 5337750 xmax: 438530 ymax: 5343230
    #> Projected CRS: +proj=utm +zone=17 +ellps=GRS80 +units=m +no_defs
    #> First 10 features:
    #>                  geometry
    #> 1  POINT (431190 5343230)
    #> 2  POINT (435750 5343210)
    #> 3  POINT (435790 5343190)
    #> 4  POINT (438270 5343150)
    #> 5  POINT (437450 5343130)
    #> 6  POINT (431910 5343090)
    #> 7  POINT (432530 5343090)
    #> 8  POINT (437410 5343090)
    #> 9  POINT (434990 5343050)
    #> 10 POINT (436550 5343030)

    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: 431270 ymin: 5337750 xmax: 438450 ymax: 5343230
    #> Projected CRS: +proj=utm +zone=17 +ellps=GRS80 +units=m +no_defs
    #> First 10 features:
    #>                  geometry
    #> 1  POINT (435290 5343230)
    #> 2  POINT (432510 5343090)
    #> 3  POINT (437710 5343070)
    #> 4  POINT (432890 5343030)
    #> 5  POINT (436170 5342990)
    #> 6  POINT (434130 5342930)
    #> 7  POINT (436090 5342830)
    #> 8  POINT (437450 5342810)
    #> 9  POINT (431270 5342690)
    #> 10 POINT (431910 5342670)

## `sample_ahels`

The `sample_ahels()` function performs the adapted Hypercube Evaluation of a Legacy Sample (ahels) algorithm using`existing` 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:

1. Determines the quantile distributions of `existing` sample units and `mraster` covariates.

2. Determines quantiles where there is a disparity between sample units and covariates.

3. 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 425 features and 7 fields
    #> Geometry type: POINT
    #> Dimension:     XY
    #> Bounding box:  xmin: 431130 ymin: 5337730 xmax: 438530 ymax: 5343230
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>      type.x zq90 pzabove2  zsd strata type.y  rule               geometry
    #> 1  existing 8.65     27.0 2.25      1    new rule1 POINT (433370 5341630)
    #> 2  existing 4.28      7.8 0.98      1    new rule1 POINT (438510 5339270)
    #> 3  existing 4.76     39.3 1.02      1    new rule1 POINT (435530 5342670)
    #> 4  existing 3.97     36.5 0.78      1    new rule1 POINT (434530 5342330)
    #> 5  existing 3.41     11.6 0.73      1    new rule1 POINT (435470 5342090)
    #> 6  existing 6.84     82.2 1.37      1    new rule1 POINT (434290 5343150)
    #> 7  existing 8.72     75.3 2.05      1    new rule1 POINT (438050 5341110)
    #> 8  existing 8.35     32.5 2.38      1    new rule1 POINT (433350 5341410)
    #> 9  existing 3.07      5.0 0.60      1    new rule1 POINT (433790 5340590)
    #> 10 existing 2.12      1.1 0.26      1    new rule1 POINT (437790 5343130)

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: 431110 ymin: 5337710 xmax: 438530 ymax: 5343210
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>      type.x zq90 pzabove2  zsd strata type.y  rule               geometry
    #> 1  existing 8.65     27.0 2.25      1    new rule1 POINT (433370 5341630)
    #> 2  existing 4.28      7.8 0.98      1    new rule1 POINT (438510 5339270)
    #> 3  existing 4.76     39.3 1.02      1    new rule1 POINT (435530 5342670)
    #> 4  existing 3.97     36.5 0.78      1    new rule1 POINT (434530 5342330)
    #> 5  existing 3.41     11.6 0.73      1    new rule1 POINT (435470 5342090)
    #> 6  existing 6.84     82.2 1.37      1    new rule1 POINT (434290 5343150)
    #> 7  existing 8.72     75.3 2.05      1    new rule1 POINT (438050 5341110)
    #> 8  existing 8.35     32.5 2.38      1    new rule1 POINT (433350 5341410)
    #> 9  existing 3.07      5.0 0.60      1    new rule1 POINT (433790 5340590)
    #> 10 existing 2.12      1.1 0.26      1    new rule1 POINT (437790 5343130)

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_existing`

Acknowledging 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)

    #--- sub sample using ---#
    e <- existing %>%
      extract_metrics(mraster = mraster, existing = .)

### `sample_existing(type = "clhs")`

The algorithm is unique in that it has two fundamental approaches:

1. Sample exclusively using `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: 431120.6 ymin: 5337713 xmax: 438545.4 ymax: 5343232
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>      zq90 pzabove2  zsd                 geometry
    #> 355 16.00     90.4 4.13 POINT (432656.3 5340643)
    #> 415 12.40     14.5 3.97 POINT (437895.4 5339319)
    #> 249  1.73      0.0 0.16 POINT (437998.6 5338247)
    #> 228 21.00     93.9 4.55 POINT (433007.6 5339706)
    #> 338 11.90     86.5 3.19 POINT (436247.4 5339384)
    #> 435 14.60     97.9 3.18 POINT (435072.1 5340353)
    #> 560 16.70     76.1 5.42 POINT (431265.4 5342299)
    #> 414 11.20     97.2 2.51 POINT (437703.4 5339375)
    #> 669 17.30     77.8 3.53 POINT (431817.7 5342763)
    #> 307  8.86     30.5 2.45   POINT (437727 5338743)

2. Sub-sampling using `raster` distributions

Our 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: 431102.6 ymin: 5337727 xmax: 438551 ymax: 5343232
    #> Projected CRS: +proj=utm +zone=17 +ellps=GRS80 +units=m +no_defs
    #> First 10 features:
    #>        zq90 pzabove2  zsd                 geometry
    #> 91354 18.40     97.1 3.25 POINT (431743.6 5339659)
    #> 91411  7.91     22.7 2.19 POINT (437942.5 5338055)
    #> 91954  4.12     33.5 0.81 POINT (435385.3 5342137)
    #> 91526 14.00     95.9 3.04 POINT (434903.7 5339777)
    #> 91674  7.70     45.3 2.09 POINT (436663.9 5340096)
    #> 91341  8.73     38.5 2.31 POINT (435910.6 5338232)
    #> 91293 16.70     80.9 4.80 POINT (435798.4 5337848)
    #> 91897  7.32     92.2 1.32 POINT (438152.5 5340911)
    #> 91533 11.90     86.5 3.19 POINT (436247.4 5339384)
    #> 92097 22.30     78.1 7.25 POINT (437505.9 5342975)

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: 431144.1 ymin: 5337707 xmax: 438551 ymax: 5343232
    #> Projected CRS: +proj=utm +zone=17 +ellps=GRS80 +units=m +no_defs
    #> First 10 features:
    #>        zq90 pzabove2  zsd dist2access                 geometry
    #> 91923 14.20     74.1 3.80   256.98735 POINT (435521.1 5341889)
    #> 91716  4.48     15.8 1.01    13.38319 POINT (438063.8 5339895)
    #> 91834 11.10     64.1 2.74   151.81332 POINT (432721.4 5342290)
    #> 91201 21.90     95.3 5.96    79.94910 POINT (432006.3 5337707)
    #> 91334  1.74      0.0 0.15     6.98911   POINT (434183 5338737)
    #> 92088  5.96     18.4 1.01   303.94952 POINT (437257.8 5342839)
    #> 91672 20.50     85.7 5.76    29.76061   POINT (436280 5340208)
    #> 91396 24.10     88.9 6.08   176.86142 POINT (434103.3 5339178)
    #> 91540 16.90     83.3 4.50    43.24137   POINT (438359 5338767)
    #> 91976  5.21     42.9 1.24    20.89866 POINT (433521.8 5342890)

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: 431144.1 ymin: 5337707 xmax: 438551 ymax: 5343227
    #> Projected CRS: +proj=utm +zone=17 +ellps=GRS80 +units=m +no_defs
    #> First 10 features:
    #>        zq90 pzabove2  zsd dist2access                 geometry
    #> 91533 13.10     77.2 3.28   125.79874 POINT (434505.2 5341977)
    #> 91634 14.20     77.8 3.36    82.68313 POINT (435609.8 5342904)
    #> 91655 16.70     74.5 4.73   187.34089   POINT (437122 5343087)
    #> 91355 13.30     96.6 2.51    56.46116 POINT (435095.6 5339721)
    #> 91388 13.50     80.5 2.85   290.78908 POINT (433288.3 5340666)
    #> 91406  9.44     42.2 2.57   166.42340 POINT (433152.5 5340914)
    #> 91266 13.20     75.0 3.26   260.44597 POINT (435774.8 5338480)
    #> 91284  9.85     90.7 2.39    59.55119 POINT (436982.7 5338336)
    #> 91430  4.68     27.7 1.20   104.50067 POINT (434360.4 5340769)
    #> 91536 18.40     86.5 4.62   145.59620 POINT (436232.8 5341472)

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: 431102.6 ymin: 5337707 xmax: 438545.4 ymax: 5343223
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>    zq90 pzabove2  zsd                 geometry
    #> 2  19.3     90.6 5.56 POINT (431238.4 5337931)
    #> 3  18.0     79.7 5.60 POINT (431430.4 5337875)
    #> 6  21.9     95.3 5.96 POINT (432006.3 5337707)
    #> 7  19.0     96.3 4.02 POINT (431102.6 5338180)
    #> 10 18.2     89.9 5.34 POINT (431678.5 5338011)
    #> 12 15.1     92.7 3.56 POINT (432062.4 5337899)
    #> 16 14.6     95.4 2.80 POINT (431158.7 5338372)
    #> 21 13.2     82.4 4.00 POINT (432118.5 5338091)
    #> 23 14.9     93.3 2.70 POINT (432502.4 5337979)
    #> 26 23.4     93.4 5.55 POINT (433078.3 5337810)

    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: 431102.6 ymin: 5337731 xmax: 438551 ymax: 5343232
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>    zq90 pzabove2  zsd                 geometry
    #> 1  14.7     95.0 2.68 POINT (431182.3 5337740)
    #> 5  16.3     94.8 3.96 POINT (431814.3 5337763)
    #> 7  19.0     96.3 4.02 POINT (431102.6 5338180)
    #> 8  18.7     95.0 5.86 POINT (431294.5 5338123)
    #> 15 12.2     49.6 3.58 POINT (432638.3 5337731)
    #> 23 14.9     93.3 2.70 POINT (432502.4 5337979)
    #> 26 23.4     93.4 5.55 POINT (433078.3 5337810)
    #> 27 21.7     86.1 6.52 POINT (433270.3 5337754)
    #> 28 17.2     94.4 3.88 POINT (431214.8 5338563)
    #> 30 17.9     94.5 3.24 POINT (431598.8 5338451)

### `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: 431111.6 ymin: 5337704 xmax: 438545.4 ymax: 5343232
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>     zq90 pzabove2  zsd                 geometry
    #> 1  24.90     92.9 6.10 POINT (433382.6 5338138)
    #> 2  14.30     57.9 4.07 POINT (437632.7 5341271)
    #> 3  15.00     35.8 4.59 POINT (438223.2 5339015)
    #> 4   7.39     72.6 1.72 POINT (438199.6 5339647)
    #> 5  15.00     93.6 4.18 POINT (438232.2 5340471)
    #> 6  17.20     70.4 4.38 POINT (431489.9 5343067)
    #> 7  25.10     88.0 5.96 POINT (432703.4 5339378)
    #> 8  14.80     90.7 2.98   POINT (432535 5338803)
    #> 9  14.10     96.7 2.21 POINT (437473.3 5342151)
    #> 10 16.60     69.5 4.91 POINT (432024.3 5340619)

### `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 300 features and 4 fields
    #> Geometry type: POINT
    #> Dimension:     XY
    #> Bounding box:  xmin: 431102.6 ymin: 5337704 xmax: 438536.4 ymax: 5343232
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>    strata zq90 pzabove2  zsd                 geometry
    #> 1       3 17.3     85.5 4.30 POINT (437080.4 5340807)
    #> 2       3 14.6     97.8 2.41 POINT (433766.5 5338026)
    #> 3       3 14.1     71.8 4.27 POINT (437904.4 5340775)
    #> 4       3 16.2     92.6 3.60 POINT (437417.2 5341959)
    #> 5       3 17.7     95.6 3.56 POINT (433471.3 5339154)
    #> 6       3 18.2     87.9 4.40 POINT (431129.6 5342548)
    #> 7       3 16.4     97.9 2.51 POINT (431135.2 5339004)
    #> 8       3 14.3     88.6 2.73 POINT (436776.2 5340480)
    #> 9       3 15.8     88.7 3.73 POINT (434847.6 5339585)
    #> 10      3 14.6     80.7 3.76 POINT (434838.6 5338129)

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: 431106 ymin: 5337707 xmax: 438527.4 ymax: 5343232
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>    strata zq90 pzabove2  zsd                 geometry
    #> 1       3 14.5     93.2 4.16 POINT (437446.3 5337783)
    #> 2       3 16.6     83.9 4.08 POINT (437623.7 5339815)
    #> 3       3 18.7     79.0 4.62 POINT (436672.9 5341552)
    #> 4       3 14.3     82.3 4.33 POINT (434735.3 5339201)
    #> 5       3 14.3     93.3 2.70 POINT (434126.8 5338545)
    #> 6       3 17.9     94.5 3.24 POINT (431598.8 5338451)
    #> 7       3 16.9     83.3 4.50   POINT (438359 5338767)
    #> 8       3 16.4     87.6 4.57 POINT (432478.9 5338611)
    #> 9       3 15.2     69.6 4.67 POINT (433713.8 5342834)
    #> 10      3 16.2     61.4 3.87 POINT (432880.8 5341410)

    #--- 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:

    #--- check proportions match weights ---#
    table(s$strata) / 100
    #>
    #>   1   2   3   4
    #> 0.2 0.6 0.1 0.1

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: 431129.6 ymin: 5337722 xmax: 438551 ymax: 5343114
    #> Projected CRS: UTM Zone 17, Northern Hemisphere
    #> First 10 features:
    #>    strata zq90 pzabove2  zsd                 geometry
    #> 1       3 18.2     83.8 4.75 POINT (435854.5 5338040)
    #> 2       3 17.1     93.6 3.36 POINT (432473.3 5342155)
    #> 3       3 16.5     89.1 3.92 POINT (433391.6 5339594)
    #> 4       3 18.0     78.9 4.32 POINT (432417.2 5341963)
    #> 5       3 12.9     86.0 3.18 POINT (433110.9 5338634)
    #> 6       3 17.9     89.5 3.23 POINT (433793.5 5342394)
    #> 7       3 17.4     87.7 3.64 POINT (436424.8 5341416)
    #> 8       3 15.8     85.8 4.52 POINT (434206.5 5338105)
    #> 9       3 16.1     82.9 4.35 POINT (434454.6 5338241)
    #> 10      3 16.3     69.4 4.26 POINT (437408.2 5340503)

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).