Provides null model algorithms for categorical and quantitative community ecology data. Extends classic binary null models (e.g., 'curveball', 'swap') to work with categorical data. Provides a stratified randomization framework for continuous data.

nullcat provides null model algorithms for categorical and
quantitative community ecology data. It extends classic binary null
models (e.g., curveball, swap) to work with categorical data, and
introduces a stratified randomization framework for continuous data that
addresses limitations in existing methods for randomizing quantitative
and count data.
# Install stable version from CRAN:
install.packages("nullcat")
# Or dev version from GitHub:
# install.packages("remotes")
remotes::install_github("matthewkling/nullcat")
Generalize binary null models to matrices where cells contain integers representing discrete categories:
library(nullcat)
# Create a categorical matrix
set.seed(123)
cat_matrix <- matrix(sample(1:4, 20*10, replace = TRUE), nrow = 20)
# Randomize using curvecat (preserves row & column category multisets)
randomized <- curvecat(cat_matrix, n_iter = 1000)
# Verify margins are preserved
all.equal(sort(cat_matrix[1,]), sort(randomized[1,]))
#> [1] TRUE
all.equal(sort(cat_matrix[,1]), sort(randomized[,1]))
#> [1] TRUE
Available algorithms: curvecat(), swapcat(), tswapcat(),
r0cat(), c0cat()
Apply stratified randomization to continuous community data:
# Create a quantitative community matrix
set.seed(456)
comm <- matrix(rexp(50 * 30, rate = 0.5), nrow = 50)
# Stratified randomization with 5 strata
rand1 <- quantize(comm, n_strata = 5, n_iter = 2000)
# Preserve row value multisets (row sums maintained)
rand2 <- quantize(comm, n_strata = 5, fixed = "row", n_iter = 2000)
all.equal(rowSums(comm), rowSums(rand2))
#> [1] TRUE
Randomize within groups of sites, e.g. regions, or a different random tiling of space in each replicate:
set.seed(789)
x <- matrix(sample(1:4, 600, replace = TRUE), nrow = 60)
# Fixed regions: each region keeps its own species pool
region <- rep(1:3, each = 20)
x_reg <- curvecat(x, n_iter = 1000, row_groups = region)
# Random hexagonal tilings (one per replicate) pool each site with its neighbors
coords <- cbind(runif(60, 0, 10), runif(60, 0, 10))
tiles <- tile_groups(coords, spacing = 4, n = 99, lonlat = FALSE)
sims <- nullcat_batch(x, n_reps = 99, row_groups = tiles, n_iter = 500)
See vignette("nullcat") for comprehensive documentation including:
Package website: https://matthewkling.github.io/nullcat/
Report issues: https://github.com/matthewkling/nullcat/issues