R/cpr_rand_comm.R

Defines functions cpr_rand_comm_intern cpr_rand_comm

Documented in cpr_rand_comm

#' Randomize a single community matrix
#'
#' Note that binary null models return a binary matrix, even if an abundance
#' matrix was used as input.
#'
#' @param comm Dataframe or matrix; input community data with
#'   sites (communities) as rows and species as columns. Values of each cell are
#'   the presence/absence (0 or 1) or number of individuals (abundance) of each
#'   species in each site.
#' @param null_model Character vector of length 1 or object of class `commsim`;
#'   either the name of the model to use for generating random communities (null
#'   model), or a custom null model. For full list of available predefined null
#'   models, see the help file of [vegan::commsim()], or run
#'   [vegan::make.commsim()]. An object of class `commsim` can be generated with
#'   [vegan::commsim()] (see Examples).
#' @param n_iterations Numeric vector of length 1; number of iterations for
#'   sequential null models. Ignored by non-sequential null models.
#' @param thin Numeric vector of length 1; thinning parameter used by some
#'   null models in `vegan` (e.g., `quasiswap`); ignored for other models.
#' @param seed Integer vector of length 1 or NULL; random seed that will be used
#'   in a call to `set.seed()` before randomizing the matrix. Default (`NULL`)
#'   will not change the random generator state.
#' @return Matrix
#' @export
#' @examples
#' set.seed(12345)
#'
#' # Check list of available pre-defined null models in vegan
#' vegan::make.commsim()
#'
#' # Binary null model produces binary output
#' data(phylocom)
#' cpr_rand_comm(phylocom$comm, "swap", 100)
#'
#' # Quantitative null model produces quantitative output
#' cpr_rand_comm(phylocom$comm, "swap_count", 100)
#'
#' # How to use a custom null model
#' # 1. Define a randomizing function, e.g. re-sample the matrix while
#' # preserving total number of presences (same as the "r00" model)
#' randomizer <- function(x, n, ...) {
#'   array(replicate(n, sample(x)), c(dim(x), n))
#' }
#'
#' # 2. Generate a commsim object
#' cs_object <- vegan::commsim(
#'   "r00_model",
#'   fun = randomizer, binary = TRUE,
#'   isSeq = FALSE, mode = "integer"
#' )
#'
#' # 3. Generate the null community
#' cpr_rand_comm(phylocom$comm, cs_object, 100)
cpr_rand_comm <- function(
  comm, null_model, n_iterations = 1, thin = 1, seed = NULL
) {
  #' @srrstats {G2.1, G2.6} Check input types and lengths
  # - comm
  assertthat::assert_that(
    inherits(comm, "data.frame") | inherits(comm, "matrix"),
    msg = "'comm' must be of class 'data.frame' or 'matrix'"
  )
  assertthat::assert_that(
    isTRUE(
      all(unique(purrr::map_chr(comm, class)) %in% c("numeric", "integer"))
    ),
    msg = "All columns of 'comm' must be numeric or integer class"
  )
  # - null_model
  assertthat::assert_that(
    assertthat::is.string(null_model) | inherits(null_model, "commsim"),
    msg = "'null_model' must be a string (character vector of length 1) or an object of class 'commsim'" # nolint
  )
  if (isTRUE(assertthat::is.string(null_model))) {
    assertthat::assert_that(assertthat::not_empty(comm))
    assertthat::assert_that(assertthat::noNA(null_model))
    assertthat::assert_that(
      isTRUE(null_model %in% vegan::make.commsim()),
      msg = paste0(
        "'null_model' must be one of: '",
        paste0(vegan::make.commsim(), collapse = "', '"), "'"
      )
    )
  }
  # - n_iterations
  assertthat::assert_that(assertthat::is.number(n_iterations))
  assertthat::assert_that(assertthat::noNA(n_iterations))
  assertthat::assert_that(is.finite(n_iterations))
  n_iterations <- as.integer(n_iterations)
  assertthat::assert_that(is.integer(n_iterations))
  assertthat::assert_that(n_iterations > 0, msg = "'n_iterations' must be > 0")
  # - thin
  assertthat::assert_that(assertthat::is.number(thin))
  assertthat::assert_that(assertthat::noNA(thin))
  assertthat::assert_that(is.finite(thin))
  thin <- as.integer(thin)
  assertthat::assert_that(is.integer(thin))
  assertthat::assert_that(thin > 0, msg = "'thin' must be > 0")
  # - seed
  assertthat::assert_that(is.numeric(seed) | is.null(seed))

  # Randomize matrix
  cpr_rand_comm_intern(
    comm = comm, null_model = null_model,
    n_iterations = n_iterations,
    thin = thin, seed = seed
  )
}

#' Randomize a single community matrix, internal version
#'
#' Does not run checks on input, to reduce computational burden when
#' repeating many times to generate null distribution.
#' Meant for internal use only.
#'
#' @inherit cpr_rand_comm params return
#'
#' @noRd
cpr_rand_comm_intern <- function(
  comm, null_model, n_iterations = 1, thin = 1, seed = NULL
) {
  # Convert to matrix
  comm <- as.matrix(comm)

  # Initiate null model
  null_model <- vegan::nullmodel(comm, null_model)

  # Randomize matrix
  # just take the first simulated community after n_iterations - 1
  stats::simulate(
    null_model,
    nsim = 1, thin = thin, burnin = n_iterations - 1, seed = seed
  )[, , 1]
}
joelnitta/canaper documentation built on May 7, 2023, 10:28 a.m.