Skip to contents

For each trait, returns the proportion of total latent variance attributable to each component present in the model: shared (rr) and unique (diag) at each tier (unit, unit_obs, phy), diagonal cluster / cluster2 components when present, the observation residual \(\sigma^2_\varepsilon\) of Gaussian and lognormal traits (residual), plus optionally the link's implicit residual of non-Gaussian traits.

Usage

extract_proportions(
  fit,
  link_residual = c("auto", "none"),
  format = c("long", "wide")
)

Arguments

fit

A fit returned by gllvmTMB().

For non-Gaussian fits: "auto" (default) adds the link's implicit residual as its own per-trait component (e.g. \(\pi^2/3\) for binomial logit, \(\log(1 + 1/\hat\mu_t)\) for Poisson log; see "Family-aware link residuals" in extract_Sigma() for the full per-family table). Mixed-family fits get the residual implied by each trait's family/link. "none" omits the link-implicit component. The Gaussian and lognormal residual is a model variance, not a link-implied constant, so it is kept under either value.

format

"long" (default) returns a tibble-like data frame with one row per (trait, component); "wide" returns one row per trait with one column per component.

Value

Long format: data frame with columns trait, component (e.g. "shared_unit", "unique_unit", "shared_unit_obs", "unique_unit_obs", "unique_phy", "shared_phy", "unique_cluster", "unique_cluster2", "residual", "link_residual"), variance (the absolute variance), proportion (the share of the total). Wide format: data frame with one column per component plus a total_variance column; the per-trait proportions sum to 1. When a component was left out, the "omitted_components" attribute names it.

OLRE interpretation: for fits with a genuine observation-level diagonal term, usually written as per-row indep() in new code (see extract_residual_split()), the unique_unit_obs component is \(\sigma^2_e\) (the estimated OLRE variance) and the link_residual component is \(\sigma^2_d\) (the distribution-specific latent residual). For a Gaussian or lognormal trait with such a per-row term (including the default latent() Psi when each unit has one observation per trait), the package does not estimate \(\sigma_\varepsilon\): it fixes it at 1/1000 of the standard deviation of all responses pooled on the raw scale. That fixed value is still part of the fitted variance and appears as residual. It is negligible when the traits share a scale, but not when trait scales differ widely or when lognormal responses are large.

Details

Some active components are not partitioned here: (1 | group) random intercepts, common-variance phylogenetic terms such as phylo_indep(common = TRUE), terms of a fit with several named kernel_*() terms, spatial fields, random-slope terms (intercepts included), response-column slopes and coefficients, temporal states, and the known sampling variance of meta_V(). extract_proportions() leaves each of them out, names them in a warning of class gllvmTMB_proportions_component_omitted, and records them in the "omitted_components" attribute of the result. The proportions are then shares of the included components only, and total_variance is their sum, not the trait's total variance. VP() does count the (1 | group) intercepts, the common-variance phylogenetic terms and the multi-kernel terms.

This is the most general proportion-decomposition function in the package. extract_phylo_signal() is the focused PGLLVM \(H^2 / C^2_\text{non} / \psi^2\) convenience wrapper for the species-level case; extract_communality() gives the rr-only "shared" proportion at one tier; extract_ICC_site() gives the between-vs-within proportion. extract_proportions() returns all of these in one tidy frame.

Structured trait-intercept rho fits are excluded because this source- allocation summary does not account for attenuation. Use extract_Sigma() and its source_strength metadata.

See also

extract_phylo_signal() — the PGLLVM-specific shortcut; extract_communality(); extract_ICC_site(); extract_residual_split() — explicit \(\sigma^2_d / \sigma^2_e\) decomposition for OLRE fits.

Examples

