#' Define a Common Latent Factor for the \pkg{dynamite} Model.
#'
#' This function can be used as part of a [dynamiteformula()] to define
#' a common latent factor component. The latent factor is modeled as a spline
#' similarly as a time-varying intercept, but instead of having equal effect on
#' each group, there is an additional loading variable for each group so that
#' in the linear predictor we have a term \eqn{\lambda_i \psi_t} for each
#' group \eqn{i}.
#' @export
#' @family formulas
#' @param responses \[`character()`]\cr Names of the responses that the
#' factor should affect. Default is all responses defined with
#' `obs` except categorical responses, which do not (yet) support the factor
#' component.
#' @param nonzero_lambda \[`logical()`]\cr If `TRUE` (the default), assumes
#' that the mean of factor loadings is nonzero or not. Should be a logical
#' vector matching the length of `responses` or a single logical value in
#' case `responses` is `NULL`. See details.
#' @param correlated \[`logical()`]\cr If `TRUE` (the default), the latent
#' factors are assumed to be correlated between channels.
#' @param noncentered_psi \[`logical(1)`]\cr If `TRUE`, uses a
#' noncentered parametrization for spline coefficients of all the factors.
#' The number of knots is based `splines()` call. Default is `FALSE`.
#' @param flip_sign \[`logical(1)`]\cr If `TRUE` (default), try to avoid
#' multimodality due to sign-switching by defining the sign of \eqn{\lambda}
#' and \eqn{\psi} based on the mean of \eqn{\omega_1,\ldots, \omega_D}
#' coefficients. This only affects channels with `nonzero_lambda = FALSE`.
#' If the true mean of \eqn{\omega}s is close to zero, this might not help,
#' in which case it is better to set `flip_sign = FALSE` and post-process the
#' samples in other ways (or use only one chain and/or suitable initial
#' values). This argument is common to all factors.
#' @return An object of class `latent_factor`.
#' @examples
#' data.table::setDTthreads(1) # For CRAN
#' # three channel model with common factor affecting for responses x and y
#' obs(y ~ 1, family = "gaussian") +
#' obs(x ~ 1, family = "poisson") +
#' obs(z ~ 1, family = "gaussian") +
#' lfactor(
#' responses = c("y", "x"), nonzero_lambda = c(TRUE, FALSE),
#' correlated = TRUE, noncentered_psi = FALSE
#' )
#'
lfactor <- function(responses = NULL, nonzero_lambda = TRUE, correlated = TRUE,
noncentered_psi = FALSE, flip_sign = TRUE) {
stopifnot_(
checkmate::test_character(x = responses, min.len = 1L, null.ok = TRUE),
"Argument {.arg responses} must be a {.cls character} vector."
)
stopifnot_(
checkmate::test_logical(
x = noncentered_psi,
any.missing = FALSE,
len = 1
),
"Argument {.arg noncentered_psi} must be a single {.cls logical} value."
)
stopifnot_(
checkmate::test_logical(
x = flip_sign,
any.missing = FALSE,
len = 1
),
"Argument {.arg flip_sign} must be a single {.cls logical} value."
)
stopifnot_(
checkmate::test_logical(
x = nonzero_lambda,
any.missing = FALSE,
min.len = 1L
),
"Argument {.arg nonzero_lambda} must be a {.cls logical} vector."
)
stopifnot_(
checkmate::test_logical(
x = correlated,
any.missing = FALSE,
len = 1
),
"Argument {.arg correlated} must be a single {.cls logical} value."
)
structure(
list(
responses = responses,
nonzero_lambda = nonzero_lambda,
correlated = correlated,
noncentered_psi = noncentered_psi,
flip_sign = flip_sign
),
class = "latent_factor"
)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.