Define latent factors for capturing unmeasured shared structure between
numerator and denominator. Factors are observation-level random effects
that enter both linear predictors when shared = TRUE (default).
Usage
latent_factor(
n_factors = 1L,
prior = NULL,
shared = TRUE,
constraint = c("sum_to_zero", "first_zero"),
scale = TRUE
)Arguments
- n_factors
Integer; number of latent factors. Default is 1. More factors capture more complex unmeasured structure but increase computational cost and risk overfitting.
- prior
Prior for factor standard deviations. Default is a PC prior with P(sigma > 1) = 0.01, which shrinks toward simpler models.
Logical; if TRUE (default), latent factors enter both numerator and denominator linear predictors identically. If FALSE, factors only affect the numerator.
- constraint
Identifiability constraint for factors:
"sum_to_zero"(default): Factors sum to zero across observations"first_zero": First observation's factor is fixed to zero
- scale
Logical; if TRUE (default), factor loadings are standardized to have unit variance before applying sigma.
Value
A ratiod_latent object for use in tratio().
Details
Why Use Latent Factors?
When modeling ratios, the numerator and denominator often share unmeasured confounders. For example, in relative abundance data, both the focal species count and total count might be affected by:
Observer skill (unmeasured)
Local microhabitat conditions (unmeasured)
Weather on sampling day (unmeasured)
Without accounting for these shared drivers, ratio estimates can be biased. Latent factors capture this shared structure without requiring the confounders to be measured.
Mathematical Model
For observation i with K latent factors:
$$\eta^{num}_i = X^{num}_i \beta^{num} + \sum_{k=1}^{K} f_{ik} \sigma_k + \ldots$$ $$\eta^{denom}_i = X^{denom}_i \beta^{denom} + \sum_{k=1}^{K} f_{ik} \sigma_k + \ldots$$
where:
\(f_{ik} \sim N(0, 1)\) are standardized factor scores
\(\sigma_k\) are factor standard deviations with PC prior
Identifiability: \(\sum_i f_{ik} = 0\) for each k
Because factors enter both linear predictors identically (when shared), they cancel in the ratio:
$$ratio_i = \exp(\eta^{num}_i - \eta^{denom}_i)$$
This means factors capture shared multiplicative effects that would otherwise bias the ratio.
Choosing n_factors
Start with
n_factors = 1for simple unmeasured confoundingUse
n_factors = 2-3if you suspect multiple independent confoundersMore than 3 factors is rarely needed and risks overfitting
The PC prior provides regularization, shrinking unneeded factors toward zero
Relationship to Random Effects
Latent factors differ from random effects in several ways:
Random effects are grouped (e.g., site-level), factors are observation-level
Random effects require grouping structure, factors don't
Factors capture residual correlation not explained by observed predictors
You can use both together: random effects for known grouping, factors for residual unmeasured confounding.
See also
tratio() for model fitting, prior_pc() for prior specification
Examples
# Basic latent factor (single shared factor)
latent_factor()
#> Latent factor specification
#> ===========================
#>
#> Number of factors: 1
#> Shared: Yes (enters both num and denom)
#> Constraint: sum_to_zero
#> Scale: Yes
#>
#> Factor SD prior:
#> PC prior: P(x > 1.00) = 0.010
#> => Exponential(4.605)
# Two latent factors
latent_factor(n_factors = 2)
#> Latent factor specification
#> ===========================
#>
#> Number of factors: 2
#> Shared: Yes (enters both num and denom)
#> Constraint: sum_to_zero
#> Scale: Yes
#>
#> Factor SD prior:
#> PC prior: P(x > 1.00) = 0.010
#> => Exponential(4.605)
# Custom prior (more regularization)
latent_factor(n_factors = 1, prior = prior_pc(U = 0.5, alpha = 0.01))
#> Latent factor specification
#> ===========================
#>
#> Number of factors: 1
#> Shared: Yes (enters both num and denom)
#> Constraint: sum_to_zero
#> Scale: Yes
#>
#> Factor SD prior:
#> PC prior: P(x > 0.50) = 0.010
#> => Exponential(9.210)
# Numerator-only factor (not shared)
latent_factor(n_factors = 1, shared = FALSE)
#> Latent factor specification
#> ===========================
#>
#> Number of factors: 1
#> Shared: No (numerator only)
#> Constraint: sum_to_zero
#> Scale: Yes
#>
#> Factor SD prior:
#> PC prior: P(x > 1.00) = 0.010
#> => Exponential(4.605)
if (FALSE) { # \dontrun{
# Use in model fitting
fit <- tratio(
species_count | total_count ~ habitat + (1 | site),
data = df,
family = ratiod_negbin_negbin(),
latent = latent_factor(n_factors = 2)
)
} # }