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, plus optionally the binomial link's implicit residual.

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.

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", "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.

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).

Details

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`: `indep(0 + trait | site_species)` is at the
#>   per-row level, so it 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 the
#>   per-row diagonal term.
## 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 0.69621687 0.47099863
#> 2  trait_2     shared_unit 0.32072421 0.28757834
#> 3  trait_3     shared_unit 0.30488801 0.30184502
#> 4  trait_4     shared_unit 0.07463678 0.08036782
#> 5  trait_1     unique_unit 0.37855037 0.25609363
#> 6  trait_2     unique_unit 0.41129712 0.36879081
#> 7  trait_3     unique_unit 0.32569315 0.32244251
#> 8  trait_4     unique_unit 0.46545928 0.50119991
#> 9  trait_1 shared_unit_obs 0.12609026 0.08530149
#> 10 trait_2 shared_unit_obs 0.11717010 0.10506093
#> 11 trait_3 shared_unit_obs 0.10806933 0.10699073
#> 12 trait_4 shared_unit_obs 0.14009496 0.15085225
#> 13 trait_1 unique_unit_obs 0.27731427 0.18760625
#> 14 trait_2 unique_unit_obs 0.26606716 0.23856992
#> 15 trait_3 unique_unit_obs 0.27143082 0.26872175
#> 16 trait_4 unique_unit_obs 0.24849886 0.26758002
## 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.47099863   0.2560936      0.08530149       0.1876063
#> trait_2 trait_2  0.28757834   0.3687908      0.10506093       0.2385699
#> trait_3 trait_3  0.30184502   0.3224425      0.10699073       0.2687217
#> trait_4 trait_4  0.08036782   0.5011999      0.15085225       0.2675800
#>         total_variance
#> trait_1      1.4781718
#> trait_2      1.1152586
#> trait_3      1.0100813
#> trait_4      0.9286899