Skip to contents

Returns one row per trait and latent axis from a fitted gllvmTMB() model. This is the report-ready companion to rotate_loadings() and to plot(type = "ordination"): the same rotation, axis-ordering, sign-anchor, and optional loading-standardization conventions are recorded in columns instead of left inside a matrix.

Usage

extract_rotated_loadings_table(
  fit,
  level = "unit",
  method = c("varimax", "promax", "none"),
  order_axes = TRUE,
  sign_anchor = c("auto", "none"),
  anchor_traits = NULL,
  loading_scale = c("raw", "standardized")
)

Arguments

fit

A fitted multivariate model returned by gllvmTMB().

level

"unit" (between-unit) or "unit_obs" (within-unit). Deprecated aliases "B" and "W" are still accepted with a warning.

method

One of "varimax", "promax", or "none"; passed to rotate_loadings().

order_axes

Logical. When TRUE, reorder rotated axes by decreasing raw shared variance before tabulation. Ignored when method = "none".

sign_anchor

One of "auto" or "none". "auto" flips each rotated axis so its anchor trait has a positive loading. Ignored when method = "none".

anchor_traits

Optional character vector of trait names used for sign anchoring. Supply one trait per axis after ordering. Axes without a supplied anchor use the trait with the largest absolute loading.

loading_scale

One of "raw" or "standardized". "raw" returns the rotated loadings on the fitted response scale. "standardized" divides each trait loading by the square root of that trait's model-implied total variance, matching plot(type = "ordination", standardize_loadings = TRUE).

Value

A data frame with columns level, trait, axis, loading, abs_loading, axis_variance, axis_share, rotation, order_axes, sign_anchor, anchor_trait, and loading_scale. axis_variance and axis_share are computed from the rotated raw loading matrix before any optional standardization; these are the quantities used to order axes.

Details

Scope: covered for fitted latent() components at level = "unit" or level = "unit_obs" with raw or standardized point-estimate loadings. This table does not attach uncertainty intervals to loadings. Bootstrap or simulation-based uncertainty is not yet implemented and remains possible future work for a later inference slice.

Examples

set.seed(1)
# Simulate six traits, each measured twice on 100 units (e.g. sites).
# Traits 2-3 share one latent axis, traits 4-6 share a second axis,
# and trait_1 loads on both.
Lambda <- cbind(c(0.7, 1.0, 0.9, 0.0, 0.0, 0.0),
                c(0.7, 0.0, 0.0, 1.0, 0.9, 0.8))
sim <- simulate_unit_trait(n_units = 100, n_obs_per_unit = 2,
                           n_traits = 6, Lambda_B = Lambda,
                           psi_B = 0.4, sigma2_eps = 0.3)
fit <- gllvmTMB(value ~ 0 + trait +
                  latent(0 + trait | unit, d = 2, unique = TRUE),
                data = sim$data, trait = "trait", unit = "unit")

# One row per trait and axis after varimax rotation. axis_share is the
# share of the shared (latent) variance carried by each axis.
tab <- extract_rotated_loadings_table(fit, level = "unit")
print(tab[, c("trait", "axis", "loading", "axis_share", "anchor_trait")],
      digits = 2)
#>      trait axis loading axis_share anchor_trait
#> 1  trait_1  LV1   0.530       0.52      trait_4
#> 2  trait_2  LV1  -0.040       0.52      trait_4
#> 3  trait_3  LV1   0.035       0.52      trait_4
#> 4  trait_4  LV1   0.968       0.52      trait_4
#> 5  trait_5  LV1   0.841       0.52      trait_4
#> 6  trait_6  LV1   0.872       0.52      trait_4
#> 7  trait_1  LV2   0.712       0.48      trait_3
#> 8  trait_2  LV2   0.941       0.48      trait_3
#> 9  trait_3  LV2   1.015       0.48      trait_3
#> 10 trait_4  LV2  -0.016       0.48      trait_3
#> 11 trait_5  LV2   0.061       0.48      trait_3
#> 12 trait_6  LV2   0.135       0.48      trait_3

# Standardized loadings divide by each trait's total between-unit
# standard deviation, so traits on different scales are comparable.
std <- extract_rotated_loadings_table(fit, level = "unit",
                                      loading_scale = "standardized")
# The tidy layout makes filtering easy: the strong loadings per axis.
print(std[std$abs_loading > 0.5, c("axis", "trait", "loading")],
      digits = 2)
#>   axis   trait loading
#> 4  LV1 trait_4    0.86
#> 5  LV1 trait_5    0.74
#> 6  LV1 trait_6    0.78
#> 7  LV2 trait_1    0.62
#> 8  LV2 trait_2    0.87
#> 9  LV2 trait_3    0.83
# Or reshape it back to a trait-by-axis grid.
round(xtabs(loading ~ trait + axis, data = std), 2)
#>          axis
#> trait       LV1   LV2
#>   trait_1  0.46  0.62
#>   trait_2 -0.04  0.87
#>   trait_3  0.03  0.83
#>   trait_4  0.86 -0.01
#>   trait_5  0.74  0.05
#>   trait_6  0.78  0.12