suppressPackageStartupMessages({ library(dplyr) library(testthat) library(tibble) }) get_data <- function(n) { sigma <- as_vcov(c(2, 1, 0.7), c(0.5, 0.3, 0.2)) set.seed(1518) dat <- get_sim_data(n, sigma, trt = 8) %>% mutate(is_miss = rbinom(n(), 1, 0.5)) %>% mutate(outcome = if_else(is_miss == 1 & visit == "visit_3", NA_real_, outcome)) %>% select(-is_miss) %>% mutate(group = factor(group, labels = c("Placebo", "TRT"))) dat_ice <- dat %>% group_by(id) %>% arrange(id, visit) %>% filter(is.na(outcome)) %>% slice(1) %>% ungroup() %>% select(id, visit) %>% mutate(strategy = "JR") vars <- set_vars( outcome = "outcome", group = "group", strategy = "strategy", subjid = "id", visit = "visit", covariates = c("age", "sex", "visit * group") ) list(dat = dat, dat_ice = dat_ice, vars = vars) } standard_checks <- function(dobj, d, meth) { expect_true(all(c("samples", "formula", "data", "method", "fit", "n_failures") %in% names(dobj))) expect_true(class(dobj)[[1]] == "draws") expect_true(class(dobj$formula) == "formula") expect_equal(meth, dobj$method) expect_true(all(vapply(dobj$samples, function(x) !x$failed, logical(1)))) expect_true(class(dobj$samples)[[1]] == "sample_list") expect_true(all(vapply(dobj$samples, function(x) length(x$sigma) == 2, logical(1)))) expect_true(all(vapply(dobj$samples, function(x) identical(x$sigma[[1]], x$sigma[[2]]), logical(1)))) expect_true(all(vapply(dobj$samples, function(x) length(x$beta) == 8, logical(1)))) expect_true(all(vapply(dobj$samples, function(x) all(!is.na(x$beta)), logical(1)))) validate(dobj$samples) for (samp in dobj$samples) { validate(samp) } } test_that("approxbayes", { set.seed(40123) d <- get_data(80) meth <- method_approxbayes(n_samples = 2) dobj <- draws(d$dat, d$dat_ice, d$vars, meth, quiet = TRUE) standard_checks(dobj, d, meth) expect_length(dobj$samples, 2) for (samp in dobj$samples) { expect_equal(samp$ids, levels(d$dat$id)) } }) test_that("condmean - bootstrap", { set.seed(40123) d <- get_data(70) meth <- method_condmean(n_samples = 1) dobj <- draws(d$dat, d$dat_ice, d$vars, meth, quiet = TRUE) standard_checks(dobj, d, meth) expect_length(dobj$samples, 2) expect_equal(dobj$samples[[1]]$ids, levels(d$dat$id)) for (samp in dobj$samples[-1]) { expect_true(max(tapply(samp$ids, samp$ids, length)) >= 2) expect_true(length(samp$ids) == length(dobj$samples[[1]]$ids)) } set.seed(623) meth <- method_condmean(n_samples = 1) dobj2 <- draws(d$dat, d$dat_ice, d$vars, meth, quiet = TRUE) standard_checks(dobj2, d, meth) expect_length(dobj2$samples, 2) expect_equal(dobj2$samples[[1]], dobj$samples[[1]]) expect_true(!identical(dobj$samples[[2]], dobj2$samples[[2]])) set.seed(623) meth <- method_condmean(n_samples = 1) dobj3 <- draws(d$dat, d$dat_ice, d$vars, meth, quiet = TRUE) standard_checks(dobj3, d, meth) expect_length(dobj3$samples, 2) expect_equal(dobj3$samples[[1]], dobj$samples[[1]]) expect_true(identical(dobj2$samples, dobj3$samples)) }) test_that("condmean - jackknife", { skip_if_not(is_full_test()) set.seed(40123) N <- 70 d <- get_data(N) meth <- method_condmean(type = "jackknife") dobj <- draws(d$dat, d$dat_ice, d$vars, meth, quiet = TRUE, ncores = 2) standard_checks(dobj, d, meth) expect_length(dobj$samples, N + 1) expect_equal(dobj$samples[[1]]$ids, levels(d$dat$id)) expect_true(all(vapply(dobj$samples[-1], function(x) length(x$ids) == N - 1, logical(1)))) for (i in seq_len(N)) { expect_equal(dobj$samples[-1][[i]]$ids, levels(d$dat$id)[-i]) } set.seed(123) dobj2 <- draws(d$dat, d$dat_ice, d$vars, meth, quiet = TRUE, ncores = 2) expect_equal(dobj[c("samples", "data")], dobj2[c("samples", "data")]) }) test_that("bayes", { set.seed(40123) d <- get_data(140) meth <- method_bayes(n_samples = 2, burn_in = 200, burn_between = 2) dobj <- suppressWarnings({ draws(d$dat, d$dat_ice, d$vars, meth, quiet = TRUE) }) standard_checks(dobj, d, meth) expect_length(dobj$samples, 2) expect_true(all(vapply(dobj$samples, function(x) all(x$ids == levels(d$dat$id)), logical(1)))) }) test_that("nmar data is removed as expected", { # In order to test if nmar is being removed correctly we will # create a dataset flag seveal patients as being nmar then compare # the output of draws on this dataset vs the same dataset after # manually removing those observations set.seed(301) mysig <- as_vcov( sd = c(1, 3, 5), cor = c(0.3, 0.5, 0.8) ) dat <- get_sim_data(120, mysig) nmar_ids <- sample(unique(dat$id), size = 4) dat2 <- dat %>% mutate(outcome = if_else(id %in% nmar_ids & visit %in% c("visit_2", "visit_3"), NA_real_, outcome)) dat_ice <- tibble( id = nmar_ids, strategy = "CR", visit = "visit_2" ) vars <- set_vars( outcome = "outcome", visit = "visit", subjid = "id", group = "group", strategy = "strategy", covariates = c("age", "sex") ) method <- method_condmean(type = "bootstrap", n_samples = 2) set.seed(101) d1 <- draws(dat, dat_ice, vars, method, quiet = TRUE) set.seed(101) d2 <- draws(dat2, dat_ice, vars, method, quiet = TRUE) expect_equal(d1$samples, d2$samples) }) test_that("NULL data_ice works uses MAR by default", { set.seed(314) dat <- simulate_test_data(n = 100) dat2 <- dat %>% mutate(outcome = if_else(rbinom(n(), 1, 0.2) == 0, outcome, NA_real_)) dobj <- draws( dat2, method = method_condmean(n_samples = 3), quiet = TRUE, vars = set_vars( outcome = "outcome", visit = "visit", subjid = "id", group = "group", strategy = "strategy", covariates = c("age", "sex") ) ) expect_true(all(unlist(dobj$data$is_mar))) expect_true(all(!unlist(dobj$data$is_post_ice))) }) test_that("Failure is handled properly", { set.seed(521) bign <- 80 sigma <- as_vcov( c(2, 1, 0.7), c( 0.3, 0.4, 0.2 ) ) dat <- get_sim_data(bign, sigma, trt = 8) %>% mutate(is_miss = rbinom(n(), 1, 0.5)) %>% mutate(outcome = if_else(is_miss == 1 & visit == "visit_3", NA_real_, outcome)) %>% select(-is_miss) dat_ice <- dat %>% group_by(id) %>% arrange(id, visit) %>% filter(is.na(outcome)) %>% slice(1) %>% ungroup() %>% select(id, visit) %>% mutate(strategy = "JR") vars <- set_vars( outcome = "outcome", group = "group", strategy = "strategy", subjid = "id", visit = "visit", covariates = c("age", "sex", "visit * group") ) MockLongData <- R6Class("MockLongData", inherit = longDataConstructor, public = list( failure_index = 0, tracker = 0, sample_ids = function() { self$tracker <- self$tracker + 1 if (self$tracker %in% self$failure_index) { return(c("1", "2")) } super$sample_ids() }, set_failed_sample_index = function(x) { self$tracker <- 0 self$failure_index <- x } ) ) ld <- MockLongData$new(dat, vars) ld$set_strategies(dat_ice) ################## # # Bootstrap - 1 core # method <- method_approxbayes(n_samples = 10, threshold = 0.5) ld$set_failed_sample_index(seq_len(4)) stack <- get_bootstrap_stack(ld, method) x <- get_draws_mle( longdata = ld, method = method, n_target_samples = method$n_samples, failure_limit = (method$threshold * method$n_samples), use_samp_ids = FALSE, ncores = 1, first_sample_orig = FALSE, quiet = TRUE, sample_stack = stack ) expect_equal(x$n_failures, 4) expect_equal(ld$tracker, 15) expect_length(stack$stack, 1) method <- method_approxbayes(n_samples = 10, threshold = 0.3) ld$set_failed_sample_index(2:5) stack <- get_bootstrap_stack(ld, method) expect_error( get_draws_mle( longdata = ld, method = method, n_target_samples = method$n_samples, failure_limit = (method$threshold * method$n_samples), use_samp_ids = FALSE, ncores = 1, quiet = TRUE, first_sample_orig = FALSE, sample_stack = stack ) ) expect_equal(ld$tracker, 13) expect_length(stack$stack, 8) ################## # # Bootstrap - 2 core # method <- method_approxbayes(n_samples = 10, threshold = 0.5) ld$set_failed_sample_index(seq_len(4)) stack <- get_bootstrap_stack(ld, method) x <- get_draws_mle( longdata = ld, method = method, n_target_samples = method$n_samples, failure_limit = (method$threshold * method$n_samples), use_samp_ids = FALSE, ncores = 2, quiet = TRUE, first_sample_orig = FALSE, sample_stack = stack ) expect_equal(x$n_failures, 4) expect_equal(ld$tracker, 15) expect_length(stack$stack, 1) method <- method_approxbayes(n_samples = 10, threshold = 0.3) ld$set_failed_sample_index(2:5) stack <- get_bootstrap_stack(ld, method) expect_error( get_draws_mle( longdata = ld, method = method, n_target_samples = method$n_samples, failure_limit = (method$threshold * method$n_samples), use_samp_ids = FALSE, ncores = 2, quiet = TRUE, first_sample_orig = FALSE, sample_stack = stack ) ) expect_equal(ld$tracker, 13) expect_length(stack$stack, 13 - 6) ################## # # Jackknife - failures only # method <- method_condmean(type = "jackknife") stack <- get_jackknife_stack(ld) for (i in 5:10) { stack$stack[[i]] <- c("1", "2") } expect_error( x <- get_draws_mle( longdata = ld, method = method, n_target_samples = length(ld$ids), failure_limit = 0, use_samp_ids = FALSE, ncores = 1, first_sample_orig = FALSE, sample_stack = stack, quiet = TRUE ), regexp = "after removing subject '3'" ) expect_length(stack$stack, length(ld$ids) - 5) method <- method_condmean(type = "jackknife") stack <- get_jackknife_stack(ld) for (i in 5:10) { stack$stack[[i]] <- c("1", "2", "3") } expect_error( x <- get_draws_mle( longdata = ld, method = method, n_target_samples = length(ld$ids), failure_limit = 0, use_samp_ids = FALSE, ncores = 2, first_sample_orig = FALSE, sample_stack = stack, quiet = TRUE ), regex = "after removing subject '4'" ) expect_length(stack$stack, length(ld$ids) - 6) }) test_that("draws is calling get_mmrm_sample properly", { bign <- 75 sigma <- as_vcov( c(2, 1, 0.7), c( 0.3, 0.4, 0.2 ) ) dat <- get_sim_data(bign, sigma, trt = 8) %>% mutate(is_miss = rbinom(n(), 1, 0.5)) %>% mutate(outcome = if_else(is_miss == 1 & visit == "visit_3", NA_real_, outcome)) %>% select(-is_miss) dat_ice <- dat %>% group_by(id) %>% arrange(id, visit) %>% filter(is.na(outcome)) %>% slice(1) %>% ungroup() %>% select(id, visit) %>% mutate(strategy = "JR") vars <- set_vars( outcome = "outcome", group = "group", strategy = "strategy", subjid = "id", visit = "visit", covariates = c("age", "sex", "visit * group") ) ################################## # # Conditional Mean # method <- method_condmean(n_samples = 2) ld <- longDataConstructor$new(dat, vars) ld$set_strategies(dat_ice) x <- draws(dat, dat_ice, vars, method, quiet = TRUE) s1 <- get_mmrm_sample( ids = ld$ids, longdata = ld, method = method ) expect_equal(ld$ids, x$samples[[1]]$ids) expect_equal(s1, x$samples[[1]]) s2 <- get_mmrm_sample( ids = x$samples[[2]]$ids, longdata = ld, method = method ) expect_true(!all(ld$ids %in% x$samples[[2]]$ids)) expect_true(length(ld$ids) == length(x$samples[[2]]$ids)) expect_equal(s2, x$samples[[2]]) ################################## # # Approx Bayesian # method <- method_approxbayes(n_samples = 2) ld <- longDataConstructor$new(dat, vars) ld$set_strategies(dat_ice) x <- draws(dat, dat_ice, vars, method, quiet = TRUE) s0 <- get_mmrm_sample( ids = ld$ids, longdata = ld, method = method ) s1 <- get_mmrm_sample( ids = x$samples[[1]]$ids_samp, longdata = ld, method = method ) s1$ids <- ld$ids expect_true(!all(ld$ids %in% x$samples[[1]]$ids_samp)) expect_true(all(ld$ids %in% x$samples[[1]]$ids)) expect_true(length(ld$ids) == length(x$samples[[1]]$ids)) expect_equal(s1, x$samples[[1]]) s2 <- get_mmrm_sample( ids = x$samples[[2]]$ids_samp, longdata = ld, method = method ) s2$ids <- ld$ids expect_true(!all(ld$ids %in% x$samples[[2]]$ids_samp)) expect_true(all(ld$ids %in% x$samples[[2]]$ids)) expect_true(length(ld$ids) == length(x$samples[[2]]$ids)) expect_equal(s2, x$samples[[2]]) }) test_that("draws.bmlmi works as expected", { set.seed(3812) bign <- 120 sigma <- as_vcov( c(2, 1, 0.7), c( 0.3, 0.4, 0.2 ) ) dat <- get_sim_data(bign, sigma, trt = 8) %>% mutate(is_miss = rbinom(n(), 1, 0.5)) %>% mutate(outcome = if_else(is_miss == 1 & visit == "visit_3", NA_real_, outcome)) %>% select(-is_miss) dat_ice <- dat %>% group_by(id) %>% arrange(id, visit) %>% filter(is.na(outcome)) %>% slice(1) %>% ungroup() %>% select(id, visit) %>% mutate(strategy = "JR") vars <- set_vars( outcome = "outcome", group = "group", strategy = "strategy", subjid = "id", visit = "visit", covariates = c("age", "sex", "visit * group") ) set.seed(3013) x1 <- draws( quiet = TRUE, dat, dat_ice, vars, method = method_bmlmi(B = 6), ncores = 2 ) set.seed(3013) x2 <- draws( quiet = TRUE, dat, dat_ice, vars, method = method_approxbayes(n_samples = 6) ) ### BMLMI should be identical to approx bayes within draws except for sample ids # Tolerance is set here to address mmrm issue where the first optimiser fails when run # in parallel and moves onto the second optimiser, where as in sequence the first # optimiser works fine. i.e. results are slightly different due to different optimisers # being used # https://github.com/openpharma/mmrm/issues/151 expect_equal( lapply(x1$samples, function(x) x[c("beta", "sigma", "theta", "failed")]), lapply(x2$samples, function(x) x[c("beta", "sigma", "theta", "failed")]), tolerance = 0.0001 ) ### Bootstrapped sample ids should have the same subject appearing multiple times ### in each sample for (samp in x1$samples) { expect_true(max(tapply(samp$ids, samp$ids, length)) > 1) } }) test_that("quiet suppress progress messages", { bign <- 90 sigma <- as_vcov( c(2, 1, 0.7), c( 0.3, 0.4, 0.2 ) ) dat <- get_sim_data(bign, sigma, trt = 8) %>% mutate(is_miss = rbinom(n(), 1, 0.5)) %>% mutate(outcome = if_else(is_miss == 1 & visit == "visit_3", NA_real_, outcome)) %>% select(-is_miss) dat_ice <- dat %>% group_by(id) %>% arrange(id, visit) %>% filter(is.na(outcome)) %>% slice(1) %>% ungroup() %>% select(id, visit) %>% mutate(strategy = "JR") vars <- set_vars( outcome = "outcome", group = "group", strategy = "strategy", subjid = "id", visit = "visit", covariates = c("age", "sex", "visit * group") ) set.seed(3013) x <- capture.output({ dobj <- draws( data = dat, data_ice = dat_ice, vars = vars, method = method_approxbayes(n_samples = 2) ) }) expect_true(any(grepl("Estimated running time", x))) expect_true(any(grepl("Progress: ", x))) set.seed(3013) x <- capture.output({ dobj <- draws( data = dat, quiet = TRUE, data_ice = dat_ice, vars = vars, method = method_approxbayes(n_samples = 1) ) }) expect_true(length(x) == 0 & is.character(x)) })