
Latent-factor (reduced-rank) random effect: latent(0 + trait | g, d = K)
Source: R/brms-sugar.R
latent.RdCanonical name for a reduced-rank latent-factor random effect at a
grouping g. Formerly rr(0 + trait | g, d = K) – same engine, new
name. The "rr" alias still works for backward compat but emits a
one-shot deprecation warning per session.
Arguments
- formula
0 + trait | gstyle formula (LHS is the response factor, typically0 + trait; RHS is the grouping factor).- d
Integer; number of latent factors. The hard guard only requires
d <= n_traits(the number of traits), but that is not the limit of what the data can identify. With the defaultunique = TRUE, each unit-trait cell observed once, and \(T\) traits, the covariance \(\boldsymbol\Sigma = \boldsymbol\Lambda\boldsymbol\Lambda^\top + \boldsymbol\Psi\) has \(T(T + 1)/2\) free entries to estimate \(T d - d(d - 1)/2 + T\) parameters (loadings up to rotation, plus the diagonal \(\boldsymbol\Psi\)). The counting rule of thumb is \((T - d)^2 \ge T + d\): \(T = 3\) and \(T = 4\) allowd <= 1, \(T = 5\) allowsd <= 2, and \(T = 10\) allowsd <= 6. Above it the split between \(\boldsymbol\Lambda\boldsymbol\Lambda^\top\) and \(\boldsymbol\Psi\) is not identified, andcheck_gllvmTMB()can flag only the symptoms (boundary \(\psi\), weak axes) after the fit. The rule is a necessary count, not a recovery guarantee. Replication within a unit, orunique = FALSE, changes the count.- unique
Logical;
TRUE(default) auto-includes the diagonal trait-specific \(\boldsymbol\Psi\) companion (\(\boldsymbol\Sigma = \boldsymbol\Lambda\boldsymbol\Lambda^\top + \boldsymbol\Psi\)). SetFALSEfor the loadings-only / rotation-invariant subset. The former argument nameresidualis retained as a soft-deprecated alias.- common
Logical;
FALSE(default) estimates one diagonal \(\boldsymbol\Psi\) variance per trait.TRUEties the default ordinary diagonal \(\boldsymbol\Psi\) companion to one shared variance across traits. Only applies whenunique = TRUE.- lv
One-sided formula for predictor-informed latent-score means. The model matrix retains the formula's factor contrasts, then its intercept column is removed. With default treatment contrasts,
lv = ~ groupestimates differences from the factor reference level. Usestats::relevel()to select that level. Designs spanning a constant, includinglv = ~ 0 + group, violate the no-LV-intercept contract and are rejected. Numericlv = ~ xandlv = ~ 0 + xare equivalent. Runtime support is limited to ordinary unit-tierlatent(..., lv = ~ x). Registered native family/link rows compose in one complete-response ordinary unit-tier block. The loadings-onlyunique = FALSEform admits ranks through the number of logical responses; automaticPsiadditionally requires that its physical loading, latent-predictor, and engine-free diagonal parameters pass a necessary joint mean-covariance dimension screen. Passing that screen is not a recovery or interval-calibration certificate. Bounded rank-2/rank-3 canaries exercise every registered family, but broad composition recovery and interval calibration remain partial. Retained recovery and interval claims remain limited to their named cells. Source-specific*_latent(..., lv = ~ x)forms are parsed and then fail loud (not yet fittable). Where it is admitted, the fit is experimental and exploratory: extract the coefficients withextract_lv_effects(), whose defaulttype = "axis_effect"output is rotation-dependent (an intrinsic latent-axis indeterminacy, not a defect – seeextract_lv_effects()for the rotation-invarianttype = "trait_effect"alternative). Repeated-sampling interval evidence is cell-specific; do not infer an interval claim for the mixed-response programme from its point-recovery evidence.
Details
Used inside a gllvmTMB() formula:
value ~ 0 + trait + latent(0 + trait | unit, d = 2)By default, ordinary latent() now fits the canonical decomposition
\(\boldsymbol\Sigma = \boldsymbol\Lambda \boldsymbol\Lambda^\top + \boldsymbol\Psi\),
with the diagonal \(\boldsymbol\Psi\) companion included automatically:
value ~ 0 + trait + latent(0 + trait | unit, d = 2)Set unique = FALSE for the loadings-only subset.
For a scalar diagonal \(\boldsymbol\Psi\) companion shared across traits,
use common = TRUE; this replaces the older two-term spelling for
ordinary intercept-only latent terms.
See also
indep(), phylo_latent(), diag_re, extract_Sigma(),
extract_lv_effects() for predictor-informed latent-score coefficients.
Examples
# Six traits on 60 units (3 replicate observations per unit): the
# between-unit trait covariance is rank two plus a trait-specific diagonal.
Lambda <- matrix(c(0.9, 0.7, 0.5, -0.4, 0.3, 0,
0, 0.2, -0.3, 0.6, 0.7, 0.8), ncol = 2)
sim <- simulate_unit_trait(
n_units = 60, n_obs_per_unit = 3, n_traits = 6,
Lambda_B = Lambda, psi_B = rep(0.2, 6), seed = 1
)
# A 2-factor latent random effect at `unit`. Ordinary latent() carries its
# diagonal Psi by default (Sigma = Lambda Lambda^T + diag(psi)).
# \donttest{
fit <- gllvmTMB(
value ~ 0 + trait + latent(0 + trait | unit, d = 2),
data = sim$data, trait = "trait", unit = "unit"
)
extract_Sigma(fit)
#> $Sigma
#> trait_1 trait_2 trait_3 trait_4 trait_5 trait_6
#> trait_1 0.89381316 0.44527987 0.36182863 -0.17721641 0.28293618 0.08033305
#> trait_2 0.44527987 0.51381104 0.21102198 -0.06556966 0.22560004 0.11821218
#> trait_3 0.36182863 0.21102198 0.39961843 -0.23329437 0.01518318 -0.15571942
#> trait_4 -0.17721641 -0.06556966 -0.23329437 0.62308156 0.23669108 0.44183860
#> trait_5 0.28293618 0.22560004 0.01518318 0.23669108 0.56530768 0.46443667
#> trait_6 0.08033305 0.11821218 -0.15571942 0.44183860 0.46443667 0.69556687
#>
#> $R
#> trait_1 trait_2 trait_3 trait_4 trait_5 trait_6
#> trait_1 1.0000000 0.6570645 0.60542005 -0.2374697 0.39803629 0.1018829
#> trait_2 0.6570645 1.0000000 0.46569677 -0.1158854 0.41859594 0.1977384
#> trait_3 0.6054200 0.4656968 1.00000000 -0.4675295 0.03194461 -0.2953592
#> trait_4 -0.2374697 -0.1158854 -0.46752954 1.0000000 0.39881088 0.6711534
#> trait_5 0.3980363 0.4185959 0.03194461 0.3988109 1.00000000 0.7406527
#> trait_6 0.1018829 0.1977384 -0.29535925 0.6711534 0.74065271 1.0000000
#>
#> $level
#> [1] "unit"
#>
#> $part
#> [1] "total"
#>
#> $note
#> character(0)
#>
# }