
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.89379213 0.44528231 0.36182285 -0.17720657 0.28293309 0.08033562
#> trait_2 0.44528231 0.51382125 0.21102915 -0.06557509 0.22559646 0.11820257
#> trait_3 0.36182285 0.21102915 0.39962633 -0.23329927 0.01517766 -0.15572311
#> trait_4 -0.17720657 -0.06557509 -0.23329927 0.62308877 0.23669856 0.44183801
#> trait_5 0.28293309 0.22559646 0.01517766 0.23669856 0.56530303 0.46443061
#> trait_6 0.08033562 0.11820257 -0.15572311 0.44183801 0.46443061 0.69555420
#>
#> $R
#> trait_1 trait_2 trait_3 trait_4 trait_5 trait_6
#> trait_1 1.0000000 0.6570693 0.60541153 -0.2374579 0.39803827 0.1018883
#> trait_2 0.6570693 1.0000000 0.46570335 -0.1158932 0.41858686 0.1977222
#> trait_3 0.6054115 0.4657034 1.00000000 -0.4675320 0.03193281 -0.2953660
#> trait_4 -0.2374579 -0.1158932 -0.46753204 1.0000000 0.39882282 0.6711547
#> trait_5 0.3980383 0.4185869 0.03193281 0.3988228 1.00000000 0.7406528
#> trait_6 0.1018883 0.1977222 -0.29536602 0.6711547 0.74065283 1.0000000
#>
#> $level
#> [1] "unit"
#>
#> $part
#> [1] "total"
#>
#> $note
#> character(0)
#>
# }