
Suggest a lambda_constraint matrix for a reduced-rank fit
Source: R/suggest-lambda-constraint.R
suggest_lambda_constraint.RdProduces a default constraint matrix M for the reduced-rank loadings
Lambda in a fit returned by gllvmTMB() or in a formula-data pair that will
be passed to gllvmTMB(). The matrix is returned in the format expected by
the lambda_constraint argument: NA in free entries, numeric values in
pinned entries. This function supplies an identification convention – an
orientation/scale scaffold that resolves rotational ambiguity – and does
not discover biological factor structure; a low or pinned loading is a
constraint choice or a result to interpret, not by itself grounds to
exclude a trait.
Usage
suggest_lambda_constraint(
fit_or_formula,
data = NULL,
level = "unit",
convention = c("lower_triangular", "pin_top_one", "none", "varimax_threshold",
"wald_retention", "profile_retention"),
trait = "trait",
unit = NULL,
threshold = 0.3,
retention_prob = 0.9,
sigma_d2 = 1,
site = NULL
)Arguments
- fit_or_formula
Either a fitted multivariate model returned by
gllvmTMB()or a formula. If a formula,datamust also be supplied.- data
A data frame. Required when
fit_or_formulais a formula; ignored when it is a fit.- level
Which loading matrix to constrain:
"unit"(between-unit, default) or"unit_obs"(within-unit). Deprecated aliases"B"and"W"are still accepted with a warning.- convention
One of:
"lower_triangular"(default)Pin every upper-triangular entry to 0, i.e.
M[i, j] = 0forj > i. Removes the rotational ambiguity completely. PinsK(K-1)/2entries."pin_top_one"Single-anchor convention:
M[1, 1] = 1, restNA. Sets the scale of factor 1; does NOT remove rotational ambiguity."none"All-
NAmatrix – no pins. Useful if you plan to rotate the fitted loadings after fitting instead.
- trait, unit
Name of the trait and unit (site) columns. Forwarded when
fit_or_formulais a formula and the data does not already use defaults.- threshold
Salience threshold on the standardised loading \(\rho_{tk} = \Lambda_{tk} / \sqrt{\Sigma_{total,tt}}\). Used by
"varimax_threshold"and"wald_retention". Comrey-Lee 1992 convention: 0.30 = "fair" salience (default). Must be a finite scalar in[0, 1). Raise to 0.40 for "good" / 0.50 for "very good".- retention_prob
Retention probability for
"wald_retention"and"profile_retention":"wald_retention": pin entry ifPr(|rho| > threshold) < retention_prob."profile_retention": pin entry if a profile LRT fails to rejectH0: Lambda = 0at significance level1 - retention_prob.
Must be a finite scalar in
(0, 1). Default 0.90 follows the applied-EFA bootstrap convention; the stricter BSEM 0.95 often over-prunes at moderate sample sizes and produces non-PD refits.- sigma_d2
Deprecated compatibility argument; ignored by the standardised-loading conventions. Their denominators now come from the model-implied total variance returned by
extract_Sigma().- site
Deprecated alias for
unit. Emits a one-shot warning and maps tounit.
Value
A list with components:
constraintA
T x Kmatrix withNAin free entries and 0 (or 1, for"pin_top_one") in pinned entries. Has trait names as rownames and"f1", ..., "fK"as colnames.conventionThe chosen convention.
dThe number of factors
K.n_pinsNumber of pinned entries.
noteA short explanation of what was pinned and why.
usage_hintAn example call as a string showing how to use the returned matrix with
gllvmTMB().
Examples
set.seed(1)
# Simulate six traits measured twice on each of 100 units, with two
# latent axes: traits 1-3 load on the first, traits 4-6 on the second.
Lambda <- cbind(c(0.9, 0.8, 0.7, 0.0, 0.0, 0.0),
c(0.0, 0.0, 0.0, 0.8, 0.7, 0.6))
sim <- simulate_unit_trait(n_units = 100, n_obs_per_unit = 2,
n_traits = 6, Lambda_B = Lambda,
psi_B = 0.3, sigma2_eps = 0.3)
form <- value ~ 0 + trait +
latent(0 + trait | unit, d = 2, unique = TRUE)
# Before fitting: suggest a constraint matrix for the 6 x 2 loadings
# (NA = estimated, 0 = pinned). With two axes, one zero is enough to
# stop the axes from rotating freely.
sug <- suggest_lambda_constraint(form, data = sim$data, unit = "unit")
sug$constraint
#> f1 f2
#> trait_1 NA 0
#> trait_2 NA NA
#> trait_3 NA NA
#> trait_4 NA NA
#> trait_5 NA NA
#> trait_6 NA NA
sug$note
#> [1] "Pinned the K(K-1)/2 = 1 upper-triangular entries of Lambda to 0 (lower-triangular convention). Removes the rotational ambiguity completely."
# Fit with the matrix: trait_1's loading on axis 2 is held at zero and
# the other loadings are estimated. gllvmTMB uses this same orientation
# when no matrix is given, so the estimates do not change; passing the
# matrix states the choice explicitly. The orientation is only a
# convention; rotate_loadings() gives a more interpretable one.
fit <- gllvmTMB(form, data = sim$data, trait = "trait", unit = "unit",
lambda_constraint = list(unit = sug$constraint))
round(extract_loadings(fit, level = "unit"), 2)
#> LV1 LV2
#> trait_1 0.81 0.00
#> trait_2 0.72 0.15
#> trait_3 0.82 0.24
#> trait_4 -0.21 0.76
#> trait_5 -0.11 0.61
#> trait_6 -0.05 0.66