Nothing
# Bootstrap confidence-interval coverage.
#
# Point recovery says the estimator is unbiased. It says nothing about whether
# the reported uncertainty is right -- an interval that is systematically too
# narrow passes every recovery test while being wrong in the way that matters
# most for a published analysis. This file simulates many datasets from a known
# truth and counts how often the 95% interval actually contains it.
#
# Scope is deliberate. Coverage is asserted on the OUTCOME parameters
# (res_Gamma), where the bootstrap behaves: measured replicate spread there is
# modest and intervals bracket the truth. It is NOT asserted on res_Beta, whose
# replicate distribution is pathological -- on well-separated N = 500 data the
# replicates ranged -30.6 to +15.7 with sd 4.0 against a point estimate of 1.72,
# giving a 95% interval of (-10.7, 12.5). A nominal-coverage assertion there
# would fail against a correct implementation of the current algorithm, so beta
# gets a floor that catches total breakage and an explicit note instead.
#
# Cost: this is the most expensive file in the suite. It carries a second gate
# beyond skip_on_cran() so a normal heavy-tier run does not pay for it.
skip_on_cran()
skip_if_not(nzchar(Sys.getenv("LUCID_TEST_LEVEL")),
"set LUCID_TEST_LEVEL=full to run bootstrap coverage")
N_COV <- 300L
N_DATASETS <- 40L
R_BOOT <- 100L
CONF <- 0.95
# With 40 datasets at nominal 0.95, the exact binomial 99% acceptance region is
# [0.85, 1.00]: qbinom(0.005, 40, 0.95)/40 = 0.85. Asserting inside that band is
# a genuine two-sided test of calibration that will not flake on Monte Carlo
# noise, while still failing on a variance estimator that is materially wrong.
COV_LO <- 0.85
covers <- function(ci_row, truth) {
lo <- min(ci_row, na.rm = TRUE)
hi <- max(ci_row, na.rm = TRUE)
is.finite(lo) && is.finite(hi) && truth >= lo && truth <= hi
}
test_that("bootstrap intervals for the outcome effect cover the truth at ~95%", {
hits <- logical(N_DATASETS)
widths <- numeric(N_DATASETS)
for (i in seq_len(N_DATASETS)) {
d <- sim_lucid("early", N = N_COV, K = 2, M = 4, sep = 2.5,
family = "normal", seed = 700 + i)
suppressWarnings(suppressMessages(invisible(capture.output(
fit <- estimate_lucid(lucid_model = "early", G = d$G, Z = d$Z, Y = d$Y,
family = "normal", K = 2,
init_omic.data.model = "VVV", seed = 1)
))))
suppressWarnings(suppressMessages(invisible(capture.output(
bs <- boot_lucid(G = d$G, Z = d$Z, Y = d$Y, lucid_model = "early",
model = fit, R = R_BOOT, conf = CONF)
))))
# The generating outcome levels are 0 and 1, so the between-cluster contrast
# is 1. Compare against the contrast rather than the levels: it is invariant
# to which cluster got which label.
truth_contrast <- diff(d$truth$gamma[[1]])
gm <- as.data.frame(bs$gamma)
# the cluster-contrast row, whatever it is named in this fit
row <- grep("cluster2|LC2", rownames(gm))
if (!length(row)) next
limits <- suppressWarnings(as.numeric(gm[row[1], -1]))
limits <- limits[is.finite(limits)]
if (length(limits) < 2L) next
hits[i] <- covers(limits, truth_contrast)
widths[i] <- max(limits) - min(limits)
}
coverage <- mean(hits)
expect_gte(coverage, COV_LO)
expect_lte(coverage, 1.0)
# a degenerate interval could "cover" everything; require it to be informative
expect_lt(mean(widths[widths > 0]), 5)
})
test_that("intervals are well formed and bracket their own point estimate", {
# Cheap structural guarantees that must hold on every single fit, independent
# of coverage: limits finite, ordered, and containing the estimate they were
# built around.
for (model in c("early", "parallel")) {
n_layer <- if (model == "early") 1L else 2L
d <- sim_lucid(model, N = N_COV, K = 2, M = 4, n_layer = n_layer,
sep = 2.5, seed = 750)
K <- if (model == "early") 2 else rep(2, n_layer)
suppressWarnings(suppressMessages(invisible(capture.output(
fit <- estimate_lucid(lucid_model = model, G = d$G, Z = d$Z, Y = d$Y,
family = "normal", K = K,
init_omic.data.model = "VVV", seed = 1)
))))
suppressWarnings(suppressMessages(invisible(capture.output(
bs <- boot_lucid(G = d$G, Z = d$Z, Y = d$Y, lucid_model = model,
model = fit, R = 60, conf = CONF)
))))
tab <- as.data.frame(bs$gamma)
est <- as.numeric(tab[[1]])
for (r in seq_len(nrow(tab))) {
lims <- suppressWarnings(as.numeric(tab[r, -1]))
lims <- lims[is.finite(lims)]
if (length(lims) < 2L) next
expect_gte(est[r], min(lims) - 1e-8, label = paste(model, "estimate above lower limit"))
expect_lte(est[r], max(lims) + 1e-8, label = paste(model, "estimate below upper limit"))
}
}
})
test_that("wider confidence levels give wider intervals", {
# Monotonicity in conf is a property no correct interval can violate, and it
# is far cheaper to check than coverage.
d <- sim_lucid("early", N = N_COV, K = 2, M = 4, sep = 2.5, seed = 760)
suppressWarnings(suppressMessages(invisible(capture.output(
fit <- estimate_lucid(lucid_model = "early", G = d$G, Z = d$Z, Y = d$Y,
family = "normal", K = 2,
init_omic.data.model = "VVV", seed = 1)
))))
width_at <- function(conf) {
set.seed(99)
suppressWarnings(suppressMessages(invisible(capture.output(
bs <- boot_lucid(G = d$G, Z = d$Z, Y = d$Y, lucid_model = "early",
model = fit, R = 80, conf = conf)
))))
tab <- as.data.frame(bs$gamma)
lims <- suppressWarnings(as.numeric(tab[nrow(tab), -1]))
lims <- lims[is.finite(lims)]
if (length(lims) < 2L) return(NA_real_)
max(lims) - min(lims)
}
w80 <- width_at(0.80)
w99 <- width_at(0.99)
skip_if(is.na(w80) || is.na(w99), "intervals unavailable at this R")
expect_gt(w99, w80)
})
test_that("exposure-effect intervals are finite, with their instability recorded", {
# NOT a coverage assertion. The bootstrap replicate distribution for res_Beta
# is heavy-tailed enough that nominal coverage is not attainable at feasible R
# -- see the file header. This asserts only that limits exist and are finite,
# which catches the interval machinery breaking outright. Raising this to a
# real coverage assertion requires first fixing the replicate instability.
d <- sim_lucid("early", N = N_COV, K = 2, M = 4, P = 2, sep = 2.5, seed = 770)
suppressWarnings(suppressMessages(invisible(capture.output(
fit <- estimate_lucid(lucid_model = "early", G = d$G, Z = d$Z, Y = d$Y,
family = "normal", K = 2,
init_omic.data.model = "VVV", seed = 1)
))))
suppressWarnings(suppressMessages(invisible(capture.output(
bs <- boot_lucid(G = d$G, Z = d$Z, Y = d$Y, lucid_model = "early",
model = fit, R = R_BOOT, conf = CONF)
))))
tab <- as.data.frame(bs$beta)
expect_gt(nrow(tab), 0)
expect_true(all(is.finite(as.numeric(tab[[1]]))), label = "beta point estimates finite")
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.