Applies a post-hoc rotation (e.g. varimax) to the loading matrix
\(\Lambda\) of either the between-unit (level = "unit") or
within-unit (level = "unit_obs") reduced-rank component. The latent scores are
rotated by the inverse transform so the linear predictor (and the
fitted log-likelihood) is unchanged; only the parameterisation
changes.
Value
A list with rotated Lambda (n_traits × d), rotated
scores (with rows = units or within-unit observations, columns = factors),
and the rotation matrix T such that
\(\Lambda_{\text{rotated}} = \Lambda T\).
Details
Useful when the lower-triangular constraint inherited from the glmmTMB-style lower-triangular constraint produces hard-to-interpret factors; a varimax rotation almost always yields cleaner trait-loading patterns.
The rotation is applied to \(\Lambda\) on the left and to the
latent scores on the right using the inverse transform, so
\(\Lambda_{\text{rot}} \mathbf{z}_{\text{rot}} = \Lambda \mathbf{z}\)
is unchanged. For varimax, T is orthogonal so the rotation
preserves the implied covariance \(\Lambda \Lambda^\top\); for
promax, T is oblique and the columns of \(\Lambda_{\text{rot}}\)
are no longer orthogonal.
Examples
if (FALSE) { # \dontrun{
set.seed(1)
sim <- simulate_site_trait(
n_sites = 60, n_species = 12, n_traits = 4,
Lambda_B = matrix(c(1.0, 0.7, -0.3, 0.5,
0.3, -0.5, 0.8, 0.2),
nrow = 4, ncol = 2),
S_B = c(0.3, 0.3, 0.3, 0.3),
seed = 1
)
fit <- gllvmTMB(value ~ 0 + trait +
latent(0 + trait | site, d = 2) +
unique(0 + trait | site),
data = sim$data)
raw <- extract_ordination(fit, "unit")
rot <- rotate_loadings(fit, level = "unit", method = "varimax")
# raw$loadings - lower-triangular (hard to read)
# rot$Lambda - varimax-rotated (typically simpler structure)
} # }
