#' @srrstats {G5.8,G5.8a, G5.8b, G5.8c, G5.8d} Edge conditions are tested.
data.table::setDTthreads(1) # For CRAN
# Model edgecases ---------------------------------------------------------
set.seed(0)
timepoints <- 10
individuals <- 5
total_obs <- timepoints * individuals
test_data <- data.frame(
group = gl(individuals, timepoints),
time = 1:timepoints,
offset = sample(50:100, size = total_obs, replace = TRUE),
trials = sample(50:100, size = total_obs, replace = TRUE)
) |>
dplyr::mutate(
y1 = as.factor(sample(5, size = total_obs, replace = TRUE)),
y2 = rnorm(n = total_obs, mean = 1, sd = 2),
y3 = rbinom(n = total_obs, size = trials, prob = 0.75),
y4 = rbinom(n = total_obs, size = 1, prob = 0.66),
y5 = rnbinom(n = total_obs, size = 100, prob = 0.33),
y6 = rpois(n = total_obs, lambda = log(offset) + 1),
y7 = rexp(n = total_obs, rate = 0.1),
y8 = rgamma(n = total_obs, shape = 2, rate = 2 * exp(-5)),
y9 = rbeta(n = total_obs, 6, 4),
x1 = sample(letters[1:4], size = total_obs, replace = TRUE),
x2 = rnorm(total_obs),
x3 = as.factor(sample(4, size = total_obs, replace = TRUE))
)
debug <- list(no_compile = TRUE)
test_that("family-specific model formulas are valid", {
# Model formulas
expect_error(
obs_categorical <- obs(y1 ~ x1, family = "categorical"), NA
)
expect_error(
obs_gaussian <- obs(y2 ~ x2, family = "gaussian"), NA
)
expect_error(
obs_mvgaussian <- obs(c(y2, y8) ~ x2, family = "mvgaussian"), NA
)
expect_error(
obs_binomial <- obs(y3 ~ x3 + trials(trials), family = "binomial"), NA
)
expect_error(
obs_bernoulli <- obs(y4 ~ x1, family = "bernoulli"), NA
)
expect_error(
obs_negbinom <- obs(y5 ~ x2, family = "negbin"), NA
)
expect_error(
obs_poisson <- obs(y6 ~ x3 + offset(offset), family = "poisson"), NA
)
expect_error(
obs_exponential <- obs(y7 ~ x3, family = "exponential"), NA
)
expect_error(
obs_gamma <- obs(y8 ~ x1, family = "gamma"), NA
)
expect_error(
obs_beta <- obs(y9 ~ x3, family = "beta"), NA
)
expect_error(
obs_student <- obs(y2 ~ x2, family = "student"), NA
)
expect_error(
obs_multinomial <- obs(
c(y3, y4, y5) ~ x2 + trials(trials),
family = "multinomial"
),
NA
)
# Stan data
expect_error(
dynamite(obs_categorical, test_data, "time", "group", debug = debug), NA
)
expect_error(
dynamite(obs_gaussian, test_data, "time", "group", debug = debug), NA
)
expect_error(
dynamite(obs_mvgaussian, test_data, "time", "group", debug = debug), NA
)
expect_error(
dynamite(obs_binomial, test_data, "time", "group", debug = debug), NA
)
expect_error(
dynamite(obs_bernoulli, test_data, "time", "group", debug = debug), NA
)
expect_error(
dynamite(obs_negbinom, test_data, "time", "group", debug = debug), NA
)
expect_error(
dynamite(obs_poisson, test_data, "time", "group", debug = debug), NA
)
expect_error(
dynamite(obs_exponential, test_data, "time", "group", debug = debug), NA
)
expect_error(
dynamite(obs_gamma, test_data, "time", "group", debug = debug), NA
)
expect_error(
dynamite(obs_beta, test_data, "time", "group", debug = debug), NA
)
expect_error(
dynamite(obs_student, test_data, "time", "group", debug = debug), NA
)
expect_error(
dynamite(obs_multinomial, test_data, "time", "group", debug = debug), NA
)
})
test_that("multichannel models are valid", {
expect_error(
obs_all <- obs(y1 ~ x1, family = "categorical") +
obs(y2 ~ x2, family = "gaussian") +
obs(y3 ~ x3 + trials(trials), family = "binomial") +
obs(y4 ~ x1, family = "bernoulli") +
obs(y5 ~ x2, family = "negbin") +
obs(y6 ~ x3 + offset(offset), family = "poisson") +
obs(y7 ~ x3, family = "exponential") +
obs(y8 ~ x1, family = "gamma") +
obs(y9 ~ x1, family = "beta"),
NA
)
expect_error(
dynamite(obs_all, test_data, "time", "group", debug = debug), NA
)
})
test_that("binomial with trials only works", {
expect_error(
obs_binomial <- obs(y3 ~ trials(trials), family = "binomial"), NA
)
expect_error(
dynamite(obs_binomial, test_data, "time", "group", debug = debug), NA
)
})
test_that("intercepts are handled correctly", {
expect_error(
obs_all_alpha <- obs(y1 ~ -1 + x1, family = "categorical") +
obs(y2 ~ -1 + x2 + varying(~1), family = "gaussian") +
obs(y3 ~ -1 + x3 + varying(~x1) + trials(trials), family = "binomial") +
obs(y4 ~ x1 + varying(~ -1 + x2), family = "bernoulli") +
splines(df = 5),
NA
)
expect_error(
dynamite(obs_all_alpha, test_data, "time", "group", debug = debug), NA
)
})
test_that("random effects are handled correctly", {
expect_error(
obs_all_alpha <- obs(y2 ~ -1 + x2 + varying(~1) + random(~1),
family = "gaussian") +
obs(y3 ~ -1 + x3 + varying(~x1) + trials(trials) + random(~1),
family = "binomial") +
obs(y4 ~ x1 + varying(~ -1 + x2), family = "bernoulli") +
splines(df = 5) + random_spec(correlated = TRUE, noncentered = TRUE),
NA
)
expect_equal(
c("sigma_nu_y2_alpha", "sigma_nu_y3_alpha", "L_nu"),
get_priors(obs_all_alpha, test_data, "time", "group")$parameter[c(1, 6, 24)]
)
expect_error(
obs_all_alpha <- obs(y2 ~ -1 + x2 + varying(~1) + random(~1),
family = "gaussian") +
obs(y3 ~ -1 + x3 + varying(~x1) + trials(trials) + random(~x1),
family = "binomial") +
obs(y4 ~ x1 + varying(~ -1 + x2) + random(~ x1 + x2),
family = "bernoulli") +
splines(df = 5) + random_spec(correlated = FALSE),
NA
)
expect_error(
obs_all_alpha <- obs(y2 ~ -1 + x2 + varying(~1) + random(~x2),
family = "gaussian") +
obs(y3 ~ -1 + x3 + varying(~x1) + trials(trials) + random(~1),
family = "binomial") +
obs(y4 ~ x1 + varying(~ -1 + x2), family = "bernoulli") +
splines(df = 5) + random_spec(correlated = FALSE, noncentered = FALSE),
NA
)
expect_error(
obs_all_alpha <- obs(y2 ~ -1 + x2 + varying(~1), family = "gaussian") +
obs(y3 ~ -1 + x3 + varying(~x1) + trials(trials) + random(~1),
family = "binomial") +
obs(y4 ~ x1 + varying(~ -1 + x2) + random(~ -1 + x1),
family = "bernoulli") +
splines(df = 5) + random_spec(correlated = TRUE, noncentered = FALSE),
NA
)
expect_error(
obs_all_alpha <- obs(y2 ~ -1 + x2 + varying(~1), family = "gaussian") +
obs(y3 ~ -1 + x3 + varying(~x1) + trials(trials) + random(~1),
family = "binomial") +
obs(y4 ~ x1 + varying(~ -1 + x2) + random(~ -1 + x1),
family = "bernoulli") +
splines(df = 5),
NA
)
expect_error(
obs_all_alpha <- obs(y2 ~ 1, family = "gaussian") +
obs(y3 ~ trials(trials) + random(~1), family = "binomial") +
obs(y4 ~ x1 + random(~x1), family = "bernoulli"),
NA
)
expect_error(
obs_all_alpha <- obs(y2 ~ x2 + random(~1), family = "gaussian") +
random_spec(),
NA
)
expect_false(
"L_nu" %in% get_priors(obs_all_alpha, test_data, "time", "group")$parameter
)
})
test_that("shrinkage is handled correctly", {
skip("Shrinkage feature removed at least for now.")
expect_error(
obs_all_alpha <- obs(y1 ~ -1 + varying(~x1), family = "categorical") +
obs(x3 ~ varying(~ -1 + x1), family = "categorical") +
obs(y2 ~ -1 + x2 + varying(~1), family = "gaussian") +
obs(y3 ~ lag(x3) + trials(trials), family = "binomial") +
obs(y4 ~ x1 + varying(~ -1 + x2), family = "bernoulli") +
obs(y9 ~ -1 + x1 + varying(~x2), family = "beta") +
splines(df = 5, shrinkage = TRUE),
NA
)
expect_equal(
unname(
unlist(
lapply(
dynamite(
obs_all_alpha,
test_data,
"time",
"group",
debug = debug
)$stan$channel_vars, "[[", "shrinkage"
)
)
),
rep(TRUE, 6)
)
expect_equal(
get_priors(
obs_all_alpha,
test_data,
"time",
"group"
)$parameter[76],
"xi"
)
})
test_that("noncentered splines are handled correctly", {
expect_error(
obs_all_alpha <- obs(y1 ~ -1 + varying(~x1), family = "categorical") +
obs(x3 ~ varying(~ -1 + x1), family = "categorical") +
obs(y2 ~ -1 + x2 + varying(~1), family = "gaussian") +
obs(y3 ~ lag(x3) + trials(trials), family = "binomial") +
obs(y4 ~ x1 + varying(~ -1 + x2), family = "bernoulli") +
obs(y9 ~ -1 + x1 + varying(~x2), family = "beta") +
splines(df = 5, noncentered = rep(TRUE, 6)),
NA
)
expect_equal(
unname(
unlist(
lapply(
dynamite(
obs_all_alpha,
test_data,
"time",
"group",
debug = debug
)$stan$channel_vars,
"[[",
"noncentered"
)
)
),
rep(TRUE, 6)
)
})
test_that("lower bounds for tau are handled correctly", {
expect_error(
obs_all_alpha <- obs(y1 ~ -+x1, family = "categorical") +
obs(y2 ~ -1 + x2 + varying(~1), family = "gaussian") +
obs(y3 ~ -1 + x3 + varying(~x1) + trials(trials), family = "binomial") +
obs(y4 ~ x1 + varying(~ -1 + x2), family = "bernoulli") +
obs(y9 ~ -1 + x1 + varying(~x2), family = "beta") +
splines(df = 5, lb_tau = c(0, 2, 1, 0.4, 0.01)),
NA
)
expect_equal(
lapply(
dynamite(
obs_all_alpha,
test_data,
"time", "group",
debug = debug
)$stan$channel_vars,
"[[",
"lb"
),
list(y1 = 0, y2 = 2, y3 = 1, y4 = 0.4, y9 = 0.01)
)
})
test_that("manual fixed() terms work", {
expect_error(
obs_fixed <- obs(y1 ~ fixed(~ x1 + lag(y2, 1)), family = "categorical"),
NA
)
})
test_that("latent factors are handled correctly", {
expect_error(
obs_all_lfactor <- obs(y2 ~ -1 + x2, family = "gaussian") +
obs(y3 ~ -1 + x3 + varying(~x1) + trials(trials), family = "binomial") +
obs(y4 ~ x1 + varying(~ -1 + x2), family = "bernoulli") +
splines(df = 5) +
lfactor(c("y2", "y3"), nonzero_lambda = c(TRUE, FALSE)),
NA
)
expect_equal(
c(
"zeta_y2", "kappa_y2", "psi_y2", "sigma_lambda_y3", "psi_y3", "L_lf"
),
get_priors(obs_all_lfactor, test_data, "time", "group")$parameter[
c(1:3, 6:7, 25)
]
)
})
# Lag edgecases -----------------------------------------------------------
test_that("lags are parsed", {
expect_error(
obs_a <- obs(y1 ~ x1 + lag(y2, 1), family = "categorical") +
obs(y2 ~ x2 + lag(y1, 1), family = "gaussian"),
NA
)
expect_error(
obs_b <- obs(
y1 ~ -1 + x1 + varying(~ lag(y2, 1)),
family = "categorical"
) +
obs(y2 ~ -1 + x2 + varying(~ lag(y1, 1)), family = "gaussian") +
splines(),
NA
)
expect_error(
obs_c <- obs(y1 ~ x1, family = "categorical") +
obs(y2 ~ x2, family = "gaussian") +
lags(k = 1, type = "fixed"),
NA
)
expect_error(
obs_d <- obs(y1 ~ x1, family = "categorical") +
obs(y2 ~ x2, family = "gaussian") +
lags(k = 1, type = "varying") +
splines(),
NA
)
expect_error(
dynamite(obs_a, test_data, "time", "group", debug = debug), NA
)
expect_error(
dynamite(obs_b, test_data, "time", "group", debug = debug), NA
)
expect_error(
dynamite(obs_c, test_data, "time", "group", debug = debug), NA
)
expect_error(
dynamite(obs_d, test_data, "time", "group", debug = debug), NA
)
})
test_that("lag without explicit shift equal shift of one", {
expect_identical(extract_lags("lag(y)")$k, 1L)
})
test_that("lags() and lag() give equal results", {
f1 <- expect_error(
obs(y1 ~ x1, family = "categorical") +
obs(y2 ~ x2, family = "gaussian") +
lags(k = 1, type = "fixed"),
NA
)
f2 <- expect_error(
obs(y1 ~ x1 + lag(y1) + lag(y2), family = "categorical") +
obs(y2 ~ x2 + lag(y1) + lag(y2), family = "gaussian"),
NA
)
expect_identical(
get_priors(f1, test_data, "time", "group"),
get_priors(f2, test_data, "time", "group")
)
})
test_that("higher order lags() and lag() give equal results", {
f1 <- obs(y1 ~ x1, family = "categorical") +
obs(y2 ~ x2, family = "gaussian") +
lags(k = 1:2, type = "fixed")
f2 <- obs(y1 ~ x1 + lag(y1, 1) + lag(y2, 1) +
lag(y1, 2) + lag(y2, 2), family = "categorical") +
obs(y2 ~ x2 + lag(y1, 1) + lag(y2, 1) +
lag(y1, 2) + lag(y2, 2), family = "gaussian")
expect_identical(
get_priors(f1, test_data, "time", "group"),
get_priors(f2, test_data, "time", "group")
)
})
test_that("disjoint and intersecting lags() ang lag() give equal results", {
f1 <- obs(y2 ~ x2, family = "gaussian") +
obs(y7 ~ x2 + lag(y2), family = "exponential") +
lags(k = 1L)
f2 <- obs(y2 ~ x2, family = "gaussian") +
obs(y7 ~ x2, family = "exponential") +
lags(k = 1L)
expect_identical(
get_priors(f1, test_data, "time", "group"),
get_priors(f2, test_data, "time", "group")
)
})
test_that("lags() is ignored if all lags already exist", {
f1 <- obs(y2 ~ x2 + lag(y2) + lag(y7), family = "gaussian") +
obs(y7 ~ x2 + lag(y2) + lag(y7), family = "exponential") +
lags(k = 1L)
f2 <- obs(y2 ~ x2 + lag(y2) + lag(y7), family = "gaussian") +
obs(y7 ~ x2 + lag(y2) + lag(y7), family = "exponential")
expect_identical(
get_priors(f1, test_data, "time", "group"),
get_priors(f2, test_data, "time", "group")
)
})
# Data edgecases ----------------------------------------------------------
test_that("data expansion to full time scale works", {
set.seed(0)
# groups
mis_rows <- sample(2L:(nrow(test_data) - 1L), 10)
test_data_mis <- test_data[-mis_rows, ]
fit <- dynamite(
obs(
y2 ~ x1 + x2 + x3 + y1 + y3 + y4 + y5 + y6 + y7 + y8 + y9,
family = "gaussian"
),
data = test_data_mis,
time = "time",
group = "group",
verbose = FALSE,
debug = debug
)
expected_data <- test_data
expected_data[mis_rows, seq(3, ncol(test_data))] <- NA
expected_data$x1 <- factor(expected_data$x1)
expected_data <- droplevels(expected_data)
expected_data$trials <- NULL
expected_data$offset <- NULL
data.table::setDT(expected_data, key = c("group", "time"))
expect_equal(fit$data, expected_data, ignore_attr = TRUE)
# no groups
test_data_single <- test_data[test_data[["group"]] == 1L, ]
mis_rows_single <- c(3, 5, 6, 9)
test_data_single_mis <- test_data_single[-mis_rows_single, ]
fit_single <- dynamite(
obs(
y2 ~ x1 + x2 + x3 + y1 + y3 + y4 + y5 + y6 + y7 + y8 + y9,
family = "gaussian"
),
data = test_data_single_mis,
time = "time",
verbose = FALSE,
debug = debug
)
expected_data_single <- test_data_single
expected_data_single[mis_rows_single, seq(3, ncol(test_data_single))] <- NA
expected_data_single$x1 <- factor(expected_data_single$x1)
expected_data_single <- droplevels(expected_data_single)
expected_data_single$trials <- NULL
expected_data_single$offset <- NULL
expected_data_single$group <- NULL
expected_data_single$.group <- 1L
data.table::setDT(expected_data_single, key = c("time"))
expect_equal(fit_single$data, expected_data_single, ignore_attr = TRUE)
})
test_that("no groups data preparation works", {
test_data_single <- test_data |>
dplyr::filter(.data$group == 1) |>
dplyr::select(!"group")
obs_all <- obs(y1 ~ x2 + lag(y1), family = "categorical") +
obs(y2 ~ x2, family = "gaussian") +
obs(y3 ~ x3 + trials(trials), family = "binomial") +
obs(y4 ~ x1, family = "bernoulli") +
obs(y5 ~ x2, family = "negbin") +
obs(y6 ~ x3 + offset(offset), family = "poisson") +
obs(y7 ~ x3, family = "exponential") +
obs(y8 ~ x1, family = "gamma")
expect_error(
dynamite(obs_all, test_data_single, time = "time", debug = debug),
NA
)
})
test_that("no groups group variable name generation works", {
d <- gaussian_example |> dplyr::filter(id == 1)
d$.group <- d$x
d$x <- NULL
expect_error(
fit <- dynamite(
dformula =
obs(y ~ -1 + z + varying(~ .group + lag(y)), family = "gaussian") +
random_spec() +
splines(df = 20),
data = d,
time = "time",
debug = list(no_compile = TRUE)
),
NA
)
expect_identical(fit$group_var, ".group_")
expect_true(all(fit$data[[fit$group_var]] == 1L))
})
# Deterministic edgecases -------------------------------------------------
test_that("deterministic channels are parsed", {
expect_error(
obs_det <- obs(
y5 ~ x1 + lag(d, 1) + lag(y5, 1) + lag(x1, 1),
family = "negbin"
) +
aux(numeric(d) ~ lag(d, 1) + lag(f, 2) + x2 | init(0)) +
aux(numeric(f) ~ lag(y5, 1) + x2 * 3 + 1 | init(c(0, 1))),
NA
)
expect_error(
dynamite(obs_det, test_data, "time", "group", debug = debug), NA
)
})
test_that("deterministic simultaneity is supported", {
expect_error(
obs(y5 ~ x1 + lag(d, 1) + lag(y5, 1) + lag(x1, 1), family = "negbin") +
aux(numeric(d) ~ y5 + 3),
NA
)
})
test_that("deterministic types are supported", {
expect_error(
aux(factor(a) ~ factor(c(1, 2, 3), levels = c(1, 2, 3))) +
aux(numeric(b) ~ log(1.0)) +
aux(integer(c) ~ 1L) +
aux(logical(d) ~ TRUE),
NA
)
})
test_that("deterministic lags with zero observed lags is evaluated", {
obs_zerolag <-
obs(y2 ~ x1, family = "gaussian") +
aux(numeric(d) ~ abs(y2) + lag(d) | init(0.5))
expect_error(
dynamite(obs_zerolag, test_data, "time", "group", debug = debug), NA
)
})
test_that("past definition computed from data is supported", {
expect_error(
obs_past <- obs(y7 ~ lag(d) + lag(y7, 1), family = "exponential") +
aux(numeric(d) ~ lag(d, 1) + lag(y3, 1) | past(log(abs(x2)))),
NA
)
expect_error(
fit <- dynamite(obs_past, test_data, "time", "group", debug = debug), NA
)
})
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.