From 10007274ab35d33af9999153a9295c78977c60c0 Mon Sep 17 00:00:00 2001 From: Colman Humphrey Date: Sun, 27 Jun 2021 15:50:48 -0400 Subject: [PATCH] v0.6.0: Making glmmTMB conditional + removing deprecated (#8) * removing `call. = FALSE` - originally inspired by https://adv-r.hadley.nz/conditions.html?q=call.%20=%20FALSE#errors-1 but I think it's not as helpful now * removing deprecated functions - it's time now. * document updates: - removed (previously deprecated) functions no longer in exported - docs updated (with roxygen update) * need glmmTMB for the last few tests * adding future.seed = TRUE to solve RNG from future.apply * increasing minimum version of glmmTMB * update the readme - run glmmTMB-dependent blocks conditionally - minor cleanup * adding conditional eval to vignette * adding clarification about non-parametric bootstrap * increasing version to 0.6.0 * adding cran-comments and news updates * spelling error * adding test envs to cran comments --- DESCRIPTION | 6 +- NAMESPACE | 3 - NEWS.md | 10 +++ R/bootstrap_ci.R | 33 +------- R/bootstrap_methods.R | 3 +- R/bootstrap_model.R | 59 ++++---------- README.Rmd | 11 ++- README.md | 72 ++++++++---------- cran-comments.md | 15 +++- man/bootstrap_ci.Rd | 11 --- man/bootstrap_model.Rd | 19 ----- man/combine_resampled_lists.Rd | 3 - man/test_data.Rd | 6 +- tests/testthat/test-bootstrap_model.R | 5 ++ vignettes/quick_use.Rmd | 20 ++--- .../figure-html/unnamed-chunk-17-1.png | Bin 0 -> 10574 bytes .../figure-html/unnamed-chunk-17-2.png | Bin 0 -> 10471 bytes 17 files changed, 101 insertions(+), 175 deletions(-) create mode 100644 vignettes/quick_use_files/figure-html/unnamed-chunk-17-1.png create mode 100644 vignettes/quick_use_files/figure-html/unnamed-chunk-17-2.png diff --git a/DESCRIPTION b/DESCRIPTION index b3c01b4..fef5b06 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: glmmboot Type: Package Title: Bootstrap Resampling for Mixed Effects and Plain Models -Version: 0.5.1 +Version: 0.6.0 Authors@R: person("Colman", "Humphrey", email = "humphrc@tcd.ie", role = c("aut", "cre")) Description: Performs bootstrap resampling for most models that update() works for. There @@ -19,12 +19,12 @@ Depends: Imports: methods, stats Suggests: - glmmTMB (>= 0.2.1), + glmmTMB (>= 1.1.0), testthat (>= 0.11.0), parallel (>= 3.0.0), future.apply (>= 1.1.0), knitr, rmarkdown, covr -RoxygenNote: 7.0.2 +RoxygenNote: 7.1.1 VignetteBuilder: knitr diff --git a/NAMESPACE b/NAMESPACE index d3664a3..223d5ef 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,8 +1,5 @@ # Generated by roxygen2: do not edit by hand -export(BootCI) -export(BootGlmm) -export(CombineResampledLists) export(bootstrap_ci) export(bootstrap_model) export(combine_resampled_lists) diff --git a/NEWS.md b/NEWS.md index 05726b3..c41dbff 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,13 @@ +# glmmboot 0.6.0 + +* Removing previously deprecated functions (deprecated as of 0.4.0) +* Adding conditional evaluation for tests and the vignette (and the readme) + for `glmmTMB`, in case it's not present / installable on a given system (as + it's only a suggested package) +* Removing `call. = FALSE` for errors and warnings +* adding `future.seed = TRUE` to `future.apply::future_lapply` call for better RNG +* Minor vignette and README copy edits + # glmmboot 0.5.1 * Changing a `donttest` to a `dontrun` within an example. diff --git a/R/bootstrap_ci.R b/R/bootstrap_ci.R index 99c07f4..9cdb731 100644 --- a/R/bootstrap_ci.R +++ b/R/bootstrap_ci.R @@ -91,12 +91,12 @@ bootstrap_individual_ci <- function(base_matrix = NULL, if (is.null(probs)) { if (alpha_level < 0 | alpha_level > 0.5) { stop("Can't calculate a two-sided CI with this alpha value, ", - "must be in (0, 0.5)", call. = FALSE) + "must be in (0, 0.5)") } probs <- sort(c(alpha_level / 2, 1 - alpha_level / 2)) } if (max(probs) > 1 || min(probs) < 0) { - stop("Probabilities should be in (0,1)", call. = FALSE) + stop("Probabilities should be in (0,1)") } base_row_names <- rownames(base_matrix) @@ -107,7 +107,7 @@ bootstrap_individual_ci <- function(base_matrix = NULL, })) if (mean(name_match) != 1) { - stop("Naming mismatch from base to list of coefs", call. = FALSE) + stop("Naming mismatch from base to list of coefs") } resampled_ests_vecs <- lapply(1:nrow(base_matrix), function(j){ @@ -239,24 +239,6 @@ ci_variable <- function(base_est, } -#' @rdname bootstrap_ci -#' @export -#' @param alp_level -#' now alpha_level -BootCI <- function(base_coef_se = NULL, # nocov start - resampled_coef_se = NULL, - orig_df = NULL, - alp_level = 0.05, - probs = NULL){ - .Deprecated("bootstrap_ci") - bootstrap_ci(base_coef_se = base_coef_se, - resampled_coef_se = resampled_coef_se, - orig_df = orig_df, - alpha_level = alp_level, - probs = probs) -} # nocov end - - #' Combines output from multiple bootstrap_model calls #' #' If you run glmmboot on e.g. a grid of computers, @@ -333,12 +315,3 @@ combine_resampled_lists <- function(..., bootstrap_ci(base_coef_se = reg_base_coef, resampled_coef_se = reg_resampled) } - -#' @rdname combine_resampled_lists -#' @export -CombineResampledLists <- function(..., # nocov start - return_combined_list = FALSE){ - .Deprecated("combine_resampled_lists") - combine_resampled_lists(..., - return_combined_list = return_combined_list) -} # nocov end diff --git a/R/bootstrap_methods.R b/R/bootstrap_methods.R index 6bd6fb3..2fbb2fe 100644 --- a/R/bootstrap_methods.R +++ b/R/bootstrap_methods.R @@ -122,8 +122,7 @@ gen_resampling_index <- function(orig_list, sampled_list){ if (length(orig_list) != length(sampled_list)) { stop("lists must be the same length ", - "(the original variables and the sampled variables)", - call. = FALSE) + "(the original variables and the sampled variables)") } ## coercing to character means this works for all types diff --git a/R/bootstrap_model.R b/R/bootstrap_model.R index a5a5115..7c14b53 100644 --- a/R/bootstrap_model.R +++ b/R/bootstrap_model.R @@ -127,12 +127,12 @@ bootstrap_model <- function(base_model, } else { stop("base_data cannot be automatically inferred, ", "please supply data as base_data ", - "to this function", call. = FALSE) + "to this function") } warning("Please supply data through the argument base_data; ", "automatic reading from your model can produce ", - "unforeseeable bugs.", call. = FALSE) + "unforeseeable bugs.") } if (missing(parallelism)) { @@ -142,7 +142,7 @@ bootstrap_model <- function(base_model, if (!requireNamespace("parallel", quietly = TRUE)) { # nocov start stop("setting `num_cores` greater than 1 without setting ", "`parallelism` uses `package:parallel`, ", - "but it's not installed", call. = FALSE) + "but it's not installed") } parallelism <- "parallel" # nocov end } else { @@ -152,25 +152,23 @@ bootstrap_model <- function(base_model, parallelism <- match.arg(parallelism) if (parallelism == "none" && !is.null(num_cores) && num_cores > 1) { stop("contradiction between `parallelism = \"none\"` ", - "and `num_cores = ", num_cores, "`; please resolve", - call. = FALSE) + "and `num_cores = ", num_cores, "`; please resolve") } if (parallelism == "future") { if (!requireNamespace("future.apply", quietly = TRUE)) { # nocov start stop("`parallelism = \"future\"` uses `package:future.apply`, ", - "but it's not installed", call. = FALSE) + "but it's not installed") } # nocov end if (!is.null(num_cores)) { stop("with `parallelism = \"future\"`, the `num_cores` ", "argument is not used to set up the backend; ", - "use `future::plan` instead", - call. = FALSE) + "use `future::plan` instead") } } if (parallelism == "parallel") { if (!requireNamespace("parallel", quietly = TRUE)) { # nocov start stop("`parallelism = \"parallel\"` uses `package:parallel`, ", - "but it's not installed", call. = FALSE) + "but it's not installed") } # nocov end if (is.null(num_cores)) { # nocov start @@ -183,7 +181,7 @@ bootstrap_model <- function(base_model, if (parallelism != "future" && !is.null(future_packages)) { stop("Argument `future_packages` should only be set when ", - "using `parallelism = \"future\"`", call. = FALSE) + "using `parallelism = \"future\"`") } ##------------------------------------ @@ -205,7 +203,7 @@ bootstrap_model <- function(base_model, } else { if (!list_of_matrices(base_coef)) { stop("currently this method needs `coef(summary(base_model))` ", # nocov start - "to be a matrix, or a list of them", call. = FALSE) # nocov end + "to be a matrix, or a list of them") # nocov end } ## only calc not_null once, but local scope the result extract_coef <- (function(not_null){ @@ -234,7 +232,7 @@ bootstrap_model <- function(base_model, if (sum(rand_cols %in% resample_specific_blocks) == 0 && length(rand_cols) > 0) { stop("No random columns from formula found ", - "in resample_specific_blocks", call. = FALSE) + "in resample_specific_blocks") } rand_cols <- rand_cols[rand_cols %in% resample_specific_blocks] } @@ -338,8 +336,7 @@ bootstrap_model <- function(base_model, } if (any(error_ind)) { stop("could not generate error-free resamples in ", # nocov start - max_redos, " attempts", - call. = FALSE) # nocov end + max_redos, " attempts") # nocov end } if (return_coefs_instead) { @@ -361,37 +358,6 @@ bootstrap_model <- function(base_model, } -#' @export -#' @rdname bootstrap_model -#' @param suppress_loading_bar -#' defunct now -#' @param allow_conv_error -#' defunct now -BootGlmm <- function(base_model, # nocov start - resamples = 9999, - base_data = NULL, - return_coefs_instead = FALSE, - resample_specific_blocks = NULL, - unique_resample_lim = NULL, - narrowness_avoid = TRUE, - num_cores = NULL, - suppress_sampling_message = FALSE, - suppress_loading_bar = FALSE, - allow_conv_error = FALSE){ - .Deprecated("bootstrap_model") - - bootstrap_model(base_model = base_model, - base_data = base_data, - resamples = resamples, - return_coefs_instead = return_coefs_instead, - resample_specific_blocks = resample_specific_blocks, - unique_resample_lim = unique_resample_lim, - narrowness_avoid = narrowness_avoid, - num_cores = num_cores, - suppress_sampling_message = suppress_sampling_message) -} # nocov end - - #' Runs the bootstrapping of the models. #' #' This function gets passed a function that runs a single bootstrap resample @@ -417,7 +383,8 @@ bootstrap_runner <- function(bootstrap_function, function(i){ bootstrap_function() }, - future.packages = future_packages)) + future.packages = future_packages, + future.seed = TRUE)) } if (parallelism == "parallel") { diff --git a/README.Rmd b/README.Rmd index 021d8a1..bdb12d4 100644 --- a/README.Rmd +++ b/README.Rmd @@ -25,7 +25,7 @@ options(warnPartialMatchArgs = FALSE, ## Overview -glmmboot provides a simple interface for creating bootstrap +glmmboot provides a simple interface for creating non-parametric bootstrap confidence intervals using a wide set of models. The primary function is `bootstrap_model`, which has three primary arguments: @@ -47,6 +47,8 @@ For models with random effects: With no random effects, performs case resampling: resamples each row with replacement. +All of these are considered non-parametric. + ## Requirements: 1. the model should work with the @@ -88,7 +90,7 @@ devtools::install_github("ColmanHumphrey/glmmboot") We'll provide a quick example using glm. First we'll set up some data: ```{r} -set.seed(15278086) # Happy for Nadia and Alan +set.seed(15278086) x1 <- rnorm(50) x2 <- runif(50) @@ -130,7 +132,8 @@ conservative at `N = 50`. An example with a zero-inflated model (from the `glmmTMB` docs): -```{r} +```{r, eval = requireNamespace("glmmTMB", quietly = TRUE)} +## we'll skip this if glmmTMB not available library(glmmTMB) owls <- transform(Owls, @@ -148,7 +151,7 @@ fit_zipoisson <- glmmTMB( summary(fit_zipoisson) ``` Let's run the bootstrap (ignore the actual results, 3 resamples is basically meaningless - just for illustration): -```{r} +```{r, eval = requireNamespace("glmmTMB", quietly = TRUE)} zi_results <- bootstrap_model(base_model = fit_zipoisson, base_data = owls, resamples = 3) diff --git a/README.md b/README.md index fbe6a37..acbe213 100644 --- a/README.md +++ b/README.md @@ -15,14 +15,14 @@ status](https://www.r-pkg.org/badges/version/glmmboot)](https://cran.r-project.o ## Overview -glmmboot provides a simple interface for creating bootstrap confidence -intervals using a wide set of models. The primary function is -`bootstrap_model`, which has three primary arguments: +glmmboot provides a simple interface for creating non-parametric +bootstrap confidence intervals using a wide set of models. The primary +function is `bootstrap_model`, which has three primary arguments: - - `base_model`: the model run on the full data as you normally would, +- `base_model`: the model run on the full data as you normally would, prior to bootstrapping - - `base_data`: the dataset used - - `resamples`: how many bootstrap resamples you wish to perform +- `base_data`: the dataset used +- `resamples`: how many bootstrap resamples you wish to perform Another function, `bootstrap_ci`, converts output from bootstrap model runs into confidence intervals and p-values. By default, @@ -32,24 +32,24 @@ runs into confidence intervals and p-values. By default, For models with random effects: - - the default (and recommended) behaviour will be to block sample over +- the default (and recommended) behaviour will be to block sample over the effect with the largest entropy (generally the one with the most levels) - - it’s also possible to specify multiple random effects to block +- it’s also possible to specify multiple random effects to block sample over With no random effects, performs case resampling: resamples each row with replacement. +All of these are considered non-parametric. + ## Requirements: 1. the model should work with the function `update`, to change the data 2. the coefficients are extractable using `coef(summary(model))` - - - - either directly, i.e. this gives a matrix - - or it’s a list of matrices; this includes e.g. zero-inflated models, +- either directly, i.e. this gives a matrix +- or it’s a list of matrices; this includes e.g. zero-inflated models, which produce two matrices of coefficients ## Parallel @@ -84,7 +84,7 @@ devtools::install_github("ColmanHumphrey/glmmboot") We’ll provide a quick example using glm. First we’ll set up some data: ``` r -set.seed(15278086) # Happy for Nadia and Alan +set.seed(15278086) x1 <- rnorm(50) x2 <- runif(50) @@ -141,14 +141,14 @@ And the results: ``` r print(boot_results) -# estimate boot 2.5% boot 97.5% boot p_value base p_value -# (Intercept) -0.1160896 -1.2295 0.9809 0.830 0.8446 -# x1 -0.5146778 -1.1245 0.0455 0.076 0.1353 -# x2 1.0932707 -0.7517 3.1328 0.284 0.2829 -# base 2.5% base 97.5% boot/base width -# (Intercept) -1.3010 1.0688 0.9327523 -# x1 -1.1961 0.1667 0.8584962 -# x2 -0.9315 3.1181 0.9592352 +# estimate boot 2.5% boot 97.5% boot p_value base p_value base 2.5% +# (Intercept) -0.1160896 -1.2295 0.9809 0.830 0.8446 -1.3010 +# x1 -0.5146778 -1.1245 0.0455 0.076 0.1353 -1.1961 +# x2 1.0932707 -0.7517 3.1328 0.284 0.2829 -0.9315 +# base 97.5% boot/base width +# (Intercept) 1.0688 0.9327523 +# x1 0.1667 0.8584962 +# x2 3.1181 0.9592352 ``` The estimates are the same, since we just pull from the base model. The @@ -158,6 +158,7 @@ typical logistic regression is fractionally conservative at `N = 50`. An example with a zero-inflated model (from the `glmmTMB` docs): ``` r +## we'll skip this if glmmTMB not available library(glmmTMB) owls <- transform(Owls, @@ -225,26 +226,19 @@ print(zi_results) # SexParentMale 0.44884508 0.1134 1.2690 0.5 # ftSatiated:SexParentMale 0.10472505 -0.1153 0.2804 1.0 # ArrivalTime:SexParentMale -0.02139750 -0.0527 -0.0087 0.5 -# base p_value base 2.5% base 97.5% -# (Intercept) 0.0000 1.8411 3.2388 -# ftSatiated 0.0000 -0.4079 -0.1743 -# ArrivalTime 0.0000 -0.0960 -0.0401 -# SexParentMale 0.3186 -0.4332 1.3309 -# ftSatiated:SexParentMale 0.1506 -0.0381 0.2475 -# ArrivalTime:SexParentMale 0.2436 -0.0574 0.0146 -# boot/base width -# (Intercept) 0.7177368 -# ftSatiated 0.5002454 -# ArrivalTime 0.8479791 -# SexParentMale 0.6550388 -# ftSatiated:SexParentMale 1.3852712 -# ArrivalTime:SexParentMale 0.6116518 +# base p_value base 2.5% base 97.5% boot/base width +# (Intercept) 0.0000 1.8411 3.2388 0.7177368 +# ftSatiated 0.0000 -0.4079 -0.1743 0.5002454 +# ArrivalTime 0.0000 -0.0960 -0.0401 0.8479791 +# SexParentMale 0.3186 -0.4332 1.3309 0.6550388 +# ftSatiated:SexParentMale 0.1506 -0.0381 0.2475 1.3852712 +# ArrivalTime:SexParentMale 0.2436 -0.0574 0.0146 0.6116518 # # $zi -# estimate boot 2.5% boot 97.5% boot p_value base p_value -# (Intercept) -1.057534 -1.0575 -0.84 0.5 0 -# base 2.5% base 97.5% boot/base width -# (Intercept) -1.242 -0.8731 0.5895082 +# estimate boot 2.5% boot 97.5% boot p_value base p_value base 2.5% +# (Intercept) -1.057534 -1.0575 -0.84 0.5 0 -1.242 +# base 97.5% boot/base width +# (Intercept) -0.8731 0.5895082 ``` We could also have run this with the `future.apply` backend: diff --git a/cran-comments.md b/cran-comments.md index f247e78..3fd2e88 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,11 +1,18 @@ ## Release Summary -Changing `donttest` to `dontrun` for an example. +Primary purpose of this change is to add conditional eval statements for tests +and vignettes using `glmmTMB`. The other change was fully removing functions +deprecated as of 0.4.0, hence the minor version bump. ## Test environments -* local OS X install, R 3.6.2 -* Ubuntu 16.04.6 LTS (on travis-ci), R 3.6.2 -* win-builder, devel R 4.0.0 alpha, and release R 3.6.3 + +* local Mac: 11.3.1, aarch64-apple-darwin20 (64-bit), R 4.1.0 +* R-hub: + * Ubuntu Linux 20.04.1 LTS, R-release (4.1.0), GCC + * Fedora Linux, R-devel, clang, gfortran + * Windows Server 2008 R2 SP1, R-devel, 32/64 bit +* win-builder: R Under development (unstable) (2021-06-22 r80544) + ## R CMD check results diff --git a/man/bootstrap_ci.Rd b/man/bootstrap_ci.Rd index b0a076a..21a0068 100644 --- a/man/bootstrap_ci.Rd +++ b/man/bootstrap_ci.Rd @@ -2,7 +2,6 @@ % Please edit documentation in R/bootstrap_ci.R \name{bootstrap_ci} \alias{bootstrap_ci} -\alias{BootCI} \title{Generating bootstrap confidence intervals.} \usage{ bootstrap_ci( @@ -12,14 +11,6 @@ bootstrap_ci( alpha_level = 0.05, probs = NULL ) - -BootCI( - base_coef_se = NULL, - resampled_coef_se = NULL, - orig_df = NULL, - alp_level = 0.05, - probs = NULL -) } \arguments{ \item{base_coef_se}{Estimates and SEs from full sample. In matrix form, @@ -41,8 +32,6 @@ t-values used for the base interval.} \item{probs}{Default \code{NULL}, and will use \code{alpha_level} to set endpoints. Else will calculate these CI endpoints.} - -\item{alp_level}{now alpha_level} } \value{ A matrix containing: diff --git a/man/bootstrap_model.Rd b/man/bootstrap_model.Rd index 10b086f..8d60c88 100644 --- a/man/bootstrap_model.Rd +++ b/man/bootstrap_model.Rd @@ -2,7 +2,6 @@ % Please edit documentation in R/bootstrap_model.R \name{bootstrap_model} \alias{bootstrap_model} -\alias{BootGlmm} \title{Computes bootstrap resamples of your data, stores estimates + SEs.} \usage{ @@ -19,20 +18,6 @@ bootstrap_model( future_packages = NULL, suppress_sampling_message = !interactive() ) - -BootGlmm( - base_model, - resamples = 9999, - base_data = NULL, - return_coefs_instead = FALSE, - resample_specific_blocks = NULL, - unique_resample_lim = NULL, - narrowness_avoid = TRUE, - num_cores = NULL, - suppress_sampling_message = FALSE, - suppress_loading_bar = FALSE, - allow_conv_error = FALSE -) } \arguments{ \item{base_model}{The pre-bootstrap model, i.e. the model output @@ -103,10 +88,6 @@ bootstrapping? If block resampling over random effects, then it'll say what effect it's sampling over; if case resampling - in which case it'll say as much. Set \code{TRUE} to hide message.} - -\item{suppress_loading_bar}{defunct now} - -\item{allow_conv_error}{defunct now} } \value{ By default (with \code{return_coefs_instead} being \code{FALSE}), diff --git a/man/combine_resampled_lists.Rd b/man/combine_resampled_lists.Rd index e4fc983..767822c 100644 --- a/man/combine_resampled_lists.Rd +++ b/man/combine_resampled_lists.Rd @@ -2,12 +2,9 @@ % Please edit documentation in R/bootstrap_ci.R \name{combine_resampled_lists} \alias{combine_resampled_lists} -\alias{CombineResampledLists} \title{Combines output from multiple bootstrap_model calls} \usage{ combine_resampled_lists(..., return_combined_list = FALSE) - -CombineResampledLists(..., return_combined_list = FALSE) } \arguments{ \item{...}{List of outputs to be combined, or just a bunch of output entries diff --git a/man/test_data.Rd b/man/test_data.Rd index b270d71..27f667f 100644 --- a/man/test_data.Rd +++ b/man/test_data.Rd @@ -4,14 +4,16 @@ \name{test_data} \alias{test_data} \title{Simulated data containing three fixed effects and one random effect} -\format{A data frame with 300 rows and 4 variables: +\format{ +A data frame with 300 rows and 4 variables: \describe{ \item{x_var1}{independent normally distributed variable} \item{x_var2}{independent normally distributed variable} \item{x_var3}{independent normally distributed variable} \item{subj}{levels of random effect} \item{y}{outcome: lives in interval [0,1]} -}} +} +} \usage{ test_data } diff --git a/tests/testthat/test-bootstrap_model.R b/tests/testthat/test-bootstrap_model.R index 4dfafed..bcaa665 100644 --- a/tests/testthat/test-bootstrap_model.R +++ b/tests/testthat/test-bootstrap_model.R @@ -188,7 +188,12 @@ test_that("bootstrap_model parallelism modes", { num_cores = NULL, suppress_sampling_message = TRUE), NA) + ## we're not actually using glmmTMB here but for testing it's fine + if (!requireNamespace("glmmTMB", quietly = TRUE)) { + skip("need glmmTMB to be installed for future package tests") + } + expect_error(bootstrap_model(base_model = simple_model, base_data = xy_data, resamples = 20, diff --git a/vignettes/quick_use.Rmd b/vignettes/quick_use.Rmd index bf8a3bd..c4f4b45 100644 --- a/vignettes/quick_use.Rmd +++ b/vignettes/quick_use.Rmd @@ -24,8 +24,9 @@ options(warnPartialMatchArgs = FALSE, For even quicker usage instructions, see the README. -The general idea of this package is that you can throw nearly any -model built in the typical R fashion. For now, we just need +The general idea behind this package is for you to be able to throw +in nearly any model built in the typical R fashion and get back +a non-parametric bootstrap analysis. For now, we just need a somewhat standard way of extracting fixed effects, and that `update` works, which is nearly always the case. @@ -59,7 +60,8 @@ We're assuming the `x_var` variables are fixed, and `subj` is to be treated as a Thus our base analysis is: -```{r, cache=TRUE} +```{r, eval = requireNamespace("glmmTMB", quietly = TRUE), cache=TRUE} +## we'll skip this if glmmTMB not available library(glmmTMB) model_formula <- as.formula(y ~ x_var1 + x_var2 + x_var2 + (1 | subj)) @@ -72,7 +74,7 @@ We get a warning because the outcome data is proportional. Not to worry. Now we'll use the bootstrap. By default it'll perform block bootstrapping over the highest entropy random effect - but there's only one, so of course the winner is `subj`. -```{r, cache=TRUE} +```{r, eval = requireNamespace("glmmTMB", quietly = TRUE), cache=TRUE} bootstrap_over_subj <- bootstrap_model(base_model = base_run, base_data = test_data, resamples = 99) @@ -81,7 +83,7 @@ For publications etc, better to run about ten thousand resamples to avoid noise having much of an effect. Of course 99 is far too small, only for an example. And comparing results: -```{r, cache=TRUE} +```{r, eval = requireNamespace("glmmTMB", quietly = TRUE), cache=TRUE} print(bootstrap_over_subj) ``` @@ -91,7 +93,7 @@ The above might take a long time in a real setting. If it takes far too long on you can ideally run it on a bunch of computers. We don't want each computer to output the fully processed output, only the intermediate outcome. To do this, we set `return_coefs_instead = TRUE` for each run: -```{r, cache=TRUE} +```{r, eval = requireNamespace("glmmTMB", quietly = TRUE), cache=TRUE} b_list1 <- bootstrap_model(base_model = base_run, base_data = test_data, resamples = 29, @@ -107,17 +109,17 @@ b_list3 <- bootstrap_model(base_model = base_run, ``` Combining this is simple enough. If we've used a few, we don't want to mess around with even more lists, so we can enter them into the relevant function: -```{r, cache=TRUE} +```{r, eval = requireNamespace("glmmTMB", quietly = TRUE), cache=TRUE} print(combine_resampled_lists(b_list1, b_list2, b_list3)) ``` If we've run a huge number of such runs, ideally we'll combine all output to a list of lists, like so: -```{r, cache=TRUE} +```{r, eval = requireNamespace("glmmTMB", quietly = TRUE), cache=TRUE} list_of_lists_output <- list(b_list1, b_list2, b_list3) ``` And we'll get the same result: -```{r, cache=TRUE} +```{r, eval = requireNamespace("glmmTMB", quietly = TRUE), cache=TRUE} print(combine_resampled_lists(list_of_lists_output)) ``` diff --git a/vignettes/quick_use_files/figure-html/unnamed-chunk-17-1.png b/vignettes/quick_use_files/figure-html/unnamed-chunk-17-1.png new file mode 100644 index 0000000000000000000000000000000000000000..aa48e15af280a6130449759d11a2248e0dbff46c GIT binary patch literal 10574 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 OOv>`=a$jW3!u|u|VKM9g literal 0 HcmV?d00001 diff --git a/vignettes/quick_use_files/figure-html/unnamed-chunk-17-2.png b/vignettes/quick_use_files/figure-html/unnamed-chunk-17-2.png new file mode 100644 index 0000000000000000000000000000000000000000..8f712cd94765d7f80df3ae7b3aceb1a63bc1a3b8 GIT binary patch literal 10471 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 S?05e$Qj}Gd`6gu)@ZSJ*cLMnU literal 0 HcmV?d00001