set.seed(3)
## Simulate 4 traits recorded on a few species at each of 50 sites, with
## trait variation at two tiers: between sites (the "unit" tier) and
## between species records within a site (the "unit_obs" tier). A zero
## beta matrix turns off the simulator's environmental effects, which
## this model does not include.
sim <- simulate_site_trait(
  n_sites = 50, n_species = 10, n_traits = 4,
  mean_species_per_site = 3,
  beta = matrix(0, 4, 2),
  Lambda_B = matrix(c(0.8, 0.6, -0.5, 0.4), 4, 1),
  psi_B = rep(0.3, 4),
  Lambda_W = matrix(c(0.5, -0.4, 0.4, 0.3), 4, 1),
  sigma2_eps = 0.3
)
## One latent factor plus trait-specific variances at each tier. Each
## species record has one value per trait, so the within-site
## trait-specific variances also absorb the measurement noise
## (gllvmTMB prints a note saying so).
fit <- gllvmTMB(
  value ~ 0 + trait +
    latent(0 + trait | site, d = 1, unique = TRUE) +
    latent(0 + trait | site_species, d = 1, unique = TRUE),
  data     = sim$data,
  trait    = "trait",
  unit     = "site",
  unit_obs = "site_species"
)
#> ℹ Auto-suppressing `sigma_eps`: the per-row diagonal at "site_species" already
#>   absorbs the observation residual.
#> • Fixed at 0.00122 (~1/1000 of sd(y)) to keep the Gaussian density
#>   well-defined; the row-level residual variance is fully captured by that
#>   diagonal (the folded Psi of `latent(..., unique = TRUE)`, or an explicit
#>   `indep()` / `unique()` at this grouping).
## Each trait's variance split into components (shared and
## trait-specific, at each tier): one row per trait and component,
## with the variance and its share of the trait's total
extract_proportions(fit)
#>      trait       component     variance   proportion
#> 1  trait_1     shared_unit 6.962143e-01 4.710040e-01
#> 2  trait_2     shared_unit 3.207111e-01 2.875673e-01
#> 3  trait_3     shared_unit 3.048792e-01 3.018377e-01
#> 4  trait_4     shared_unit 7.463553e-02 8.036651e-02
#> 5  trait_1     unique_unit 3.785295e-01 2.560834e-01
#> 6  trait_2     unique_unit 4.113023e-01 3.687964e-01
#> 7  trait_3     unique_unit 3.256956e-01 3.224465e-01
#> 8  trait_4     unique_unit 4.654574e-01 5.011981e-01
#> 9  trait_1 shared_unit_obs 1.260911e-01 8.530331e-02
#> 10 trait_2 shared_unit_obs 1.171711e-01 1.050621e-01
#> 11 trait_3 shared_unit_obs 1.080697e-01 1.069916e-01
#> 12 trait_4 shared_unit_obs 1.400961e-01 1.508536e-01
#> 13 trait_1 unique_unit_obs 2.773132e-01 1.876083e-01
#> 14 trait_2 unique_unit_obs 2.660697e-01 2.385728e-01
#> 15 trait_3 unique_unit_obs 2.714305e-01 2.687227e-01
#> 16 trait_4 unique_unit_obs 2.484989e-01 2.675801e-01
#> 17 trait_1        residual 1.495978e-06 1.012061e-06
#> 18 trait_2        residual 1.495978e-06 1.341377e-06
#> 19 trait_3        residual 1.495978e-06 1.481054e-06
#> 20 trait_4        residual 1.495978e-06 1.610849e-06
## The same shares with one row per trait and one column per component;
## each row of proportions sums to 1
extract_proportions(fit, format = "wide")
#>           trait shared_unit unique_unit shared_unit_obs unique_unit_obs
#> trait_1 trait_1  0.47100396   0.2560834      0.08530331       0.1876083
#> trait_2 trait_2  0.28756732   0.3687964      0.10506208       0.2385728
#> trait_3 trait_3  0.30183775   0.3224465      0.10699160       0.2687227
#> trait_4 trait_4  0.08036651   0.5011981      0.15085360       0.2675801
#>             residual total_variance
#> trait_1 1.012061e-06      1.4781495
#> trait_2 1.341377e-06      1.1152556
#> trait_3 1.481054e-06      1.0100766
#> trait_4 1.610849e-06      0.9286895