Skip to contents

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.

shared

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 = 1 for simple unmeasured confounding

  • Use n_factors = 2-3 if you suspect multiple independent confounders

  • More 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)
)
} # }