
Auxiliary GLMM for trait-varying and site-varying slopes
Source:R/fit_auxiliary_residents_glmm.R
fit_auxiliary_residents_glmm.Rdfit_auxiliary_residents_glmm() assembles a long table of resident
site by species cells with standardized predictors
\(r^{(z)}_{js}\), \(C^{(z)}_{js}\), and \(S^{(z)}_{js}\), together with
two-dimensional trait scores (tr1, tr2). It then fits a Gaussian
generalized linear mixed model to estimate how slopes on abiotic suitability,
niche crowding, and site saturation vary across the trait plane.
Optional site-level random slopes can be included for r_z and
C_z. Random slopes for S_z are intentionally excluded because
S_z is site-only and has no within-site variation across residents.
This function is intentionally forgiving: non-matrix inputs are coerced using
as.matrix(), missing dimension names are repaired when possible, and
inputs are aligned to comm_res.
Usage
fit_auxiliary_residents_glmm(
comm_res,
r_js_z,
C_js_z,
S_js_z,
Q_res,
use_site_random_slopes = TRUE,
family = gaussian(),
control = glmmTMB::glmmTMBControl(optCtrl = list(iter.max = 1e+05, eval.max = 1e+05)),
na_action = c("drop", "error"),
verbose = TRUE
)Arguments
- comm_res
Numeric matrix of site by resident abundances. Row names are site identifiers and column names are resident identifiers.
- r_js_z
Numeric matrix of standardized abiotic suitability with the same dimensions and names as
comm_res.- C_js_z
Numeric matrix of standardized niche crowding with the same dimensions and names as
comm_res.- S_js_z
Numeric matrix of standardized site saturation broadcast across residents, with the same dimensions and names as
comm_res.- Q_res
Data frame of resident trait scores. Must contain numeric columns
tr1andtr2, with row names matchingcolnames(comm_res).- use_site_random_slopes
Logical; if
TRUE, include random slopes forr_zandC_zat the site level.- family
GLM family for the conditional model. Default is
gaussian()applied tolog1p(abundance).- control
Control object passed to
glmmTMB::glmmTMB().- na_action
How to handle rows with missing values. Either
"drop"(default) or"error".- verbose
Logical; if
TRUE, print a short model summary line.
Value
A list with components:
fit: the fittedglmmTMBmodeldata: the long-format data frame used for fittingformula: the model formulaargs: resolved arguments used in the fit
Details
Fit an auxiliary residents-only GLMM on standardized predictors
The fixed-effects component of the model is $$\log(1 + \mathrm{abundance}) \sim (r_z + C_z + S_z) \times (tr1 + tr2),$$ with random intercepts for species and site always included.
When use_site_random_slopes = TRUE, random slopes
\((0 + r_z | site)\) and \((0 + C_z | site)\) are added. Random slopes
for S_z are omitted because S_z is constant within each site
and therefore not identifiable.
Role in invasion fitness
This auxiliary model estimates trait-dependent slope systems that can be mapped to invader-level parameters such as \(\theta_i\), \(\alpha_i\), and \(\beta_i\), and optionally to site-varying counterparts via random slopes. These parameters enter directly into the linear invasion-fitness decomposition $$\lambda_{is} = \Gamma_{is} r^{(z)}_{is} - \alpha_{is} C^{(z)}_{is} - \beta_i S^{(z)}_{is},$$ linking trait position to abiotic suitability, niche crowding, and resident competition.
Examples
if (FALSE) { # \dontrun{
# Toy dimensions
set.seed(1)
S = 8 # sites
J = 6 # residents
sites = paste0("s", 1:S)
res_ids = paste0("sp", 1:J)
# Site x resident abundance
comm_res = matrix(rpois(S*J, lambda = 2), S, J,
dimnames = list(sites, res_ids))
# Standardized predictors (row-wise z by site for r and C; site-only for S)
r_raw = matrix(rnorm(S*J), S, J, dimnames = dimnames(comm_res))
C_raw = matrix(rnorm(S*J), S, J, dimnames = dimnames(comm_res))
S_raw = matrix(rep(scale(rnorm(S))[,1], each = J), S, J,
dimnames = dimnames(comm_res))
# Simple per-site z for demo
r_js_z = t(scale(t(r_raw))); r_js_z[!is.finite(r_js_z)] = 0
C_js_z = t(scale(t(C_raw))); C_js_z[!is.finite(C_js_z)] = 0
S_js_z = S_raw
# Resident trait-plane scores (PCoA on Gower in real workflow)
Q_res = data.frame(tr1 = rnorm(J), tr2 = rnorm(J))
rownames(Q_res) = res_ids
aux = fit_auxiliary_residents_glmm(
comm_res = comm_res,
r_js_z = r_js_z,
C_js_z = C_js_z,
S_js_z = S_js_z,
Q_res = Q_res,
use_site_random_slopes = TRUE
)
summary(aux$fit)
head(aux$data)
aux$formula
} # }