
Per-trait proportion-of-variance decomposition across all model components
Source:R/extract-omega.R
extract_proportions.RdFor 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.
Arguments
- fit
A fit returned by
gllvmTMB().- link_residual
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" inextract_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 lognormalresidualis 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