├── .Rbuildignore ├── .gitattributes ├── .gitignore ├── .travis.yml ├── DESCRIPTION ├── LICENSE ├── LICENSE.md ├── NAMESPACE ├── NEWS.md ├── R ├── extract_fixed.R ├── extract_ranef.R ├── extract_vc.R ├── gammit-package.R ├── globals.R ├── predict_gamm.R ├── summary_gamm.R ├── utils-pipe.R └── utils.R ├── README.Rmd ├── README.md ├── _pkgdown.yml ├── appveyor.yml ├── code-of-conduct.md ├── codecov.yml ├── docs ├── 404.html ├── LICENSE-text.html ├── LICENSE.html ├── README.knit.html ├── README.utf8.html ├── authors.html ├── bootstrap-toc.css ├── bootstrap-toc.js ├── code-of-conduct.html ├── docsearch.css ├── docsearch.js ├── extra.css ├── index.html ├── link.svg ├── news │ ├── index.html │ └── man │ │ └── figures │ │ └── mc_logo.png ├── pkgdown.css ├── pkgdown.js ├── pkgdown.yml └── reference │ ├── Rplot001.png │ ├── extract_fixed.html │ ├── extract_ranef.html │ ├── extract_vc.html │ ├── figures │ └── mc_logo.png │ ├── gammit-package.html │ ├── index.html │ ├── man │ └── figures │ │ └── mc_logo.png │ ├── predict_gamm.html │ ├── reexports.html │ └── summary_gamm.html ├── gammit.Rproj ├── man ├── extract_fixed.Rd ├── extract_ranef.Rd ├── extract_vc.Rd ├── figures │ └── mc_logo.png ├── gammit-package.Rd ├── predict_gamm.Rd ├── reexports.Rd └── summary_gamm.Rd ├── pkgdown ├── extra.css └── pygment_highlights.css └── tests ├── testthat.R └── testthat ├── helper-load_data.R ├── mgcv_results.RData ├── test_extract_fixed.R ├── test_extract_ranef.R ├── test_extract_vc.R ├── test_predict_gamm.R └── test_summary_gamm.R /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^code-of-conduct\.md$ 4 | ^LICENSE\.md$ 5 | ^README\.Rmd$ 6 | ^\.github$ 7 | ^\.travis\.yml$ 8 | ^appveyor\.yml$ 9 | ^codecov\.yml$ 10 | docs 11 | pkgdown 12 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.css linguist-vendored 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # History files 2 | .Rhistory 3 | .Rapp.history 4 | 5 | # Example code in package build process 6 | *-Ex.R 7 | 8 | # RStudio files 9 | .Rproj.user/ 10 | 11 | # produced vignettes 12 | vignettes/*.html 13 | vignettes/*.pdf 14 | 15 | # OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 16 | .httr-oauth 17 | 18 | .DS_Store 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r 2 | 3 | language: R 4 | sudo: false 5 | cache: packages 6 | 7 | warnings_are_errors: false 8 | 9 | matrix: 10 | include: 11 | - r: 3.5.0 12 | - r: release 13 | 14 | allow_failures: 15 | 16 | 17 | repos: 18 | CRAN: https://cloud.r-project.org 19 | ropensci: http://packages.ropensci.org 20 | 21 | r_packages: 22 | - covr 23 | 24 | after_success: 25 | - Rscript -e 'covr::codecov()' 26 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: gammit 2 | Type: Package 3 | Title: Using Generalized Additive Mixed Models 4 | Version: 0.3.2 5 | Authors@R: person("Michael", "Clark", role = c("aut", "cre"), email = "micl@umich.edu") 6 | Maintainer: Michael Clark 7 | URL: https://github.com/m-clark/gammit 8 | BugReports: https://github.com/m-clark/gammit/issues 9 | Description: The goal of gammit is to provide a set of functions to aid using mgcv (possibly solely) for mixed models. 10 | License: MIT + file LICENSE 11 | Encoding: UTF-8 12 | LazyData: true 13 | Depends: 14 | R (>= 4.0.0) 15 | Imports: 16 | mgcv, 17 | rlang, 18 | dplyr, 19 | stringr, 20 | purrr, 21 | visibly 22 | Suggests: 23 | lme4, 24 | covr, 25 | knitr, 26 | testthat, 27 | Remotes: 28 | m-clark/visibly 29 | RoxygenNote: 6.1.1 30 | Roxygen: list(markdown = TRUE) 31 | VignetteBuilder: knitr 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2019 2 | COPYRIGHT HOLDER: Michael Clark 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2019 Michael Clark 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(extract_fixed) 4 | export(extract_ranef) 5 | export(extract_vc) 6 | export(plot_gam) 7 | export(plot_gam_2d) 8 | export(plot_gam_3d) 9 | export(plot_gam_by) 10 | export(plot_gam_check) 11 | export(predict_gamm) 12 | export(summary_gamm) 13 | importFrom(dplyr,"%>%") 14 | importFrom(dplyr,as_tibble) 15 | importFrom(dplyr,n_distinct) 16 | importFrom(dplyr,tibble) 17 | importFrom(mgcv,gam.vcomp) 18 | importFrom(purrr,is_empty) 19 | importFrom(purrr,map) 20 | importFrom(purrr,map_chr) 21 | importFrom(purrr,map_lgl) 22 | importFrom(stats,coef) 23 | importFrom(stats,predict) 24 | importFrom(stats,vcov) 25 | importFrom(stringr,str_detect) 26 | importFrom(stringr,str_replace) 27 | importFrom(visibly,plot_gam) 28 | importFrom(visibly,plot_gam_2d) 29 | importFrom(visibly,plot_gam_3d) 30 | importFrom(visibly,plot_gam_by) 31 | importFrom(visibly,plot_gam_check) 32 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # gammit 0.3.1 2 | * Refactor and extend most functions as done in mixedup 3 | 4 | # gammit 0.3.0 5 | * Build package website. 6 | 7 | # gammit 0.2.5 8 | * Added a `NEWS.md` file to track changes to the package. 9 | 10 | # gammit 0.2.1 11 | * Imported visibly's plot_gam functionality 12 | 13 | # gammit 0.2.0 14 | * Add predict_gamm 15 | 16 | # gammit 0.1.0 17 | * Added basic functionality 18 | 19 | 20 | -------------------------------------------------------------------------------- /R/extract_fixed.R: -------------------------------------------------------------------------------- 1 | #' Extract the fixed effects from a GAMM 2 | #' 3 | #' When using a GAM for mixed models, we may have specific interest in the fixed 4 | #' effect parameters. 5 | #' 6 | #' @inheritParams extract_vc 7 | #' @param ... Passed to summary.gam, e.g. to set re.test = FALSE. 8 | #' 9 | #' 10 | #' @details This essentially reproduces the 'parametric' output from 11 | #' \code{\link[mgcv]{summary.gam}}. 12 | #' 13 | #' @return A \code{data.frame} with the coefficients, standard error, and upper 14 | #' and lower bounds. 15 | #' 16 | #' @seealso \code{\link[lme4]{fixef}} 17 | #' @importFrom dplyr as_tibble 18 | #' @examples 19 | #' 20 | #' library(mgcv) 21 | #' library(lme4) 22 | #' 23 | #' lmer_model <- lmer(Reaction ~ Days + (Days || Subject), data = sleepstudy) 24 | #' ga_model <- gam(Reaction ~ Days + s(Subject, bs = "re") + s(Days, Subject, bs = "re"), 25 | #' data = sleepstudy, 26 | #' method = "REML" 27 | #' ) 28 | #' 29 | #' fixef(lmer_model) 30 | #' extract_fixed(ga_model) 31 | #' 32 | #' @importFrom stats coef vcov 33 | #' @export 34 | extract_fixed <- function( 35 | model, 36 | ci_level = .95, 37 | digits = 3, 38 | ... 39 | ) { 40 | fe <- data.frame(summary(model, ...)$p.table) 41 | colnames(fe) = c('value', 'se', 't', 'p') 42 | 43 | # no confint.gam 44 | if (ci_level > 0) { 45 | 46 | lower <- (1 - ci_level)/2 47 | upper <- 1 - lower 48 | nu <- model$df.residual 49 | mult <- stats::qt(upper, nu) 50 | 51 | ci <- data.frame( 52 | lower = fe$value - mult * fe$se, 53 | upper = fe$value + mult * fe$se 54 | ) 55 | 56 | colnames(ci) <- paste0(c('lower_', 'upper_'), c(lower, upper) * 100) 57 | 58 | fe <- data.frame(fe, ci) 59 | } 60 | 61 | fe <- fe %>% 62 | dplyr::mutate_all(round, digits = digits) %>% 63 | dplyr::mutate(term = gsub(rownames(fe), 64 | pattern = '[\\(,\\)]', 65 | replacement = '')) %>% 66 | dplyr::select(term, dplyr::everything()) %>% 67 | dplyr::as_tibble() 68 | 69 | fe 70 | 71 | } 72 | -------------------------------------------------------------------------------- /R/extract_ranef.R: -------------------------------------------------------------------------------- 1 | #' Extract random effects from a gam 2 | #' 3 | #' @description Extract what would be the random effects from a mixed model from 4 | #' a gam object. Assumes an mgcv model of the form `gam(... + s(g, 5 | #' bs='re'))`. 6 | #' 7 | #' @inheritParams extract_vc 8 | #' @param re Filter results to a specific random effect/grouping variable. 9 | #' 10 | #' @details Returns a data frame of the the `component` type, the estimated 11 | #' random effect `re`, the estimated `se`, and approximate `lower` and `upper` 12 | #' bounds. Note that the standard errors are Bayesian 13 | #' estimates (see \code{\link{gamObject}}, specifically type `Vp`). The `re` 14 | #' will only reflect smooth terms whose basis function is 're', i.e. of class 15 | #' `random.effect`. Others will be ignored. 16 | #' 17 | #' @return A `tibble` or data frame with the random effect, 18 | #' its standard error, and its lower and upper bounds. The bounds are based 19 | #' on a simple normal approximation using the standard error. 20 | #' 21 | #' @note `mgcv` strips the level names for 're' smooth terms, so this attempts 22 | #' to get them back. This may not work under every circumstance, but the 23 | #' attempt is made to extract the names of random effect groups based on how 24 | #' they are ordered in the data (which is how the model matrix would be 25 | #' constructed), and in the case of random slopes, detect that second variable 26 | #' in the 're' specification would be the grouping variable. This will not 27 | #' work for continuous x continuous smooths of type 're', but I can't think of 28 | #' a reason why you'd use that given your other options with `mgcv`. 29 | #' 30 | #' @seealso \code{\link{ranef}} 31 | #' 32 | #' @examples 33 | #' library(mgcv) 34 | #' library(lme4) 35 | #' 36 | #' lmer_model <- lmer(Reaction ~ Days + (Days || Subject), data = sleepstudy) 37 | #' ga_model <- gam(Reaction ~ Days + s(Subject, bs = "re") + s(Days, Subject, bs = "re"), 38 | #' data = sleepstudy, 39 | #' method = "REML" 40 | #' ) 41 | #' 42 | #' ranef(lmer_model) 43 | #' extract_ranef(ga_model) 44 | #' @importFrom purrr map_lgl map_chr is_empty map 45 | #' @importFrom dplyr n_distinct tibble 46 | #' @importFrom stringr str_detect 47 | #' 48 | #' @export 49 | extract_ranef <- function( 50 | model, 51 | re = NULL, 52 | ci_level = .95, 53 | digits = 3 54 | ) { 55 | 56 | if (!inherits(model, "gam")) stop("Need a gam object.") 57 | 58 | # get the re variables and their levels 59 | re_terms <- purrr::map_lgl(model$smooth, 60 | function(x) 61 | inherits(x, "random.effect")) 62 | 63 | re_names <- purrr::map_chr(model$smooth[re_terms], 64 | function(x) 65 | ifelse(length(x$vn) == 1, 66 | x$vn, 67 | x$vn[length(x$vn)])) 68 | 69 | re_levels <- vector("list", length(re_names)) 70 | 71 | # add check on re name/type 72 | # check that re is factor as re smooth can be applied to continuous 73 | for (i in seq_along(re_names)) { 74 | if (!inherits(model$model[, re_names[i]], "factor")) { 75 | warning( 76 | paste0(re_names[i], ' is not a factor. No results provided for it.') 77 | ) 78 | re_levels[[i]] <- NULL 79 | } 80 | else { 81 | re_levels[[i]] <- levels(model$model[, re_names[i]]) 82 | } 83 | } 84 | 85 | 86 | if (purrr::is_empty(re_levels) | all(purrr::map_lgl(re_levels, is.null))) { 87 | stop('No factor random effects.') 88 | } 89 | 90 | non_factors <- purrr::map_lgl(re_levels, is.null) 91 | 92 | # this test is covered but covr ignores for some reason 93 | if (any(non_factors)) { 94 | re_terms[non_factors] <- FALSE 95 | } 96 | 97 | if (!is.null(re) && !re %in% re_names) 98 | stop( 99 | paste0('re is not among the names of the random effects: ', 100 | paste0(re_names, collapse = ' ') 101 | ) 102 | ) 103 | 104 | re_labels <- purrr::map(model$smooth[re_terms], function(x) x$label) 105 | 106 | gam_coef <- stats::coef(model) 107 | 108 | # issue, parenthesis in the names means problematic regex matching so remove 109 | # all but key part of pattern 110 | re_label_base <- gsub(re_labels, pattern = "s\\(", replacement = '') # remove first s 111 | re_label_base <- gsub(re_label_base, pattern = "\\(|\\)", replacement = '') # remove parenthesis 112 | 113 | re_coef <- grepl(names(gam_coef), pattern = paste0('^s\\(', re_label_base, collapse = "|")) 114 | 115 | re0 <- gam_coef[re_coef] 116 | 117 | gam_se <- sqrt(diag(model$Vp)) # no names 118 | gam_se <- gam_se[names(gam_coef) %in% names(re0)] 119 | 120 | # clean up names 121 | names(re0) <- gsub(names(re0), pattern = "s\\(|\\)", replacement = '') 122 | names(re0) <- gsub(names(re0), pattern = "\\.[0-9]+", replacement = '') 123 | 124 | re_n <- dplyr::n_distinct(names(re0)) # possible use later 125 | re_names <- names(re0) 126 | 127 | random_effects <- dplyr::tibble(effect = re_names) %>% 128 | dplyr::mutate( 129 | group_var = split_group_effect(effect, which = 2), 130 | effect = split_group_effect(effect, which = 1), 131 | effect = ifelse(effect == group_var, 'Intercept', effect), 132 | group = unlist(re_levels), 133 | value = re0, 134 | se = gam_se 135 | ) 136 | 137 | if (ci_level > 0) { 138 | 139 | lower = (1 - ci_level)/2 140 | upper = 1 - lower 141 | mult <- stats::qnorm(upper) 142 | 143 | random_effects <- random_effects %>% 144 | dplyr::mutate( 145 | lower = value - mult * se, 146 | upper = value + mult * se 147 | ) 148 | 149 | colnames(random_effects)[colnames(random_effects) %in% c('lower', 'upper')] <- 150 | paste0(c('lower_', 'upper_'), c(lower, upper) * 100) 151 | } 152 | 153 | if (!is.null(re)) { 154 | random_effects <- random_effects %>% 155 | dplyr::filter(group_var == re) 156 | } 157 | 158 | random_effects %>% 159 | dplyr::select(group_var, effect, dplyr::everything()) %>% 160 | dplyr::mutate_if(is.numeric, round, digits = digits) 161 | } 162 | 163 | 164 | 165 | split_group_effect <- function(x, which = 1) { 166 | init = strsplit(x, split = ",") 167 | purrr::map_chr(init, function(x) x[min(which, length(x))]) 168 | } 169 | -------------------------------------------------------------------------------- /R/extract_vc.R: -------------------------------------------------------------------------------- 1 | #' Extract variance components 2 | #' 3 | #' @description This function extracts the variance components from a gam or bam 4 | #' object, where one is using the associated functions from the mgcv package 5 | #' for mixed models. 6 | #' 7 | #' @param model A gam or bam model 8 | #' @param ci_level Level for the confidence interval. Must be between 0 and 1. 9 | #' @param ci_scale Whether the confidence interval should be on the variance or standard deviation scale. 10 | #' @param digits Rounding for the output. 11 | #' 12 | #' @details This is essentially a pretty way to print \code{\link{gam.vcomp}}. 13 | #' Note that if you do something like a random slope, the gam approach does 14 | #' not estimate the intercept-slope correlation, so none will be printed. 15 | #' Should work fine on standard smooth terms also, but the model \emph{must be 16 | #' estimated with} `method = REML` or `method = ML`. This is the default for 17 | #' non-exponential families, but otherwise you'll have to change the value or 18 | #' will receive an error. Have not tested much with interactions, using `by`, 19 | #' etc., but it has worked on some default \code{\link{mgcv}} examples. 20 | #' 21 | #' @return A tibble or data frame with the standard deviation, its lower and 22 | #' upper bounds, the variance, and the relative proportion of total variance 23 | #' for each variance component. 24 | #' 25 | #' @examples 26 | #' library(mgcv) 27 | #' library(lme4) 28 | #' 29 | #' lmer_model <- lmer(Reaction ~ Days + (Days || Subject), data = sleepstudy) 30 | #' ga_model <- gam(Reaction ~ Days + s(Subject, bs = "re") + s(Days, Subject, bs = "re"), 31 | #' data = sleepstudy, 32 | #' method = "REML" 33 | #' ) 34 | #' 35 | #' VarCorr(lmer_model) 36 | #' extract_vc(ga_model) 37 | #' 38 | #' @importFrom stringr str_replace 39 | #' @importFrom mgcv gam.vcomp 40 | #' @export 41 | extract_vc <- function( 42 | model, 43 | ci_level = .95, 44 | ci_scale = 'sd', 45 | digits = 3 46 | ) { 47 | 48 | if (!inherits(model, "gam")) stop("Need a gam object.") 49 | 50 | if (!grepl(model$method, pattern = "REML")) { 51 | stop("REML required. Rerun model with method = 'REML' for appropriate results.") 52 | } 53 | 54 | # keep from printing result 55 | invisible( 56 | utils::capture.output( 57 | vc <- mgcv::gam.vcomp(model, conf.lev = ci_level) 58 | ) 59 | ) 60 | 61 | vc <- data.frame(vc) 62 | 63 | # clean up names 64 | vc <- vc %>% 65 | dplyr::mutate( 66 | effect = rownames(vc), 67 | effect = gsub(effect, pattern = "s\\(|ti\\(|te\\(|\\)", replacement = '') 68 | ) 69 | 70 | # if more two after split, suggests random slope 71 | vc <- vc %>% 72 | dplyr::mutate( 73 | group = split_group_effect(effect, which = 2), 74 | group = ifelse(group == 'scale', 'Residual', group), 75 | effect = split_group_effect(effect, which = 1), 76 | effect = ifelse(effect == 'scale', '', effect), 77 | effect = ifelse(effect == group, 'Intercept', effect) 78 | ) 79 | 80 | # calc variance and scale 81 | vc <- vc %>% 82 | dplyr::mutate( 83 | variance = std.dev^2, 84 | var_prop = variance / sum(variance) 85 | ) %>% 86 | dplyr::rename(sd = std.dev) 87 | 88 | lower <- (1 - ci_level) / 2 89 | upper <- 1 - lower 90 | 91 | if (ci_scale == 'var') { 92 | vc <- vc %>% 93 | dplyr::mutate(lower = lower^2, upper = upper^2) 94 | 95 | colnames(vc)[colnames(vc) %in% c('lower', 'upper')] <- 96 | c(paste0('var_', 100 * lower), paste0('var_', 100 * upper)) 97 | } 98 | else { 99 | colnames(vc)[colnames(vc) %in% c('lower', 'upper')] <- 100 | c(paste0('sd_', 100 * lower), paste0('sd_', 100 * upper)) 101 | } 102 | 103 | vc %>% 104 | dplyr::select(group, effect, variance, dplyr::everything()) %>% 105 | dplyr::mutate_if(is.numeric, round, digits = digits) 106 | } 107 | -------------------------------------------------------------------------------- /R/gammit-package.R: -------------------------------------------------------------------------------- 1 | #' @keywords internal 2 | "_PACKAGE" 3 | 4 | # The following block is used by usethis to automatically manage 5 | # roxygen namespace tags. Modify with care! 6 | ## usethis namespace: start 7 | #' @name gammit-package 8 | #' @title gammit: Using Generalized Additive Mixed Models 9 | ## usethis namespace: end 10 | NULL 11 | -------------------------------------------------------------------------------- /R/globals.R: -------------------------------------------------------------------------------- 1 | # so that check ignores 2 | utils::globalVariables( 3 | c( 4 | 'Term', 5 | 'term', 6 | 'group', 7 | 'group_var', 8 | 'effect', 9 | 'value', 10 | 'se', 11 | 'std.dev', 12 | 'variance' 13 | ) 14 | ) 15 | -------------------------------------------------------------------------------- /R/predict_gamm.R: -------------------------------------------------------------------------------- 1 | #' Make predictions with or without random effects 2 | #' 3 | #' @description Use predict in an `lme4` style on gam/bam objects from \code{\link{mgcv}}. 4 | #' @param model A gam class model from the \code{\link{mgcv}} package. 5 | #' @param newdata Data on which to predict on. Empty by default. 6 | #' @param re_form `NULL`, `NA`, or character string. If `NULL` (default), all 7 | #' random effects will be used. If NA, no random effects will be used. If 8 | #' character, must be of the form `"s(varname)"`, where `varname` would be the 9 | #' name of the grouping variable pertaining to the random effect. Appended to 10 | #' `include`. 11 | #' @param se Logical. Include standard errors or not. Default is FALSE. 12 | #' @param include Which random effects to include in prediction. See 13 | #' \code{\link{predict.gam}} for details. 14 | #' @param exclude Which random effects to exclude in prediction. See 15 | #' \code{\link{predict.gam}} for details. 16 | #' @param keep_prediction_data Keep the model frame or newdata that was used in 17 | #' the prediction in final output? Default is FALSE. 18 | #' @param ... Other arguments for \code{\link{predict.gam}}. 19 | #' 20 | #' @details This is a wrapper for \code{\link{predict.gam}}. The goal is to 21 | #' have similar functionality with predict function in `lme4`, which makes it 22 | #' easy to drop all random effects or include specific ones. Some of this 23 | #' functionality is not yet available for class `bam`. 24 | #' 25 | #' @return A data frame of predictions and possibly standard errors. 26 | #' 27 | #' @seealso \code{\link{predict.gam}} 28 | #' 29 | #' @importFrom stats predict 30 | #' @examples 31 | #' library(lme4) 32 | #' library(mgcv) 33 | #' lmer_model <- lmer(Reaction ~ Days + (Days || Subject), data = sleepstudy) 34 | #' ga_model <- gam(Reaction ~ Days + s(Subject, bs = "re") + s(Days, Subject, bs = "re"), 35 | #' data = sleepstudy, 36 | #' method = "REML" 37 | #' ) 38 | #' 39 | #' head( 40 | #' data.frame( 41 | #' lmer = predict(lmer_model), 42 | #' gam = predict_gamm(ga_model) 43 | #' ) 44 | #' ) 45 | #' 46 | #' head( 47 | #' cbind( 48 | #' lmer = predict(lmer_model, re.form = NA), 49 | #' gam1 = predict_gamm(ga_model, re_form = NA), 50 | #' gam2 = predict_gamm(ga_model, 51 | #' exclude = c("s(Subject)", "s(Days,Subject)") 52 | #' ) 53 | #' ) 54 | #' ) 55 | #' 56 | #' head(predict_gamm(ga_model, se = TRUE)) 57 | #' @export 58 | predict_gamm <- function( 59 | model, 60 | newdata, 61 | re_form = NULL, 62 | se = FALSE, 63 | include = NULL, 64 | exclude = NULL, 65 | keep_prediction_data = FALSE, 66 | ...) { 67 | 68 | # Note because predict doesn't use NULL, can't use NULL for new_data arg or 69 | # even a differently named arg, and I'm not going into the weeds of rlang to 70 | # find a hack. 71 | 72 | # basic checks 73 | if (!inherits(model, "gam")) stop("Need a gam object.") 74 | 75 | if (!rlang::is_null(include) && !rlang::is_character(include)) { 76 | stop("include must be NULL or character.") 77 | } 78 | 79 | if (!rlang::is_null(exclude) && !rlang::is_character(exclude)) { 80 | stop("exclude must be NULL or character.") 81 | } 82 | 83 | if (!rlang::is_null(re_form) && 84 | !rlang::is_na(re_form) & 85 | !rlang::is_character(re_form)) { 86 | stop("re_form must be NULL, NA, or character.") 87 | } 88 | 89 | if (any(include %in% exclude)) { 90 | stop("You can't include and exclude the same thing.") 91 | } 92 | 93 | if (!rlang::is_logical(se)) { 94 | stop("se must be TRUE or FALSE") 95 | } 96 | 97 | if (!rlang::is_logical(keep_prediction_data)) { 98 | stop("keep_prediction_data must be TRUE or FALSE") 99 | } 100 | 101 | # standard prediction would simply call predict.gam 102 | if (rlang::is_null(re_form) | rlang::is_character(re_form)) { 103 | if (rlang::is_null(re_form)) { 104 | preds <- predict(model, 105 | newdata, 106 | se = se, 107 | terms = include, 108 | exclude = exclude, 109 | ... 110 | ) 111 | } else { 112 | preds <- predict(model, 113 | newdata, 114 | se = se, 115 | terms = c(include, re_form), 116 | exclude = exclude, 117 | ... 118 | ) 119 | } 120 | } else if (rlang::is_na(re_form)) { 121 | 122 | # FE only 123 | re_terms <- sapply(model$smooth, function(x) inherits(x, "random.effect")) 124 | re_terms <- sapply(model$smooth[re_terms], function(x) x$label) 125 | 126 | preds <- predict(model, 127 | newdata, 128 | se = se, 129 | terms = include, 130 | exclude = c(re_terms, exclude), 131 | ... 132 | ) 133 | } 134 | 135 | if (se) { 136 | preds <- data.frame(prediction = preds$fit, se = preds$se) 137 | } else { 138 | preds <- data.frame(prediction = preds) 139 | } 140 | 141 | if (keep_prediction_data) { 142 | if (missing(newdata)) { 143 | base <- model$model 144 | } else { 145 | base <- newdata 146 | } 147 | preds <- data.frame(base, preds) 148 | } 149 | 150 | preds 151 | } 152 | -------------------------------------------------------------------------------- /R/summary_gamm.R: -------------------------------------------------------------------------------- 1 | #' Summarize a GAMM 2 | #' 3 | #' @description Summarize a gam model in a clean mixed effects style. 4 | #' @param model The mgcv model 5 | #' @param digits number of digits to display 6 | #' 7 | #' @details This displays the variance components and fixed effects from a gam 8 | #' model. Assumes an mgcv model of the form `gam(... + s(g, bs='re'))`, 9 | #' but should work with just about any gam with a smooth term. 10 | #' 11 | #' @return Invisibly returns a list with the variance components via 12 | #' `extract_vc` and fixed effects parameter, labeled `vc` and `fe` 13 | #' respectively. 14 | #' 15 | #' @seealso \code{\link{extract_vc}} 16 | #' 17 | #' @examples 18 | #' library(mgcv) 19 | #' library(lme4) 20 | #' 21 | #' lmer_model <- lmer(Reaction ~ Days + (Days || Subject), data = sleepstudy) 22 | #' ga_model <- gam(Reaction ~ Days + s(Subject, bs = "re") + s(Days, Subject, bs = "re"), 23 | #' data = sleepstudy, 24 | #' method = "REML" 25 | #' ) 26 | #' 27 | #' summary(lmer_model) 28 | #' summary_gamm(ga_model) 29 | #' @export 30 | summary_gamm <- function(model, digits = 3) { 31 | if (!inherits(model, "gam")) stop("Need a gam object.") 32 | 33 | summary_table <- mgcv::summary.gam(model)$p.table 34 | 35 | vc <- extract_vc(model) 36 | 37 | fe <- data.frame(round(summary_table, digits = digits)) 38 | names(fe) <- colnames(summary_table) 39 | fe$Term <- rownames(summary_table) 40 | fe <- dplyr::select(fe, Term, dplyr::everything()) 41 | rownames(fe) <- NULL 42 | 43 | # re part 44 | message("\nVariance components:\n") 45 | 46 | print( 47 | format( 48 | dplyr::mutate_if(vc, 49 | is.numeric, 50 | round, 51 | digits = digits 52 | ), 53 | nsmall = digits 54 | ), 55 | row.names = FALSE 56 | ) 57 | 58 | # fe part 59 | message("\n\nFixed Effects:\n") 60 | 61 | print(format(fe, nsmall = digits), row.names = FALSE) 62 | 63 | 64 | invisible(list(vc = vc, fe = fe)) 65 | } 66 | -------------------------------------------------------------------------------- /R/utils-pipe.R: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-clark/gammit/b1500bdabc48c76bd8ebfdb0ca4531e88ae50b70/R/utils-pipe.R -------------------------------------------------------------------------------- /R/utils.R: -------------------------------------------------------------------------------- 1 | #' @importFrom visibly plot_gam plot_gam_2d plot_gam_3d plot_gam_by plot_gam_check 2 | #' @importFrom dplyr %>% 3 | #' 4 | #' @export 5 | visibly::plot_gam 6 | #' @export 7 | visibly::plot_gam_2d 8 | #' @export 9 | visibly::plot_gam_3d 10 | #' @export 11 | visibly::plot_gam_by 12 | #' @export 13 | visibly::plot_gam_check 14 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: 3 | github_document: 4 | toc: false # doesn't show well on website, where it isn't really needed 5 | --- 6 | 7 | 8 | 9 | ```{r setup, include = FALSE} 10 | knitr::opts_chunk$set( 11 | collapse = TRUE, 12 | comment = NA, 13 | fig.path = "man/figures/README-", 14 | out.width = "100%" 15 | ) 16 | ``` 17 | # gammit 18 | 19 | This package was specifically for mixed models using mgcv. At present it has been almost entirely superseded by the [mixedup](https://m-clark.github.io/mixedup/) package, which provides all the same functionality and more, while the visualizations were originally from the [visibly](https://m-clark.github.io/visibly/) package anyway. That only leaves the prediction functionality as unique to this package, so I leave it here as I may still use it for that, and I'm contemplating moving the GAM specific visuals from visibly at some point. 20 | 21 | 22 | # Package Description 23 | 24 | 25 | [![Travis build status](https://travis-ci.org/m-clark/gammit.svg?branch=master)](https://travis-ci.org/m-clark/gammit) 26 | [![AppVeyor build status](https://ci.appveyor.com/api/projects/status/github/m-clark/gammit?branch=master&svg=true)](https://ci.appveyor.com/project/m-clark/gammit) 27 | [![Codecov test coverage](https://codecov.io/gh/m-clark/gammit/branch/master/graph/badge.svg)](https://codecov.io/gh/m-clark/gammit?branch=master) 28 | [![Lifecycle: superseded](https://img.shields.io/badge/lifecycle-superseded-orange.svg)](https://www.tidyverse.org/lifecycle/#superseded) 29 | 30 | 31 | ## Introduction 32 | 33 | The goal of gammit is to provide a set of functions to aid using mgcv (possibly solely) for mixed models. Lately I've been using it in lieu of lme4, especially the bam function, for GLMM with millions of observations and multiple random effects. It's turning out very useful in this sense (see [this post](https://m-clark.github.io/posts/2019-10-20-big-mixed-models/) for details), but I'd like some more/different functionality with the results. Furthermore, mgcv just has some nice things going on for such models anyway, like the ability to add other smooth terms, alternative distributions for the target variable, etc., so I'm looking to make it easier for me to get some things I want when I use it. 34 | 35 | At present there are four functions: extract_vc, extract_ranef, extract_fixed, summary_gamm, and predict_gamm. 36 | 37 | ## Installation 38 | 39 | You can install the development version from [GitHub](https://github.com/) with: 40 | 41 | ``` r 42 | # install.packages("devtools") 43 | devtools::install_github("m-clark/gammit") 44 | ``` 45 | 46 | ## Example 47 | 48 | This example demonstrates the summary_gamm function with comparison to the corresponding lme4 model. 49 | 50 | ```{r summary} 51 | library(mgcv) 52 | library(lme4) 53 | library(gammit) 54 | 55 | lmer_model = lmer(Reaction ~ Days + (Days || Subject), data=sleepstudy) 56 | 57 | ga_model = gam(Reaction ~ Days + s(Subject, bs='re') + s(Days, Subject, bs='re'), 58 | data=sleepstudy, 59 | method = 'REML') 60 | 61 | summary(lmer_model) 62 | 63 | 64 | summary_gamm(ga_model) 65 | ``` 66 | 67 | Extract the variance components with extract_vc. 68 | 69 | ```{r extract_vc} 70 | data.frame(VarCorr(lmer_model)) 71 | 72 | 73 | extract_vc(ga_model) 74 | ``` 75 | 76 | 77 | Extract the random effects with extract_ranef. 78 | 79 | ```{r extract_ranef} 80 | ranef(lmer_model) 81 | 82 | 83 | extract_ranef(ga_model) 84 | ``` 85 | 86 | Extract the fixed effects extract_fixef. 87 | 88 | ```{r extract_fixed} 89 | fixef(lmer_model) 90 | 91 | 92 | extract_fixed(ga_model) 93 | ``` 94 | 95 | 96 | ## Prediction 97 | 98 | There are a couple of ways to do prediction, and the main goal for gammit was to make it easy to use the lme4 style to include random effects or not. mgcv already has this functionality as well, so the functionality of predict_gamm is mostly cosmetic. One benefit here is to provide standard errors for the prediction also. 99 | 100 | ```{r predict_gamm} 101 | head(predict_gamm(ga_model)) 102 | ``` 103 | 104 | Add standard errors. 105 | 106 | ```{r predict_gamm_se} 107 | head(data.frame(predict_gamm(ga_model, se=T))) 108 | ``` 109 | 110 | ```{r predict_gamm_fe} 111 | compare = data.frame( 112 | gam_original = predict_gamm(ga_model)$prediction, 113 | gam_fe_only = predict_gamm(ga_model, re_form = NA)$prediction, 114 | gam_fe_only2 = predict_gamm(ga_model, 115 | exclude = c('s(Subject)', "s(Days,Subject)"))$prediction, 116 | lme4_fe_only = predict(lmer_model, re.form = NA)) 117 | 118 | head(compare) 119 | ``` 120 | 121 | Along with that, one can still use include/exclude for other smooth terms as above. Unfortunately, some options do not yet work with bam objects, but this is to due to the functionality in predict.gam from mgcv and should change in the near future. 122 | 123 | 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # gammit 5 | 6 | This package was specifically for mixed models using mgcv. At present it 7 | has been almost entirely superseded by the 8 | [mixedup](https://m-clark.github.io/mixedup/) package, which provides 9 | all the same functionality and more, while the visualizations were 10 | originally from the [visibly](https://m-clark.github.io/visibly/) 11 | package anyway. That only leaves the prediction functionality as unique 12 | to this package, so I leave it here as I may still use it for that, and 13 | I’m contemplating moving the GAM specific visuals from visibly at some 14 | point. 15 | 16 | # Package Description 17 | 18 | 19 | 20 | [![Travis build 21 | status](https://travis-ci.org/m-clark/gammit.svg?branch=master)](https://travis-ci.org/m-clark/gammit) 22 | [![AppVeyor build 23 | status](https://ci.appveyor.com/api/projects/status/github/m-clark/gammit?branch=master&svg=true)](https://ci.appveyor.com/project/m-clark/gammit) 24 | [![Codecov test 25 | coverage](https://codecov.io/gh/m-clark/gammit/branch/master/graph/badge.svg)](https://codecov.io/gh/m-clark/gammit?branch=master) 26 | [![Lifecycle: 27 | superseded](https://img.shields.io/badge/lifecycle-superseded-orange.svg)](https://www.tidyverse.org/lifecycle/#superseded) 28 | 29 | 30 | ## Introduction 31 | 32 | The goal of gammit is to provide a set of functions to aid using 33 | mgcv (possibly solely) for mixed 34 | models. Lately I’ve been using it in lieu of 35 | lme4, especially the 36 | bam function, for GLMM with millions 37 | of observations and multiple random effects. It’s turning out very 38 | useful in this sense (see [this 39 | post](https://m-clark.github.io/posts/2019-10-20-big-mixed-models/) for 40 | details), but I’d like some more/different functionality with the 41 | results. Furthermore, mgcv just has 42 | some nice things going on for such models anyway, like the ability to 43 | add other smooth terms, alternative distributions for the target 44 | variable, etc., so I’m looking to make it easier for me to get some 45 | things I want when I use it. 46 | 47 | At present there are four functions: 48 | extract\_vc, 49 | extract\_ranef, 50 | extract\_fixed, 51 | summary\_gamm, and 52 | predict\_gamm. 53 | 54 | ## Installation 55 | 56 | You can install the development version from 57 | [GitHub](https://github.com/) with: 58 | 59 | ``` r 60 | # install.packages("devtools") 61 | devtools::install_github("m-clark/gammit") 62 | ``` 63 | 64 | ## Example 65 | 66 | This example demonstrates the 67 | summary\_gamm function with 68 | comparison to the corresponding lme4 69 | model. 70 | 71 | ``` r 72 | library(mgcv) 73 | Loading required package: nlme 74 | This is mgcv 1.8-31. For overview type 'help("mgcv-package")'. 75 | library(lme4) 76 | Loading required package: Matrix 77 | 78 | Attaching package: 'lme4' 79 | The following object is masked from 'package:nlme': 80 | 81 | lmList 82 | library(gammit) 83 | 84 | lmer_model = lmer(Reaction ~ Days + (Days || Subject), data=sleepstudy) 85 | 86 | ga_model = gam(Reaction ~ Days + s(Subject, bs='re') + s(Days, Subject, bs='re'), 87 | data=sleepstudy, 88 | method = 'REML') 89 | 90 | summary(lmer_model) 91 | Linear mixed model fit by REML ['lmerMod'] 92 | Formula: Reaction ~ Days + ((1 | Subject) + (0 + Days | Subject)) 93 | Data: sleepstudy 94 | 95 | REML criterion at convergence: 1743.7 96 | 97 | Scaled residuals: 98 | Min 1Q Median 3Q Max 99 | -3.9626 -0.4625 0.0204 0.4653 5.1860 100 | 101 | Random effects: 102 | Groups Name Variance Std.Dev. 103 | Subject (Intercept) 627.57 25.051 104 | Subject.1 Days 35.86 5.988 105 | Residual 653.58 25.565 106 | Number of obs: 180, groups: Subject, 18 107 | 108 | Fixed effects: 109 | Estimate Std. Error t value 110 | (Intercept) 251.405 6.885 36.513 111 | Days 10.467 1.560 6.712 112 | 113 | Correlation of Fixed Effects: 114 | (Intr) 115 | Days -0.184 116 | 117 | 118 | summary_gamm(ga_model) 119 | 120 | Variance components: 121 | group effect variance sd sd_2.5 sd_97.5 var_prop 122 | Subject Intercept 627.571 25.051 16.085 39.015 0.477 123 | Subject Days 35.858 5.988 4.025 8.908 0.027 124 | Residual 653.582 25.565 22.792 28.676 0.496 125 | 126 | 127 | Fixed Effects: 128 | Term Estimate Std. Error t value Pr(>|t|) 129 | (Intercept) 251.405 6.885 36.513 0.000 130 | Days 10.467 1.560 6.712 0.000 131 | ``` 132 | 133 | Extract the variance components with 134 | extract\_vc. 135 | 136 | ``` r 137 | data.frame(VarCorr(lmer_model)) 138 | grp var1 var2 vcov sdcor 139 | 1 Subject (Intercept) 627.56905 25.051328 140 | 2 Subject.1 Days 35.85838 5.988187 141 | 3 Residual 653.58350 25.565279 142 | 143 | 144 | extract_vc(ga_model) 145 | group effect variance sd sd_2.5 sd_97.5 var_prop 146 | 1 Subject Intercept 627.571 25.051 16.085 39.015 0.477 147 | 2 Subject Days 35.858 5.988 4.025 8.908 0.027 148 | 3 Residual 653.582 25.565 22.792 28.676 0.496 149 | ``` 150 | 151 | Extract the random effects with 152 | extract\_ranef. 153 | 154 | ``` r 155 | ranef(lmer_model) 156 | $Subject 157 | (Intercept) Days 158 | 308 1.5126648 9.3234970 159 | 309 -40.3738728 -8.5991757 160 | 310 -39.1810279 -5.3877944 161 | 330 24.5189244 -4.9686503 162 | 331 22.9144470 -3.1939378 163 | 332 9.2219759 -0.3084939 164 | 333 17.1561243 -0.2872078 165 | 334 -7.4517382 1.1159911 166 | 335 0.5787623 -10.9059754 167 | 337 34.7679030 8.6276228 168 | 349 -25.7543312 1.2806892 169 | 350 -13.8650598 6.7564064 170 | 351 4.9159912 -3.0751356 171 | 352 20.9290332 3.5122123 172 | 369 3.2586448 0.8730514 173 | 370 -26.4758468 4.9837910 174 | 371 0.9056510 -1.0052938 175 | 372 12.4217547 1.2584037 176 | 177 | with conditional variances for "Subject" 178 | 179 | 180 | extract_ranef(ga_model) 181 | # A tibble: 36 x 7 182 | group_var effect group value se lower_2.5 upper_97.5 183 | 184 | 1 Subject Intercept 308 1.51 13.3 -24.5 27.5 185 | 2 Subject Intercept 309 -40.4 13.3 -66.4 -14.3 186 | 3 Subject Intercept 310 -39.2 13.3 -65.2 -13.2 187 | 4 Subject Intercept 330 24.5 13.3 -1.51 50.5 188 | 5 Subject Intercept 331 22.9 13.3 -3.11 48.9 189 | 6 Subject Intercept 332 9.22 13.3 -16.8 35.2 190 | 7 Subject Intercept 333 17.2 13.3 -8.87 43.2 191 | 8 Subject Intercept 334 -7.45 13.3 -33.5 18.6 192 | 9 Subject Intercept 335 0.579 13.3 -25.4 26.6 193 | 10 Subject Intercept 337 34.8 13.3 8.74 60.8 194 | # … with 26 more rows 195 | ``` 196 | 197 | Extract the fixed effects 198 | extract\_fixef. 199 | 200 | ``` r 201 | fixef(lmer_model) 202 | (Intercept) Days 203 | 251.40510 10.46729 204 | 205 | 206 | extract_fixed(ga_model) 207 | # A tibble: 2 x 7 208 | term value se t p lower_2.5 upper_97.5 209 | 210 | 1 Intercept 251. 6.88 36.5 0 238. 265. 211 | 2 Days 10.5 1.56 6.71 0 7.39 13.5 212 | ``` 213 | 214 | ## Prediction 215 | 216 | There are a couple of ways to do prediction, and the main goal for 217 | gammit was to make it easy to use the 218 | lme4 style to include random effects 219 | or not. mgcv already has this 220 | functionality as well, so the functionality of 221 | predict\_gamm is mostly cosmetic. One 222 | benefit here is to provide standard errors for the prediction also. 223 | 224 | ``` r 225 | head(predict_gamm(ga_model)) 226 | prediction 227 | 1 252.9178 228 | 2 272.7086 229 | 3 292.4994 230 | 4 312.2901 231 | 5 332.0809 232 | 6 351.8717 233 | ``` 234 | 235 | Add standard errors. 236 | 237 | ``` r 238 | head(data.frame(predict_gamm(ga_model, se=T))) 239 | prediction se 240 | 1 252.9178 12.410220 241 | 2 272.7086 10.660891 242 | 3 292.4994 9.191224 243 | 4 312.2901 8.153871 244 | 5 332.0809 7.724998 245 | 6 351.8717 8.003034 246 | ``` 247 | 248 | ``` r 249 | compare = data.frame( 250 | gam_original = predict_gamm(ga_model)$prediction, 251 | gam_fe_only = predict_gamm(ga_model, re_form = NA)$prediction, 252 | gam_fe_only2 = predict_gamm(ga_model, 253 | exclude = c('s(Subject)', "s(Days,Subject)"))$prediction, 254 | lme4_fe_only = predict(lmer_model, re.form = NA)) 255 | 256 | head(compare) 257 | gam_original gam_fe_only gam_fe_only2 lme4_fe_only 258 | 1 252.9178 251.4051 251.4051 251.4051 259 | 2 272.7086 261.8724 261.8724 261.8724 260 | 3 292.4994 272.3397 272.3397 272.3397 261 | 4 312.2901 282.8070 282.8070 282.8070 262 | 5 332.0809 293.2742 293.2742 293.2742 263 | 6 351.8717 303.7415 303.7415 303.7415 264 | ``` 265 | 266 | Along with that, one can still use include/exclude for other smooth 267 | terms as above. Unfortunately, some options do not yet work with 268 | bam objects, but this is to due 269 | to the functionality in predict.gam 270 | from mgcv and should change in the 271 | near future. 272 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | title: 'gammit' 2 | title-img: logo.png 3 | 4 | authors: 5 | Michael Clark: 6 | href: https://m-clark.github.io 7 | html: 8 | 9 | template: 10 | params: 11 | highlight: pygments 12 | #bootswatch: sandstone 13 | templates_path: inst/pkgdown 14 | 15 | highlight: pygments 16 | 17 | 18 | home: 19 | #strip_header: true 20 | links: 21 | - text: Docs on Stats, R, and more 22 | href: http://m-clark.github.io 23 | 24 | reference: 25 | - title: "Extraction" 26 | desc: > 27 | Get variance components, random effects, etc. 28 | contents: 29 | - extract_fixed 30 | - extract_vc 31 | - extract_ranef 32 | 33 | - title: "Summarize and predict" 34 | desc: > 35 | lme4-style summary and prediction tools. 36 | contents: 37 | - summary_gamm 38 | - predict_gamm 39 | 40 | - title: "Visualization" 41 | desc: > 42 | Visualization functions from visibly. 43 | contents: 44 | - plot_gam 45 | 46 | 47 | figures: 48 | dev: png 49 | dpi: 96 50 | dev.args: [] 51 | fig.ext: png 52 | fig.width: 7.2916667 53 | fig.height: ~ 54 | fig.retina: 2 55 | fig.asp: 1.618 56 | 57 | navbar: 58 | title: "gammit" 59 | type: ~ 60 | left: 61 | - text: "Reference" 62 | href: "reference/index.html" 63 | - text: "News" 64 | href: "news/index.html" 65 | # - text: Articles 66 | # menu: 67 | # - text: Demo 68 | # href: articles/Demo.html 69 | right: 70 | - icon: fa-github-alt 71 | href: https://github.com/m-clark 72 | - icon: fa-empire 73 | href: https://m-clark.github.io 74 | 75 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # DO NOT CHANGE the "init" and "install" sections below 2 | 3 | # Download script file from GitHub 4 | init: 5 | ps: | 6 | $ErrorActionPreference = "Stop" 7 | Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1" 8 | Import-Module '..\appveyor-tool.ps1' 9 | 10 | install: 11 | ps: Bootstrap 12 | 13 | cache: 14 | - C:\RLibrary 15 | 16 | environment: 17 | NOT_CRAN: true 18 | # env vars that may need to be set, at least temporarily, from time to time 19 | # see https://github.com/krlmlr/r-appveyor#readme for details 20 | USE_RTOOLS: true 21 | R_REMOTES_STANDALONE: true 22 | 23 | # Adapt as necessary starting from here 24 | 25 | build_script: 26 | - travis-tool.sh install_deps 27 | 28 | test_script: 29 | - travis-tool.sh run_tests 30 | 31 | on_failure: 32 | - 7z a failure.zip *.Rcheck\* 33 | - appveyor PushArtifact failure.zip 34 | 35 | artifacts: 36 | - path: '*.Rcheck\**\*.log' 37 | name: Logs 38 | 39 | - path: '*.Rcheck\**\*.out' 40 | name: Logs 41 | 42 | - path: '*.Rcheck\**\*.fail' 43 | name: Logs 44 | 45 | - path: '*.Rcheck\**\*.Rout' 46 | name: Logs 47 | 48 | - path: '\*_*.tar.gz' 49 | name: Bits 50 | 51 | - path: '\*_*.zip' 52 | name: Bits 53 | -------------------------------------------------------------------------------- /code-of-conduct.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies within all project spaces, and it also applies when 49 | an individual is representing the project or its community in public spaces. 50 | Examples of representing a project or community include using an official 51 | project e-mail address, posting via an official social media account, or acting 52 | as an appointed representative at an online or offline event. Representation of 53 | a project may be further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at [INSERT EMAIL ADDRESS]. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | 78 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | patch: 10 | default: 11 | target: auto 12 | threshold: 1% 13 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Page not found (404) • gammit 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
64 |
65 | 107 | 108 | 109 | 110 |
111 | 112 |
113 |
114 | 117 | 118 | Content not found. Please use links in the navbar. 119 | 120 |
121 | 122 | 127 | 128 |
129 | 130 | 131 | 132 |
133 | 136 | 137 |
138 |

Site built with pkgdown 1.6.1.

139 |
140 | 141 |
142 |
143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /docs/LICENSE-text.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | License • gammit 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
64 |
65 | 107 | 108 | 109 | 110 |
111 | 112 |
113 |
114 | 117 | 118 |
YEAR: 2019
119 | COPYRIGHT HOLDER: Michael Clark
120 | 
121 | 122 |
123 | 124 | 129 | 130 |
131 | 132 | 133 | 134 |
135 | 138 | 139 |
140 |

Site built with pkgdown 1.6.1.

141 |
142 | 143 |
144 |
145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /docs/LICENSE.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | MIT License • gammit 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
64 |
65 | 107 | 108 | 109 | 110 |
111 | 112 |
113 |
114 | 117 | 118 |
119 | 120 |

Copyright (c) 2019 Michael Clark

121 |

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

122 |

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

123 |

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

124 |
125 | 126 |
127 | 128 | 133 | 134 |
135 | 136 | 137 | 138 |
139 | 142 | 143 |
144 |

Site built with pkgdown 1.6.1.

145 |
146 | 147 |
148 |
149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /docs/authors.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Authors • gammit 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
64 |
65 | 107 | 108 | 109 | 110 |
111 | 112 |
113 |
114 | 117 | 118 |
    119 |
  • 120 |

    . Author, maintainer. 121 |

    122 |
  • 123 |
124 | 125 |
126 | 127 |
128 | 129 | 130 | 131 |
132 | 135 | 136 |
137 |

Site built with pkgdown 1.6.1.

138 |
139 | 140 |
141 |
142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /docs/bootstrap-toc.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | 6 | /* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ 7 | 8 | /* All levels of nav */ 9 | nav[data-toggle='toc'] .nav > li > a { 10 | display: block; 11 | padding: 4px 20px; 12 | font-size: 13px; 13 | font-weight: 500; 14 | color: #767676; 15 | } 16 | nav[data-toggle='toc'] .nav > li > a:hover, 17 | nav[data-toggle='toc'] .nav > li > a:focus { 18 | padding-left: 19px; 19 | color: #563d7c; 20 | text-decoration: none; 21 | background-color: transparent; 22 | border-left: 1px solid #563d7c; 23 | } 24 | nav[data-toggle='toc'] .nav > .active > a, 25 | nav[data-toggle='toc'] .nav > .active:hover > a, 26 | nav[data-toggle='toc'] .nav > .active:focus > a { 27 | padding-left: 18px; 28 | font-weight: bold; 29 | color: #563d7c; 30 | background-color: transparent; 31 | border-left: 2px solid #563d7c; 32 | } 33 | 34 | /* Nav: second level (shown on .active) */ 35 | nav[data-toggle='toc'] .nav .nav { 36 | display: none; /* Hide by default, but at >768px, show it */ 37 | padding-bottom: 10px; 38 | } 39 | nav[data-toggle='toc'] .nav .nav > li > a { 40 | padding-top: 1px; 41 | padding-bottom: 1px; 42 | padding-left: 30px; 43 | font-size: 12px; 44 | font-weight: normal; 45 | } 46 | nav[data-toggle='toc'] .nav .nav > li > a:hover, 47 | nav[data-toggle='toc'] .nav .nav > li > a:focus { 48 | padding-left: 29px; 49 | } 50 | nav[data-toggle='toc'] .nav .nav > .active > a, 51 | nav[data-toggle='toc'] .nav .nav > .active:hover > a, 52 | nav[data-toggle='toc'] .nav .nav > .active:focus > a { 53 | padding-left: 28px; 54 | font-weight: 500; 55 | } 56 | 57 | /* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ 58 | nav[data-toggle='toc'] .nav > .active > ul { 59 | display: block; 60 | } 61 | -------------------------------------------------------------------------------- /docs/bootstrap-toc.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | (function() { 6 | 'use strict'; 7 | 8 | window.Toc = { 9 | helpers: { 10 | // return all matching elements in the set, or their descendants 11 | findOrFilter: function($el, selector) { 12 | // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/ 13 | // http://stackoverflow.com/a/12731439/358804 14 | var $descendants = $el.find(selector); 15 | return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); 16 | }, 17 | 18 | generateUniqueIdBase: function(el) { 19 | var text = $(el).text(); 20 | var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); 21 | return anchor || el.tagName.toLowerCase(); 22 | }, 23 | 24 | generateUniqueId: function(el) { 25 | var anchorBase = this.generateUniqueIdBase(el); 26 | for (var i = 0; ; i++) { 27 | var anchor = anchorBase; 28 | if (i > 0) { 29 | // add suffix 30 | anchor += '-' + i; 31 | } 32 | // check if ID already exists 33 | if (!document.getElementById(anchor)) { 34 | return anchor; 35 | } 36 | } 37 | }, 38 | 39 | generateAnchor: function(el) { 40 | if (el.id) { 41 | return el.id; 42 | } else { 43 | var anchor = this.generateUniqueId(el); 44 | el.id = anchor; 45 | return anchor; 46 | } 47 | }, 48 | 49 | createNavList: function() { 50 | return $(''); 51 | }, 52 | 53 | createChildNavList: function($parent) { 54 | var $childList = this.createNavList(); 55 | $parent.append($childList); 56 | return $childList; 57 | }, 58 | 59 | generateNavEl: function(anchor, text) { 60 | var $a = $(''); 61 | $a.attr('href', '#' + anchor); 62 | $a.text(text); 63 | var $li = $('
  • '); 64 | $li.append($a); 65 | return $li; 66 | }, 67 | 68 | generateNavItem: function(headingEl) { 69 | var anchor = this.generateAnchor(headingEl); 70 | var $heading = $(headingEl); 71 | var text = $heading.data('toc-text') || $heading.text(); 72 | return this.generateNavEl(anchor, text); 73 | }, 74 | 75 | // Find the first heading level (`

    `, then `

    `, etc.) that has more than one element. Defaults to 1 (for `

    `). 76 | getTopLevel: function($scope) { 77 | for (var i = 1; i <= 6; i++) { 78 | var $headings = this.findOrFilter($scope, 'h' + i); 79 | if ($headings.length > 1) { 80 | return i; 81 | } 82 | } 83 | 84 | return 1; 85 | }, 86 | 87 | // returns the elements for the top level, and the next below it 88 | getHeadings: function($scope, topLevel) { 89 | var topSelector = 'h' + topLevel; 90 | 91 | var secondaryLevel = topLevel + 1; 92 | var secondarySelector = 'h' + secondaryLevel; 93 | 94 | return this.findOrFilter($scope, topSelector + ',' + secondarySelector); 95 | }, 96 | 97 | getNavLevel: function(el) { 98 | return parseInt(el.tagName.charAt(1), 10); 99 | }, 100 | 101 | populateNav: function($topContext, topLevel, $headings) { 102 | var $context = $topContext; 103 | var $prevNav; 104 | 105 | var helpers = this; 106 | $headings.each(function(i, el) { 107 | var $newNav = helpers.generateNavItem(el); 108 | var navLevel = helpers.getNavLevel(el); 109 | 110 | // determine the proper $context 111 | if (navLevel === topLevel) { 112 | // use top level 113 | $context = $topContext; 114 | } else if ($prevNav && $context === $topContext) { 115 | // create a new level of the tree and switch to it 116 | $context = helpers.createChildNavList($prevNav); 117 | } // else use the current $context 118 | 119 | $context.append($newNav); 120 | 121 | $prevNav = $newNav; 122 | }); 123 | }, 124 | 125 | parseOps: function(arg) { 126 | var opts; 127 | if (arg.jquery) { 128 | opts = { 129 | $nav: arg 130 | }; 131 | } else { 132 | opts = arg; 133 | } 134 | opts.$scope = opts.$scope || $(document.body); 135 | return opts; 136 | } 137 | }, 138 | 139 | // accepts a jQuery object, or an options object 140 | init: function(opts) { 141 | opts = this.helpers.parseOps(opts); 142 | 143 | // ensure that the data attribute is in place for styling 144 | opts.$nav.attr('data-toggle', 'toc'); 145 | 146 | var $topContext = this.helpers.createChildNavList(opts.$nav); 147 | var topLevel = this.helpers.getTopLevel(opts.$scope); 148 | var $headings = this.helpers.getHeadings(opts.$scope, topLevel); 149 | this.helpers.populateNav($topContext, topLevel, $headings); 150 | } 151 | }; 152 | 153 | $(function() { 154 | $('nav[data-toggle="toc"]').each(function(i, el) { 155 | var $nav = $(el); 156 | Toc.init($nav); 157 | }); 158 | }); 159 | })(); 160 | -------------------------------------------------------------------------------- /docs/code-of-conduct.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Contributor Covenant Code of Conduct • gammit 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
    64 |
    65 | 107 | 108 | 109 | 110 |
    111 | 112 |
    113 |
    114 | 117 | 118 |
    119 | 120 |
    121 |

    122 | Our Pledge

    123 |

    In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.

    124 |
    125 |
    126 |

    127 | Our Standards

    128 |

    Examples of behavior that contributes to creating a positive environment include:

    129 |
      130 |
    • Using welcoming and inclusive language
    • 131 |
    • Being respectful of differing viewpoints and experiences
    • 132 |
    • Gracefully accepting constructive criticism
    • 133 |
    • Focusing on what is best for the community
    • 134 |
    • Showing empathy towards other community members
    • 135 |
    136 |

    Examples of unacceptable behavior by participants include:

    137 |
      138 |
    • The use of sexualized language or imagery and unwelcome sexual attention or advances
    • 139 |
    • Trolling, insulting/derogatory comments, and personal or political attacks
    • 140 |
    • Public or private harassment
    • 141 |
    • Publishing others’ private information, such as a physical or electronic address, without explicit permission
    • 142 |
    • Other conduct which could reasonably be considered inappropriate in a professional setting
    • 143 |
    144 |
    145 |
    146 |

    147 | Our Responsibilities

    148 |

    Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

    149 |

    Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

    150 |
    151 |
    152 |

    153 | Scope

    154 |

    This Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.

    155 |
    156 |
    157 |

    158 | Enforcement

    159 |

    Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [INSERT EMAIL ADDRESS]. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.

    160 |

    Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project’s leadership.

    161 |
    162 |
    163 |

    164 | Attribution

    165 |

    This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

    166 |

    For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq

    167 |
    168 |
    169 | 170 |
    171 | 172 | 177 | 178 |
    179 | 180 | 181 | 182 |
    183 | 186 | 187 |
    188 |

    Site built with pkgdown 1.6.1.

    189 |
    190 | 191 |
    192 |
    193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | -------------------------------------------------------------------------------- /docs/docsearch.css: -------------------------------------------------------------------------------- 1 | /* Docsearch -------------------------------------------------------------- */ 2 | /* 3 | Source: https://github.com/algolia/docsearch/ 4 | License: MIT 5 | */ 6 | 7 | .algolia-autocomplete { 8 | display: block; 9 | -webkit-box-flex: 1; 10 | -ms-flex: 1; 11 | flex: 1 12 | } 13 | 14 | .algolia-autocomplete .ds-dropdown-menu { 15 | width: 100%; 16 | min-width: none; 17 | max-width: none; 18 | padding: .75rem 0; 19 | background-color: #fff; 20 | background-clip: padding-box; 21 | border: 1px solid rgba(0, 0, 0, .1); 22 | box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .175); 23 | } 24 | 25 | @media (min-width:768px) { 26 | .algolia-autocomplete .ds-dropdown-menu { 27 | width: 175% 28 | } 29 | } 30 | 31 | .algolia-autocomplete .ds-dropdown-menu::before { 32 | display: none 33 | } 34 | 35 | .algolia-autocomplete .ds-dropdown-menu [class^=ds-dataset-] { 36 | padding: 0; 37 | background-color: rgb(255,255,255); 38 | border: 0; 39 | max-height: 80vh; 40 | } 41 | 42 | .algolia-autocomplete .ds-dropdown-menu .ds-suggestions { 43 | margin-top: 0 44 | } 45 | 46 | .algolia-autocomplete .algolia-docsearch-suggestion { 47 | padding: 0; 48 | overflow: visible 49 | } 50 | 51 | .algolia-autocomplete .algolia-docsearch-suggestion--category-header { 52 | padding: .125rem 1rem; 53 | margin-top: 0; 54 | font-size: 1.3em; 55 | font-weight: 500; 56 | color: #00008B; 57 | border-bottom: 0 58 | } 59 | 60 | .algolia-autocomplete .algolia-docsearch-suggestion--wrapper { 61 | float: none; 62 | padding-top: 0 63 | } 64 | 65 | .algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column { 66 | float: none; 67 | width: auto; 68 | padding: 0; 69 | text-align: left 70 | } 71 | 72 | .algolia-autocomplete .algolia-docsearch-suggestion--content { 73 | float: none; 74 | width: auto; 75 | padding: 0 76 | } 77 | 78 | .algolia-autocomplete .algolia-docsearch-suggestion--content::before { 79 | display: none 80 | } 81 | 82 | .algolia-autocomplete .ds-suggestion:not(:first-child) .algolia-docsearch-suggestion--category-header { 83 | padding-top: .75rem; 84 | margin-top: .75rem; 85 | border-top: 1px solid rgba(0, 0, 0, .1) 86 | } 87 | 88 | .algolia-autocomplete .ds-suggestion .algolia-docsearch-suggestion--subcategory-column { 89 | display: block; 90 | padding: .1rem 1rem; 91 | margin-bottom: 0.1; 92 | font-size: 1.0em; 93 | font-weight: 400 94 | /* display: none */ 95 | } 96 | 97 | .algolia-autocomplete .algolia-docsearch-suggestion--title { 98 | display: block; 99 | padding: .25rem 1rem; 100 | margin-bottom: 0; 101 | font-size: 0.9em; 102 | font-weight: 400 103 | } 104 | 105 | .algolia-autocomplete .algolia-docsearch-suggestion--text { 106 | padding: 0 1rem .5rem; 107 | margin-top: -.25rem; 108 | font-size: 0.8em; 109 | font-weight: 400; 110 | line-height: 1.25 111 | } 112 | 113 | .algolia-autocomplete .algolia-docsearch-footer { 114 | width: 110px; 115 | height: 20px; 116 | z-index: 3; 117 | margin-top: 10.66667px; 118 | float: right; 119 | font-size: 0; 120 | line-height: 0; 121 | } 122 | 123 | .algolia-autocomplete .algolia-docsearch-footer--logo { 124 | background-image: url("data:image/svg+xml;utf8,"); 125 | background-repeat: no-repeat; 126 | background-position: 50%; 127 | background-size: 100%; 128 | overflow: hidden; 129 | text-indent: -9000px; 130 | width: 100%; 131 | height: 100%; 132 | display: block; 133 | transform: translate(-8px); 134 | } 135 | 136 | .algolia-autocomplete .algolia-docsearch-suggestion--highlight { 137 | color: #FF8C00; 138 | background: rgba(232, 189, 54, 0.1) 139 | } 140 | 141 | 142 | .algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight { 143 | box-shadow: inset 0 -2px 0 0 rgba(105, 105, 105, .5) 144 | } 145 | 146 | .algolia-autocomplete .ds-suggestion.ds-cursor .algolia-docsearch-suggestion--content { 147 | background-color: rgba(192, 192, 192, .15) 148 | } 149 | -------------------------------------------------------------------------------- /docs/docsearch.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | // register a handler to move the focus to the search bar 4 | // upon pressing shift + "/" (i.e. "?") 5 | $(document).on('keydown', function(e) { 6 | if (e.shiftKey && e.keyCode == 191) { 7 | e.preventDefault(); 8 | $("#search-input").focus(); 9 | } 10 | }); 11 | 12 | $(document).ready(function() { 13 | // do keyword highlighting 14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ 15 | var mark = function() { 16 | 17 | var referrer = document.URL ; 18 | var paramKey = "q" ; 19 | 20 | if (referrer.indexOf("?") !== -1) { 21 | var qs = referrer.substr(referrer.indexOf('?') + 1); 22 | var qs_noanchor = qs.split('#')[0]; 23 | var qsa = qs_noanchor.split('&'); 24 | var keyword = ""; 25 | 26 | for (var i = 0; i < qsa.length; i++) { 27 | var currentParam = qsa[i].split('='); 28 | 29 | if (currentParam.length !== 2) { 30 | continue; 31 | } 32 | 33 | if (currentParam[0] == paramKey) { 34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); 35 | } 36 | } 37 | 38 | if (keyword !== "") { 39 | $(".contents").unmark({ 40 | done: function() { 41 | $(".contents").mark(keyword); 42 | } 43 | }); 44 | } 45 | } 46 | }; 47 | 48 | mark(); 49 | }); 50 | }); 51 | 52 | /* Search term highlighting ------------------------------*/ 53 | 54 | function matchedWords(hit) { 55 | var words = []; 56 | 57 | var hierarchy = hit._highlightResult.hierarchy; 58 | // loop to fetch from lvl0, lvl1, etc. 59 | for (var idx in hierarchy) { 60 | words = words.concat(hierarchy[idx].matchedWords); 61 | } 62 | 63 | var content = hit._highlightResult.content; 64 | if (content) { 65 | words = words.concat(content.matchedWords); 66 | } 67 | 68 | // return unique words 69 | var words_uniq = [...new Set(words)]; 70 | return words_uniq; 71 | } 72 | 73 | function updateHitURL(hit) { 74 | 75 | var words = matchedWords(hit); 76 | var url = ""; 77 | 78 | if (hit.anchor) { 79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; 80 | } else { 81 | url = hit.url + '?q=' + escape(words.join(" ")); 82 | } 83 | 84 | return url; 85 | } 86 | -------------------------------------------------------------------------------- /docs/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /docs/news/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Changelog • gammit 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
    64 |
    65 | 107 | 108 | 109 | 110 |
    111 | 112 |
    113 |
    114 | 118 | 119 |
    120 |

    121 | gammit 0.3.1

    122 |
      123 |
    • Refactor and extend most functions as done in mixedup
    • 124 |
    125 |
    126 |
    127 |

    128 | gammit 0.3.0

    129 |
      130 |
    • Build package website.
    • 131 |
    132 |
    133 |
    134 |

    135 | gammit 0.2.5

    136 |
      137 |
    • Added a NEWS.md file to track changes to the package.
    • 138 |
    139 |
    140 |
    141 |

    142 | gammit 0.2.1

    143 |
      144 |
    • Imported visibly’s plot_gam functionality
    • 145 |
    146 |
    147 |
    148 |

    149 | gammit 0.2.0

    150 |
      151 |
    • Add predict_gamm
    • 152 |
    153 |
    154 |
    155 |

    156 | gammit 0.1.0

    157 |
      158 |
    • Added basic functionality
    • 159 |
    160 |
    161 |
    162 | 163 | 168 | 169 |
    170 | 171 | 172 |
    173 | 176 | 177 |
    178 |

    Site built with pkgdown 1.6.1.

    179 |
    180 | 181 |
    182 |
    183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | -------------------------------------------------------------------------------- /docs/news/man/figures/mc_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-clark/gammit/b1500bdabc48c76bd8ebfdb0ca4531e88ae50b70/docs/news/man/figures/mc_logo.png -------------------------------------------------------------------------------- /docs/pkgdown.css: -------------------------------------------------------------------------------- 1 | /* Sticky footer */ 2 | 3 | /** 4 | * Basic idea: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/ 5 | * Details: https://github.com/philipwalton/solved-by-flexbox/blob/master/assets/css/components/site.css 6 | * 7 | * .Site -> body > .container 8 | * .Site-content -> body > .container .row 9 | * .footer -> footer 10 | * 11 | * Key idea seems to be to ensure that .container and __all its parents__ 12 | * have height set to 100% 13 | * 14 | */ 15 | 16 | html, body { 17 | height: 100%; 18 | } 19 | 20 | body { 21 | position: relative; 22 | } 23 | 24 | body > .container { 25 | display: flex; 26 | height: 100%; 27 | flex-direction: column; 28 | } 29 | 30 | body > .container .row { 31 | flex: 1 0 auto; 32 | } 33 | 34 | footer { 35 | margin-top: 45px; 36 | padding: 35px 0 36px; 37 | border-top: 1px solid #e5e5e5; 38 | color: #666; 39 | display: flex; 40 | flex-shrink: 0; 41 | } 42 | footer p { 43 | margin-bottom: 0; 44 | } 45 | footer div { 46 | flex: 1; 47 | } 48 | footer .pkgdown { 49 | text-align: right; 50 | } 51 | footer p { 52 | margin-bottom: 0; 53 | } 54 | 55 | img.icon { 56 | float: right; 57 | } 58 | 59 | img { 60 | max-width: 100%; 61 | } 62 | 63 | /* Fix bug in bootstrap (only seen in firefox) */ 64 | summary { 65 | display: list-item; 66 | } 67 | 68 | /* Typographic tweaking ---------------------------------*/ 69 | 70 | .contents .page-header { 71 | margin-top: calc(-60px + 1em); 72 | } 73 | 74 | dd { 75 | margin-left: 3em; 76 | } 77 | 78 | /* Section anchors ---------------------------------*/ 79 | 80 | a.anchor { 81 | margin-left: -30px; 82 | display:inline-block; 83 | width: 30px; 84 | height: 30px; 85 | visibility: hidden; 86 | 87 | background-image: url(./link.svg); 88 | background-repeat: no-repeat; 89 | background-size: 20px 20px; 90 | background-position: center center; 91 | } 92 | 93 | .hasAnchor:hover a.anchor { 94 | visibility: visible; 95 | } 96 | 97 | @media (max-width: 767px) { 98 | .hasAnchor:hover a.anchor { 99 | visibility: hidden; 100 | } 101 | } 102 | 103 | 104 | /* Fixes for fixed navbar --------------------------*/ 105 | 106 | .contents h1, .contents h2, .contents h3, .contents h4 { 107 | padding-top: 60px; 108 | margin-top: -40px; 109 | } 110 | 111 | /* Navbar submenu --------------------------*/ 112 | 113 | .dropdown-submenu { 114 | position: relative; 115 | } 116 | 117 | .dropdown-submenu>.dropdown-menu { 118 | top: 0; 119 | left: 100%; 120 | margin-top: -6px; 121 | margin-left: -1px; 122 | border-radius: 0 6px 6px 6px; 123 | } 124 | 125 | .dropdown-submenu:hover>.dropdown-menu { 126 | display: block; 127 | } 128 | 129 | .dropdown-submenu>a:after { 130 | display: block; 131 | content: " "; 132 | float: right; 133 | width: 0; 134 | height: 0; 135 | border-color: transparent; 136 | border-style: solid; 137 | border-width: 5px 0 5px 5px; 138 | border-left-color: #cccccc; 139 | margin-top: 5px; 140 | margin-right: -10px; 141 | } 142 | 143 | .dropdown-submenu:hover>a:after { 144 | border-left-color: #ffffff; 145 | } 146 | 147 | .dropdown-submenu.pull-left { 148 | float: none; 149 | } 150 | 151 | .dropdown-submenu.pull-left>.dropdown-menu { 152 | left: -100%; 153 | margin-left: 10px; 154 | border-radius: 6px 0 6px 6px; 155 | } 156 | 157 | /* Sidebar --------------------------*/ 158 | 159 | #pkgdown-sidebar { 160 | margin-top: 30px; 161 | position: -webkit-sticky; 162 | position: sticky; 163 | top: 70px; 164 | } 165 | 166 | #pkgdown-sidebar h2 { 167 | font-size: 1.5em; 168 | margin-top: 1em; 169 | } 170 | 171 | #pkgdown-sidebar h2:first-child { 172 | margin-top: 0; 173 | } 174 | 175 | #pkgdown-sidebar .list-unstyled li { 176 | margin-bottom: 0.5em; 177 | } 178 | 179 | /* bootstrap-toc tweaks ------------------------------------------------------*/ 180 | 181 | /* All levels of nav */ 182 | 183 | nav[data-toggle='toc'] .nav > li > a { 184 | padding: 4px 20px 4px 6px; 185 | font-size: 1.5rem; 186 | font-weight: 400; 187 | color: inherit; 188 | } 189 | 190 | nav[data-toggle='toc'] .nav > li > a:hover, 191 | nav[data-toggle='toc'] .nav > li > a:focus { 192 | padding-left: 5px; 193 | color: inherit; 194 | border-left: 1px solid #878787; 195 | } 196 | 197 | nav[data-toggle='toc'] .nav > .active > a, 198 | nav[data-toggle='toc'] .nav > .active:hover > a, 199 | nav[data-toggle='toc'] .nav > .active:focus > a { 200 | padding-left: 5px; 201 | font-size: 1.5rem; 202 | font-weight: 400; 203 | color: inherit; 204 | border-left: 2px solid #878787; 205 | } 206 | 207 | /* Nav: second level (shown on .active) */ 208 | 209 | nav[data-toggle='toc'] .nav .nav { 210 | display: none; /* Hide by default, but at >768px, show it */ 211 | padding-bottom: 10px; 212 | } 213 | 214 | nav[data-toggle='toc'] .nav .nav > li > a { 215 | padding-left: 16px; 216 | font-size: 1.35rem; 217 | } 218 | 219 | nav[data-toggle='toc'] .nav .nav > li > a:hover, 220 | nav[data-toggle='toc'] .nav .nav > li > a:focus { 221 | padding-left: 15px; 222 | } 223 | 224 | nav[data-toggle='toc'] .nav .nav > .active > a, 225 | nav[data-toggle='toc'] .nav .nav > .active:hover > a, 226 | nav[data-toggle='toc'] .nav .nav > .active:focus > a { 227 | padding-left: 15px; 228 | font-weight: 500; 229 | font-size: 1.35rem; 230 | } 231 | 232 | /* orcid ------------------------------------------------------------------- */ 233 | 234 | .orcid { 235 | font-size: 16px; 236 | color: #A6CE39; 237 | /* margins are required by official ORCID trademark and display guidelines */ 238 | margin-left:4px; 239 | margin-right:4px; 240 | vertical-align: middle; 241 | } 242 | 243 | /* Reference index & topics ----------------------------------------------- */ 244 | 245 | .ref-index th {font-weight: normal;} 246 | 247 | .ref-index td {vertical-align: top; min-width: 100px} 248 | .ref-index .icon {width: 40px;} 249 | .ref-index .alias {width: 40%;} 250 | .ref-index-icons .alias {width: calc(40% - 40px);} 251 | .ref-index .title {width: 60%;} 252 | 253 | .ref-arguments th {text-align: right; padding-right: 10px;} 254 | .ref-arguments th, .ref-arguments td {vertical-align: top; min-width: 100px} 255 | .ref-arguments .name {width: 20%;} 256 | .ref-arguments .desc {width: 80%;} 257 | 258 | /* Nice scrolling for wide elements --------------------------------------- */ 259 | 260 | table { 261 | display: block; 262 | overflow: auto; 263 | } 264 | 265 | /* Syntax highlighting ---------------------------------------------------- */ 266 | 267 | pre { 268 | word-wrap: normal; 269 | word-break: normal; 270 | border: 1px solid #eee; 271 | } 272 | 273 | pre, code { 274 | background-color: #f8f8f8; 275 | color: #333; 276 | } 277 | 278 | pre code { 279 | overflow: auto; 280 | word-wrap: normal; 281 | white-space: pre; 282 | } 283 | 284 | pre .img { 285 | margin: 5px 0; 286 | } 287 | 288 | pre .img img { 289 | background-color: #fff; 290 | display: block; 291 | height: auto; 292 | } 293 | 294 | code a, pre a { 295 | color: #375f84; 296 | } 297 | 298 | a.sourceLine:hover { 299 | text-decoration: none; 300 | } 301 | 302 | .fl {color: #1514b5;} 303 | .fu {color: #000000;} /* function */ 304 | .ch,.st {color: #036a07;} /* string */ 305 | .kw {color: #264D66;} /* keyword */ 306 | .co {color: #888888;} /* comment */ 307 | 308 | .message { color: black; font-weight: bolder;} 309 | .error { color: orange; font-weight: bolder;} 310 | .warning { color: #6A0366; font-weight: bolder;} 311 | 312 | /* Clipboard --------------------------*/ 313 | 314 | .hasCopyButton { 315 | position: relative; 316 | } 317 | 318 | .btn-copy-ex { 319 | position: absolute; 320 | right: 0; 321 | top: 0; 322 | visibility: hidden; 323 | } 324 | 325 | .hasCopyButton:hover button.btn-copy-ex { 326 | visibility: visible; 327 | } 328 | 329 | /* headroom.js ------------------------ */ 330 | 331 | .headroom { 332 | will-change: transform; 333 | transition: transform 200ms linear; 334 | } 335 | .headroom--pinned { 336 | transform: translateY(0%); 337 | } 338 | .headroom--unpinned { 339 | transform: translateY(-100%); 340 | } 341 | 342 | /* mark.js ----------------------------*/ 343 | 344 | mark { 345 | background-color: rgba(255, 255, 51, 0.5); 346 | border-bottom: 2px solid rgba(255, 153, 51, 0.3); 347 | padding: 1px; 348 | } 349 | 350 | /* vertical spacing after htmlwidgets */ 351 | .html-widget { 352 | margin-bottom: 10px; 353 | } 354 | 355 | /* fontawesome ------------------------ */ 356 | 357 | .fab { 358 | font-family: "Font Awesome 5 Brands" !important; 359 | } 360 | 361 | /* don't display links in code chunks when printing */ 362 | /* source: https://stackoverflow.com/a/10781533 */ 363 | @media print { 364 | code a:link:after, code a:visited:after { 365 | content: ""; 366 | } 367 | } 368 | -------------------------------------------------------------------------------- /docs/pkgdown.js: -------------------------------------------------------------------------------- 1 | /* http://gregfranko.com/blog/jquery-best-practices/ */ 2 | (function($) { 3 | $(function() { 4 | 5 | $('.navbar-fixed-top').headroom(); 6 | 7 | $('body').css('padding-top', $('.navbar').height() + 10); 8 | $(window).resize(function(){ 9 | $('body').css('padding-top', $('.navbar').height() + 10); 10 | }); 11 | 12 | $('[data-toggle="tooltip"]').tooltip(); 13 | 14 | var cur_path = paths(location.pathname); 15 | var links = $("#navbar ul li a"); 16 | var max_length = -1; 17 | var pos = -1; 18 | for (var i = 0; i < links.length; i++) { 19 | if (links[i].getAttribute("href") === "#") 20 | continue; 21 | // Ignore external links 22 | if (links[i].host !== location.host) 23 | continue; 24 | 25 | var nav_path = paths(links[i].pathname); 26 | 27 | var length = prefix_length(nav_path, cur_path); 28 | if (length > max_length) { 29 | max_length = length; 30 | pos = i; 31 | } 32 | } 33 | 34 | // Add class to parent
  • , and enclosing
  • if in dropdown 35 | if (pos >= 0) { 36 | var menu_anchor = $(links[pos]); 37 | menu_anchor.parent().addClass("active"); 38 | menu_anchor.closest("li.dropdown").addClass("active"); 39 | } 40 | }); 41 | 42 | function paths(pathname) { 43 | var pieces = pathname.split("/"); 44 | pieces.shift(); // always starts with / 45 | 46 | var end = pieces[pieces.length - 1]; 47 | if (end === "index.html" || end === "") 48 | pieces.pop(); 49 | return(pieces); 50 | } 51 | 52 | // Returns -1 if not found 53 | function prefix_length(needle, haystack) { 54 | if (needle.length > haystack.length) 55 | return(-1); 56 | 57 | // Special case for length-0 haystack, since for loop won't run 58 | if (haystack.length === 0) { 59 | return(needle.length === 0 ? 0 : -1); 60 | } 61 | 62 | for (var i = 0; i < haystack.length; i++) { 63 | if (needle[i] != haystack[i]) 64 | return(i); 65 | } 66 | 67 | return(haystack.length); 68 | } 69 | 70 | /* Clipboard --------------------------*/ 71 | 72 | function changeTooltipMessage(element, msg) { 73 | var tooltipOriginalTitle=element.getAttribute('data-original-title'); 74 | element.setAttribute('data-original-title', msg); 75 | $(element).tooltip('show'); 76 | element.setAttribute('data-original-title', tooltipOriginalTitle); 77 | } 78 | 79 | if(ClipboardJS.isSupported()) { 80 | $(document).ready(function() { 81 | var copyButton = ""; 82 | 83 | $(".examples, div.sourceCode").addClass("hasCopyButton"); 84 | 85 | // Insert copy buttons: 86 | $(copyButton).prependTo(".hasCopyButton"); 87 | 88 | // Initialize tooltips: 89 | $('.btn-copy-ex').tooltip({container: 'body'}); 90 | 91 | // Initialize clipboard: 92 | var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', { 93 | text: function(trigger) { 94 | return trigger.parentNode.textContent; 95 | } 96 | }); 97 | 98 | clipboardBtnCopies.on('success', function(e) { 99 | changeTooltipMessage(e.trigger, 'Copied!'); 100 | e.clearSelection(); 101 | }); 102 | 103 | clipboardBtnCopies.on('error', function() { 104 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); 105 | }); 106 | }); 107 | } 108 | })(window.jQuery || window.$) 109 | -------------------------------------------------------------------------------- /docs/pkgdown.yml: -------------------------------------------------------------------------------- 1 | pandoc: 2.9.2.1 2 | pkgdown: 1.6.1 3 | pkgdown_sha: ~ 4 | articles: {} 5 | last_built: 2020-10-20T19:43Z 6 | 7 | -------------------------------------------------------------------------------- /docs/reference/Rplot001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-clark/gammit/b1500bdabc48c76bd8ebfdb0ca4531e88ae50b70/docs/reference/Rplot001.png -------------------------------------------------------------------------------- /docs/reference/extract_fixed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Extract the fixed effects from a GAMM — extract_fixed • gammit 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 59 | 60 | 61 | 62 | 63 | 64 | 65 |
    66 |
    67 | 109 | 110 | 111 | 112 |
    113 | 114 |
    115 |
    116 | 121 | 122 |
    123 |

    When using a GAM for mixed models, we may have specific interest in the fixed 124 | effect parameters.

    125 |
    126 | 127 |
    extract_fixed(model, ci_level = 0.95, digits = 3, ...)
    128 | 129 |

    Arguments

    130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 |
    model

    A gam or bam model

    ci_level

    Level for the confidence interval. Must be between 0 and 1.

    digits

    Rounding for the output.

    ...

    Passed to summary.gam, e.g. to set re.test = FALSE.

    149 | 150 |

    Value

    151 | 152 |

    A data.frame with the coefficients, standard error, and upper 153 | and lower bounds.

    154 |

    Details

    155 | 156 |

    This essentially reproduces the 'parametric' output from 157 | summary.gam.

    158 |

    See also

    159 | 160 | 161 | 162 |

    Examples

    163 |
    164 | library(mgcv) 165 |
    #> Loading required package: nlme
    #> This is mgcv 1.8-33. For overview type 'help("mgcv-package")'.
    library(lme4) 166 |
    #> Loading required package: Matrix
    #> 167 | #> Attaching package: ‘lme4’
    #> The following object is masked from ‘package:nlme’: 168 | #> 169 | #> lmList
    170 | lmer_model <- lmer(Reaction ~ Days + (Days || Subject), data = sleepstudy) 171 | ga_model <- gam(Reaction ~ Days + s(Subject, bs = "re") + s(Days, Subject, bs = "re"), 172 | data = sleepstudy, 173 | method = "REML" 174 | ) 175 | 176 | fixef(lmer_model) 177 |
    #> (Intercept) Days 178 | #> 251.40510 10.46729
    extract_fixed(ga_model) 179 |
    #> # A tibble: 2 x 7 180 | #> term value se t p lower_2.5 upper_97.5 181 | #> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 182 | #> 1 Intercept 251. 6.88 36.5 0 238. 265. 183 | #> 2 Days 10.5 1.56 6.71 0 7.39 13.5
    184 |
    185 |
    186 | 191 |
    192 | 193 | 194 |
    195 | 198 | 199 |
    200 |

    Site built with pkgdown 1.6.1.

    201 |
    202 | 203 |
    204 |
    205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | -------------------------------------------------------------------------------- /docs/reference/extract_vc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Extract variance components — extract_vc • gammit 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 60 | 61 | 62 | 63 | 64 | 65 | 66 |
    67 |
    68 | 110 | 111 | 112 | 113 |
    114 | 115 |
    116 |
    117 | 122 | 123 |
    124 |

    This function extracts the variance components from a gam or bam 125 | object, where one is using the associated functions from the mgcv package 126 | for mixed models.

    127 |
    128 | 129 |
    extract_vc(model, ci_level = 0.95, ci_scale = "sd", digits = 3)
    130 | 131 |

    Arguments

    132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 |
    model

    A gam or bam model

    ci_level

    Level for the confidence interval. Must be between 0 and 1.

    ci_scale

    Whether the confidence interval should be on the variance or standard deviation scale.

    digits

    Rounding for the output.

    151 | 152 |

    Value

    153 | 154 |

    A tibble or data frame with the standard deviation, its lower and 155 | upper bounds, the variance, and the relative proportion of total variance 156 | for each variance component.

    157 |

    Details

    158 | 159 |

    This is essentially a pretty way to print gam.vcomp. 160 | Note that if you do something like a random slope, the gam approach does 161 | not estimate the intercept-slope correlation, so none will be printed. 162 | Should work fine on standard smooth terms also, but the model must be 163 | estimated with method = REML or method = ML. This is the default for 164 | non-exponential families, but otherwise you'll have to change the value or 165 | will receive an error. Have not tested much with interactions, using by, 166 | etc., but it has worked on some default mgcv examples.

    167 | 168 |

    Examples

    169 |
    library(mgcv) 170 | library(lme4) 171 | 172 | lmer_model <- lmer(Reaction ~ Days + (Days || Subject), data = sleepstudy) 173 | ga_model <- gam(Reaction ~ Days + s(Subject, bs = "re") + s(Days, Subject, bs = "re"), 174 | data = sleepstudy, 175 | method = "REML" 176 | ) 177 | 178 | VarCorr(lmer_model) 179 |
    #> Groups Name Std.Dev. 180 | #> Subject (Intercept) 25.0513 181 | #> Subject.1 Days 5.9882 182 | #> Residual 25.5653
    extract_vc(ga_model) 183 |
    #> group effect variance sd sd_2.5 sd_97.5 var_prop 184 | #> 1 Subject Intercept 627.571 25.051 16.085 39.015 0.477 185 | #> 2 Subject Days 35.858 5.988 4.025 8.908 0.027 186 | #> 3 Residual 653.582 25.565 22.792 28.676 0.496
    187 |
    188 |
    189 | 194 |
    195 | 196 | 197 |
    198 | 201 | 202 |
    203 |

    Site built with pkgdown 1.6.1.

    204 |
    205 | 206 |
    207 |
    208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /docs/reference/figures/mc_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-clark/gammit/b1500bdabc48c76bd8ebfdb0ca4531e88ae50b70/docs/reference/figures/mc_logo.png -------------------------------------------------------------------------------- /docs/reference/gammit-package.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | gammit: Using Generalized Additive Mixed Models — gammit-package • gammit 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
    65 |
    66 | 108 | 109 | 110 | 111 |
    112 | 113 |
    114 |
    115 | 120 | 121 |
    122 |

    The goal of gammit is to provide a set of functions to aid using mgcv (possibly solely) for mixed models.

    123 |
    124 | 125 | 126 | 127 |

    See also

    128 | 129 |

    Useful links:

    133 | 134 |
    135 |

    Author

    136 | 137 |

    Maintainer: Michael Clark micl@umich.edu

    138 | 139 |
    140 | 145 |
    146 | 147 | 148 |
    149 | 152 | 153 |
    154 |

    Site built with pkgdown 1.6.1.

    155 |
    156 | 157 |
    158 |
    159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /docs/reference/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Function reference • gammit 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
    64 |
    65 | 107 | 108 | 109 | 110 |
    111 | 112 |
    113 |
    114 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 143 | 144 | 145 | 146 | 149 | 150 | 151 | 152 | 155 | 156 | 157 | 158 | 159 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 174 | 175 | 176 | 177 | 180 | 181 | 182 | 183 | 184 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 199 | 200 | 201 | 202 |
    129 |

    Extraction

    130 |

    Get variance components, random effects, etc.

    131 |
    141 |

    extract_fixed()

    142 |

    Extract the fixed effects from a GAMM

    147 |

    extract_vc()

    148 |

    Extract variance components

    153 |

    extract_ranef()

    154 |

    Extract random effects from a gam

    160 |

    Summarize and predict

    161 |

    lme4-style summary and prediction tools.

    162 |
    172 |

    summary_gamm()

    173 |

    Summarize a GAMM

    178 |

    predict_gamm()

    179 |

    Make predictions with or without random effects

    185 |

    Visualization

    186 |

    Visualization functions from visibly.

    187 |
    197 |

    reexports

    198 |

    Objects exported from other packages

    203 |
    204 | 205 | 210 |
    211 | 212 | 213 |
    214 | 217 | 218 |
    219 |

    Site built with pkgdown 1.6.1.

    220 |
    221 | 222 |
    223 |
    224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | -------------------------------------------------------------------------------- /docs/reference/man/figures/mc_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-clark/gammit/b1500bdabc48c76bd8ebfdb0ca4531e88ae50b70/docs/reference/man/figures/mc_logo.png -------------------------------------------------------------------------------- /docs/reference/predict_gamm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Make predictions with or without random effects — predict_gamm • gammit 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
    65 |
    66 | 108 | 109 | 110 | 111 |
    112 | 113 |
    114 |
    115 | 120 | 121 |
    122 |

    Use predict in an lme4 style on gam/bam objects from mgcv.

    123 |
    124 | 125 |
    predict_gamm(
    126 |   model,
    127 |   newdata,
    128 |   re_form = NULL,
    129 |   se = FALSE,
    130 |   include = NULL,
    131 |   exclude = NULL,
    132 |   keep_prediction_data = FALSE,
    133 |   ...
    134 | )
    135 | 136 |

    Arguments

    137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 163 | 164 | 165 | 166 | 168 | 169 | 170 | 171 | 173 | 174 | 175 | 176 | 177 | 178 |
    model

    A gam class model from the mgcv package.

    newdata

    Data on which to predict on. Empty by default.

    re_form

    NULL, NA, or character string. If NULL (default), all 150 | random effects will be used. If NA, no random effects will be used. If 151 | character, must be of the form "s(varname)", where varname would be the 152 | name of the grouping variable pertaining to the random effect. Appended to 153 | include.

    se

    Logical. Include standard errors or not. Default is FALSE.

    include

    Which random effects to include in prediction. See 162 | predict.gam for details.

    exclude

    Which random effects to exclude in prediction. See 167 | predict.gam for details.

    keep_prediction_data

    Keep the model frame or newdata that was used in 172 | the prediction in final output? Default is FALSE.

    ...

    Other arguments for predict.gam.

    179 | 180 |

    Value

    181 | 182 |

    A data frame of predictions and possibly standard errors.

    183 |

    Details

    184 | 185 |

    This is a wrapper for predict.gam. The goal is to 186 | have similar functionality with predict function in lme4, which makes it 187 | easy to drop all random effects or include specific ones. Some of this 188 | functionality is not yet available for class bam.

    189 |

    See also

    190 | 191 | 192 | 193 |

    Examples

    194 |
    library(lme4) 195 | library(mgcv) 196 | lmer_model <- lmer(Reaction ~ Days + (Days || Subject), data = sleepstudy) 197 | ga_model <- gam(Reaction ~ Days + s(Subject, bs = "re") + s(Days, Subject, bs = "re"), 198 | data = sleepstudy, 199 | method = "REML" 200 | ) 201 | 202 | head( 203 | data.frame( 204 | lmer = predict(lmer_model), 205 | gam = predict_gamm(ga_model) 206 | ) 207 | ) 208 |
    #> lmer prediction 209 | #> 1 252.9178 252.9178 210 | #> 2 272.7086 272.7086 211 | #> 3 292.4993 292.4994 212 | #> 4 312.2901 312.2901 213 | #> 5 332.0809 332.0809 214 | #> 6 351.8717 351.8717
    215 | head( 216 | cbind( 217 | lmer = predict(lmer_model, re.form = NA), 218 | gam1 = predict_gamm(ga_model, re_form = NA), 219 | gam2 = predict_gamm(ga_model, 220 | exclude = c("s(Subject)", "s(Days,Subject)") 221 | ) 222 | ) 223 | ) 224 |
    #> lmer prediction prediction 225 | #> 1 251.4051 251.4051 251.4051 226 | #> 2 261.8724 261.8724 261.8724 227 | #> 3 272.3397 272.3397 272.3397 228 | #> 4 282.8070 282.8070 282.8070 229 | #> 5 293.2742 293.2742 293.2742 230 | #> 6 303.7415 303.7415 303.7415
    231 | head(predict_gamm(ga_model, se = TRUE)) 232 |
    #> prediction se 233 | #> 1 252.9178 12.410220 234 | #> 2 272.7086 10.660891 235 | #> 3 292.4994 9.191224 236 | #> 4 312.2901 8.153871 237 | #> 5 332.0809 7.724998 238 | #> 6 351.8717 8.003034
    239 |
    240 | 245 |
    246 | 247 | 248 |
    249 | 252 | 253 |
    254 |

    Site built with pkgdown 1.6.1.

    255 |
    256 | 257 |
    258 |
    259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | -------------------------------------------------------------------------------- /docs/reference/reexports.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Objects exported from other packages — reexports • gammit 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
    70 |
    71 | 113 | 114 | 115 | 116 |
    117 | 118 |
    119 |
    120 | 125 | 126 |
    127 |

    These objects are imported from other packages. Follow the links 128 | below to see their documentation.

    129 |
    130 |
    visibly

    plot_gam, plot_gam_2d, plot_gam_3d, plot_gam_by, plot_gam_check

    131 | 132 |
    133 |
    134 | 135 | 136 | 137 | 138 |
    139 | 144 |
    145 | 146 | 147 |
    148 | 151 | 152 |
    153 |

    Site built with pkgdown 1.6.1.

    154 |
    155 | 156 |
    157 |
    158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /docs/reference/summary_gamm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Summarize a GAMM — summary_gamm • gammit 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
    65 |
    66 | 108 | 109 | 110 | 111 |
    112 | 113 |
    114 |
    115 | 120 | 121 |
    122 |

    Summarize a gam model in a clean mixed effects style.

    123 |
    124 | 125 |
    summary_gamm(model, digits = 3)
    126 | 127 |

    Arguments

    128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 |
    model

    The mgcv model

    digits

    number of digits to display

    139 | 140 |

    Value

    141 | 142 |

    Invisibly returns a list with the variance components via 143 | extract_vc and fixed effects parameter, labeled vc and fe 144 | respectively.

    145 |

    Details

    146 | 147 |

    This displays the variance components and fixed effects from a gam 148 | model. Assumes an mgcv model of the form gam(... + s(g, bs='re')), 149 | but should work with just about any gam with a smooth term.

    150 |

    See also

    151 | 152 | 153 | 154 |

    Examples

    155 |
    library(mgcv) 156 | library(lme4) 157 | 158 | lmer_model <- lmer(Reaction ~ Days + (Days || Subject), data = sleepstudy) 159 | ga_model <- gam(Reaction ~ Days + s(Subject, bs = "re") + s(Days, Subject, bs = "re"), 160 | data = sleepstudy, 161 | method = "REML" 162 | ) 163 | 164 | summary(lmer_model) 165 |
    #> Linear mixed model fit by REML ['lmerMod'] 166 | #> Formula: Reaction ~ Days + ((1 | Subject) + (0 + Days | Subject)) 167 | #> Data: sleepstudy 168 | #> 169 | #> REML criterion at convergence: 1743.7 170 | #> 171 | #> Scaled residuals: 172 | #> Min 1Q Median 3Q Max 173 | #> -3.9626 -0.4625 0.0204 0.4653 5.1860 174 | #> 175 | #> Random effects: 176 | #> Groups Name Variance Std.Dev. 177 | #> Subject (Intercept) 627.57 25.051 178 | #> Subject.1 Days 35.86 5.988 179 | #> Residual 653.58 25.565 180 | #> Number of obs: 180, groups: Subject, 18 181 | #> 182 | #> Fixed effects: 183 | #> Estimate Std. Error t value 184 | #> (Intercept) 251.405 6.885 36.513 185 | #> Days 10.467 1.560 6.712 186 | #> 187 | #> Correlation of Fixed Effects: 188 | #> (Intr) 189 | #> Days -0.184
    summary_gamm(ga_model) 190 |
    #> 191 | #> Variance components:
    #> group effect variance sd sd_2.5 sd_97.5 var_prop 192 | #> Subject Intercept 627.571 25.051 16.085 39.015 0.477 193 | #> Subject Days 35.858 5.988 4.025 8.908 0.027 194 | #> Residual 653.582 25.565 22.792 28.676 0.496
    #> 195 | #> 196 | #> Fixed Effects:
    #> Term Estimate Std. Error t value Pr(>|t|) 197 | #> (Intercept) 251.405 6.885 36.513 0.000 198 | #> Days 10.467 1.560 6.712 0.000
    199 |
    200 | 205 |
    206 | 207 | 208 | 218 |
    219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | -------------------------------------------------------------------------------- /gammit.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: knitr 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace,vignette 22 | -------------------------------------------------------------------------------- /man/extract_fixed.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/extract_fixed.R 3 | \name{extract_fixed} 4 | \alias{extract_fixed} 5 | \title{Extract the fixed effects from a GAMM} 6 | \usage{ 7 | extract_fixed(model, ci_level = 0.95, digits = 3, ...) 8 | } 9 | \arguments{ 10 | \item{model}{A gam or bam model} 11 | 12 | \item{ci_level}{Level for the confidence interval. Must be between 0 and 1.} 13 | 14 | \item{digits}{Rounding for the output.} 15 | 16 | \item{...}{Passed to summary.gam, e.g. to set re.test = FALSE.} 17 | } 18 | \value{ 19 | A \code{data.frame} with the coefficients, standard error, and upper 20 | and lower bounds. 21 | } 22 | \description{ 23 | When using a GAM for mixed models, we may have specific interest in the fixed 24 | effect parameters. 25 | } 26 | \details{ 27 | This essentially reproduces the 'parametric' output from 28 | \code{\link[mgcv]{summary.gam}}. 29 | } 30 | \examples{ 31 | 32 | library(mgcv) 33 | library(lme4) 34 | 35 | lmer_model <- lmer(Reaction ~ Days + (Days || Subject), data = sleepstudy) 36 | ga_model <- gam(Reaction ~ Days + s(Subject, bs = "re") + s(Days, Subject, bs = "re"), 37 | data = sleepstudy, 38 | method = "REML" 39 | ) 40 | 41 | fixef(lmer_model) 42 | extract_fixed(ga_model) 43 | 44 | } 45 | \seealso{ 46 | \code{\link[lme4]{fixef}} 47 | } 48 | -------------------------------------------------------------------------------- /man/extract_ranef.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/extract_ranef.R 3 | \name{extract_ranef} 4 | \alias{extract_ranef} 5 | \title{Extract random effects from a gam} 6 | \usage{ 7 | extract_ranef(model, re = NULL, ci_level = 0.95, digits = 3) 8 | } 9 | \arguments{ 10 | \item{model}{A gam or bam model} 11 | 12 | \item{re}{Filter results to a specific random effect/grouping variable.} 13 | 14 | \item{ci_level}{Level for the confidence interval. Must be between 0 and 1.} 15 | 16 | \item{digits}{Rounding for the output.} 17 | } 18 | \value{ 19 | A \code{tibble} or data frame with the random effect, 20 | its standard error, and its lower and upper bounds. The bounds are based 21 | on a simple normal approximation using the standard error. 22 | } 23 | \description{ 24 | Extract what would be the random effects from a mixed model from 25 | a gam object. Assumes an mgcv model of the form \code{gam(... + s(g, bs='re'))}. 26 | } 27 | \details{ 28 | Returns a data frame of the the \code{component} type, the estimated 29 | random effect \code{re}, the estimated \code{se}, and approximate \code{lower} and \code{upper} 30 | bounds. Note that the standard errors are Bayesian 31 | estimates (see \code{\link{gamObject}}, specifically type \code{Vp}). The \code{re} 32 | will only reflect smooth terms whose basis function is 're', i.e. of class 33 | \code{random.effect}. Others will be ignored. 34 | } 35 | \note{ 36 | \code{mgcv} strips the level names for 're' smooth terms, so this attempts 37 | to get them back. This may not work under every circumstance, but the 38 | attempt is made to extract the names of random effect groups based on how 39 | they are ordered in the data (which is how the model matrix would be 40 | constructed), and in the case of random slopes, detect that second variable 41 | in the 're' specification would be the grouping variable. This will not 42 | work for continuous x continuous smooths of type 're', but I can't think of 43 | a reason why you'd use that given your other options with \code{mgcv}. 44 | } 45 | \examples{ 46 | library(mgcv) 47 | library(lme4) 48 | 49 | lmer_model <- lmer(Reaction ~ Days + (Days || Subject), data = sleepstudy) 50 | ga_model <- gam(Reaction ~ Days + s(Subject, bs = "re") + s(Days, Subject, bs = "re"), 51 | data = sleepstudy, 52 | method = "REML" 53 | ) 54 | 55 | ranef(lmer_model) 56 | extract_ranef(ga_model) 57 | } 58 | \seealso{ 59 | \code{\link{ranef}} 60 | } 61 | -------------------------------------------------------------------------------- /man/extract_vc.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/extract_vc.R 3 | \name{extract_vc} 4 | \alias{extract_vc} 5 | \title{Extract variance components} 6 | \usage{ 7 | extract_vc(model, ci_level = 0.95, ci_scale = "sd", digits = 3) 8 | } 9 | \arguments{ 10 | \item{model}{A gam or bam model} 11 | 12 | \item{ci_level}{Level for the confidence interval. Must be between 0 and 1.} 13 | 14 | \item{ci_scale}{Whether the confidence interval should be on the variance or standard deviation scale.} 15 | 16 | \item{digits}{Rounding for the output.} 17 | } 18 | \value{ 19 | A tibble or data frame with the standard deviation, its lower and 20 | upper bounds, the variance, and the relative proportion of total variance 21 | for each variance component. 22 | } 23 | \description{ 24 | This function extracts the variance components from a gam or bam 25 | object, where one is using the associated functions from the mgcv package 26 | for mixed models. 27 | } 28 | \details{ 29 | This is essentially a pretty way to print \code{\link{gam.vcomp}}. 30 | Note that if you do something like a random slope, the gam approach does 31 | not estimate the intercept-slope correlation, so none will be printed. 32 | Should work fine on standard smooth terms also, but the model \emph{must be 33 | estimated with} \code{method = REML} or \code{method = ML}. This is the default for 34 | non-exponential families, but otherwise you'll have to change the value or 35 | will receive an error. Have not tested much with interactions, using \code{by}, 36 | etc., but it has worked on some default \code{\link{mgcv}} examples. 37 | } 38 | \examples{ 39 | library(mgcv) 40 | library(lme4) 41 | 42 | lmer_model <- lmer(Reaction ~ Days + (Days || Subject), data = sleepstudy) 43 | ga_model <- gam(Reaction ~ Days + s(Subject, bs = "re") + s(Days, Subject, bs = "re"), 44 | data = sleepstudy, 45 | method = "REML" 46 | ) 47 | 48 | VarCorr(lmer_model) 49 | extract_vc(ga_model) 50 | 51 | } 52 | -------------------------------------------------------------------------------- /man/figures/mc_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-clark/gammit/b1500bdabc48c76bd8ebfdb0ca4531e88ae50b70/man/figures/mc_logo.png -------------------------------------------------------------------------------- /man/gammit-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/gammit-package.R 3 | \docType{package} 4 | \name{gammit-package} 5 | \alias{gammit} 6 | \alias{gammit-package} 7 | \title{gammit: Using Generalized Additive Mixed Models} 8 | \description{ 9 | The goal of gammit is to provide a set of functions to aid using mgcv (possibly solely) for mixed models. 10 | } 11 | \seealso{ 12 | Useful links: 13 | \itemize{ 14 | \item \url{https://github.com/m-clark/gammit} 15 | \item Report bugs at \url{https://github.com/m-clark/gammit/issues} 16 | } 17 | 18 | } 19 | \author{ 20 | \strong{Maintainer}: Michael Clark \email{micl@umich.edu} 21 | 22 | } 23 | \keyword{internal} 24 | -------------------------------------------------------------------------------- /man/predict_gamm.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/predict_gamm.R 3 | \name{predict_gamm} 4 | \alias{predict_gamm} 5 | \title{Make predictions with or without random effects} 6 | \usage{ 7 | predict_gamm( 8 | model, 9 | newdata, 10 | re_form = NULL, 11 | se = FALSE, 12 | include = NULL, 13 | exclude = NULL, 14 | keep_prediction_data = FALSE, 15 | ... 16 | ) 17 | } 18 | \arguments{ 19 | \item{model}{A gam class model from the \code{\link{mgcv}} package.} 20 | 21 | \item{newdata}{Data on which to predict on. Empty by default.} 22 | 23 | \item{re_form}{\code{NULL}, \code{NA}, or character string. If \code{NULL} (default), all 24 | random effects will be used. If NA, no random effects will be used. If 25 | character, must be of the form \code{"s(varname)"}, where \code{varname} would be the 26 | name of the grouping variable pertaining to the random effect. Appended to 27 | \code{include}.} 28 | 29 | \item{se}{Logical. Include standard errors or not. Default is FALSE.} 30 | 31 | \item{include}{Which random effects to include in prediction. See 32 | \code{\link{predict.gam}} for details.} 33 | 34 | \item{exclude}{Which random effects to exclude in prediction. See 35 | \code{\link{predict.gam}} for details.} 36 | 37 | \item{keep_prediction_data}{Keep the model frame or newdata that was used in 38 | the prediction in final output? Default is FALSE.} 39 | 40 | \item{...}{Other arguments for \code{\link{predict.gam}}.} 41 | } 42 | \value{ 43 | A data frame of predictions and possibly standard errors. 44 | } 45 | \description{ 46 | Use predict in an \code{lme4} style on gam/bam objects from \code{\link{mgcv}}. 47 | } 48 | \details{ 49 | This is a wrapper for \code{\link{predict.gam}}. The goal is to 50 | have similar functionality with predict function in \code{lme4}, which makes it 51 | easy to drop all random effects or include specific ones. Some of this 52 | functionality is not yet available for class \code{bam}. 53 | } 54 | \examples{ 55 | library(lme4) 56 | library(mgcv) 57 | lmer_model <- lmer(Reaction ~ Days + (Days || Subject), data = sleepstudy) 58 | ga_model <- gam(Reaction ~ Days + s(Subject, bs = "re") + s(Days, Subject, bs = "re"), 59 | data = sleepstudy, 60 | method = "REML" 61 | ) 62 | 63 | head( 64 | data.frame( 65 | lmer = predict(lmer_model), 66 | gam = predict_gamm(ga_model) 67 | ) 68 | ) 69 | 70 | head( 71 | cbind( 72 | lmer = predict(lmer_model, re.form = NA), 73 | gam1 = predict_gamm(ga_model, re_form = NA), 74 | gam2 = predict_gamm(ga_model, 75 | exclude = c("s(Subject)", "s(Days,Subject)") 76 | ) 77 | ) 78 | ) 79 | 80 | head(predict_gamm(ga_model, se = TRUE)) 81 | } 82 | \seealso{ 83 | \code{\link{predict.gam}} 84 | } 85 | -------------------------------------------------------------------------------- /man/reexports.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \docType{import} 4 | \name{reexports} 5 | \alias{reexports} 6 | \alias{plot_gam} 7 | \alias{plot_gam_2d} 8 | \alias{plot_gam_3d} 9 | \alias{plot_gam_by} 10 | \alias{plot_gam_check} 11 | \title{Objects exported from other packages} 12 | \keyword{internal} 13 | \description{ 14 | These objects are imported from other packages. Follow the links 15 | below to see their documentation. 16 | 17 | \describe{ 18 | \item{visibly}{\code{\link[visibly]{plot_gam}}, \code{\link[visibly]{plot_gam_2d}}, \code{\link[visibly]{plot_gam_3d}}, \code{\link[visibly:plot_gam_2d]{plot_gam_by}}, \code{\link[visibly]{plot_gam_check}}} 19 | }} 20 | 21 | -------------------------------------------------------------------------------- /man/summary_gamm.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/summary_gamm.R 3 | \name{summary_gamm} 4 | \alias{summary_gamm} 5 | \title{Summarize a GAMM} 6 | \usage{ 7 | summary_gamm(model, digits = 3) 8 | } 9 | \arguments{ 10 | \item{model}{The mgcv model} 11 | 12 | \item{digits}{number of digits to display} 13 | } 14 | \value{ 15 | Invisibly returns a list with the variance components via 16 | \code{extract_vc} and fixed effects parameter, labeled \code{vc} and \code{fe} 17 | respectively. 18 | } 19 | \description{ 20 | Summarize a gam model in a clean mixed effects style. 21 | } 22 | \details{ 23 | This displays the variance components and fixed effects from a gam 24 | model. Assumes an mgcv model of the form \code{gam(... + s(g, bs='re'))}, 25 | but should work with just about any gam with a smooth term. 26 | } 27 | \examples{ 28 | library(mgcv) 29 | library(lme4) 30 | 31 | lmer_model <- lmer(Reaction ~ Days + (Days || Subject), data = sleepstudy) 32 | ga_model <- gam(Reaction ~ Days + s(Subject, bs = "re") + s(Days, Subject, bs = "re"), 33 | data = sleepstudy, 34 | method = "REML" 35 | ) 36 | 37 | summary(lmer_model) 38 | summary_gamm(ga_model) 39 | } 40 | \seealso{ 41 | \code{\link{extract_vc}} 42 | } 43 | -------------------------------------------------------------------------------- /pkgdown/pygment_highlights.css: -------------------------------------------------------------------------------- 1 | .highlight { background: #ffffff; } 2 | .highlight pre { background-color: #fff; font-size: 16px } 3 | .highlight .c { color: #999988; font-style: italic } /* Comment */ 4 | .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ 5 | .highlight .k { font-weight: bold } /* Keyword */ 6 | .highlight .o { font-weight: bold } /* Operator */ 7 | .highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ 8 | .highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ 9 | .highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ 10 | .highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ 11 | .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ 12 | .highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ 13 | .highlight .ge { font-style: italic } /* Generic.Emph */ 14 | .highlight .gr { color: #aa0000 } /* Generic.Error */ 15 | .highlight .gh { color: #999999 } /* Generic.Heading */ 16 | .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ 17 | .highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ 18 | .highlight .go { color: #888888 } /* Generic.Output */ 19 | .highlight .gp { color: #555555 } /* Generic.Prompt */ 20 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 21 | .highlight .gu { color: #aaaaaa } /* Generic.Subheading */ 22 | .highlight .gt { color: #aa0000 } /* Generic.Traceback */ 23 | .highlight .kc { font-weight: bold } /* Keyword.Constant */ 24 | .highlight .kd { font-weight: bold } /* Keyword.Declaration */ 25 | .highlight .kp { font-weight: bold } /* Keyword.Pseudo */ 26 | .highlight .kr { font-weight: bold } /* Keyword.Reserved */ 27 | .highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ 28 | .highlight .m { color: #009999 } /* Literal.Number */ 29 | .highlight .s { color: #d14 } /* Literal.String */ 30 | .highlight .na { color: #008080 } /* Name.Attribute */ 31 | .highlight .nb { color: #0086B3 } /* Name.Builtin */ 32 | .highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ 33 | .highlight .no { color: #008080 } /* Name.Constant */ 34 | .highlight .ni { color: #800080 } /* Name.Entity */ 35 | .highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ 36 | .highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ 37 | .highlight .nn { color: #555555 } /* Name.Namespace */ 38 | .highlight .nt { color: #000080 } /* Name.Tag */ 39 | .highlight .nv { color: #008080 } /* Name.Variable */ 40 | .highlight .ow { font-weight: bold } /* Operator.Word */ 41 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 42 | .highlight .mf { color: #009999 } /* Literal.Number.Float */ 43 | .highlight .mh { color: #009999 } /* Literal.Number.Hex */ 44 | .highlight .mi { color: #009999 } /* Literal.Number.Integer */ 45 | .highlight .mo { color: #009999 } /* Literal.Number.Oct */ 46 | .highlight .sb { color: #d14 } /* Literal.String.Backtick */ 47 | .highlight .sc { color: #d14 } /* Literal.String.Char */ 48 | .highlight .sd { color: #d14 } /* Literal.String.Doc */ 49 | .highlight .s2 { color: #d14 } /* Literal.String.Double */ 50 | .highlight .se { color: #d14 } /* Literal.String.Escape */ 51 | .highlight .sh { color: #d14 } /* Literal.String.Heredoc */ 52 | .highlight .si { color: #d14 } /* Literal.String.Interpol */ 53 | .highlight .sx { color: #d14 } /* Literal.String.Other */ 54 | .highlight .sr { color: #009926 } /* Literal.String.Regex */ 55 | .highlight .s1 { color: #d14 } /* Literal.String.Single */ 56 | .highlight .ss { color: #990073 } /* Literal.String.Symbol */ 57 | .highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ 58 | .highlight .vc { color: #008080 } /* Name.Variable.Class */ 59 | .highlight .vg { color: #008080 } /* Name.Variable.Global */ 60 | .highlight .vi { color: #008080 } /* Name.Variable.Instance */ 61 | .highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ 62 | 63 | /* Make line numbers unselectable: excludes line numbers from copy-paste user ops */ 64 | .highlight .lineno {color:rgba(0,0,0,0.3);padding: 0 10px;-webkit-user-select: none;-moz-user-select: none; -o-user-select: none;} 65 | .lineno::-moz-selection {background-color: transparent;} /* Mozilla specific */ 66 | .lineno::selection {background-color: transparent;} /* Other major browsers */ 67 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(gammit) 3 | 4 | test_check("gammit") 5 | -------------------------------------------------------------------------------- /tests/testthat/helper-load_data.R: -------------------------------------------------------------------------------- 1 | # Run mgcv models --------------------------------------------------------- 2 | 3 | load('mgcv_results.RData') 4 | 5 | # library(mgcv) 6 | # 7 | # gam_1 = gam(Reaction ~ Days + s(Subject, bs = 're'), 8 | # data = lme4::sleepstudy, 9 | # method = 'REML') 10 | # 11 | # gam_2 = gam( 12 | # Reaction ~ Days + 13 | # s(Subject, bs = 're') + 14 | # s(Days, Subject, bs = 're'), 15 | # data = lme4::sleepstudy, 16 | # method = 'REML' 17 | # ) 18 | # 19 | # gam_3 <- gam( 20 | # y ~ service + 21 | # s(s, bs = 're') + 22 | # s(dept, bs = 're'), 23 | # method = 'REML', 24 | # data = lme4::InstEval[1:1000, ] 25 | # ) 26 | # 27 | # # bam objects are very large to save even for small models 28 | # bam_1 = bam( 29 | # y ~ service + 30 | # s(d, bs = 're') + 31 | # s(dept, bs = 're'), 32 | # data = lme4::InstEval[1:1000, ], 33 | # nthreads = 10 34 | # ) 35 | # 36 | # ## TODO: glm 37 | # 38 | # save( 39 | # gam_1, 40 | # gam_2, 41 | # gam_3, 42 | # bam_1, 43 | # file = 'tests/testthat/mgcv_results.RData' 44 | # ) 45 | -------------------------------------------------------------------------------- /tests/testthat/mgcv_results.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-clark/gammit/b1500bdabc48c76bd8ebfdb0ca4531e88ae50b70/tests/testthat/mgcv_results.RData -------------------------------------------------------------------------------- /tests/testthat/test_extract_fixed.R: -------------------------------------------------------------------------------- 1 | context('test extract fixed effects') 2 | 3 | ga_model = mgcv::gam(Reaction ~ Days + s(Subject, bs='re') + s(Days, Subject, bs='re'), 4 | data = lme4::sleepstudy, 5 | method = 'REML') 6 | 7 | test_that('Works on single lme model', { 8 | expect_s3_class(extract_fixed(ga_model), 'data.frame') 9 | }) 10 | 11 | test_that('Fails with non-gam', { 12 | expect_error(extract_fixed(lm(mpg ~ wt, mtcars))) 13 | }) 14 | 15 | 16 | test_that('extract_fixed_effects.gam handles no ci', { 17 | expect_s3_class(extract_fixed(ga_model, ci_level = 0), 'data.frame') 18 | }) 19 | 20 | 21 | test_that('extract_fixed_effects.gam handles digits', { 22 | expect_s3_class(extract_fixed(ga_model, digits = 2), 'data.frame') 23 | }) 24 | -------------------------------------------------------------------------------- /tests/testthat/test_extract_ranef.R: -------------------------------------------------------------------------------- 1 | context('test extract_ranef') 2 | 3 | test_that('Fails with non-gam', { 4 | expect_error(extract_ranef(lm(mpg ~ wt, mtcars))) 5 | }) 6 | 7 | test_that('extract_ranef.gam basic functionality', { 8 | expect_s3_class(extract_ranef(gam_1), 'data.frame') 9 | }) 10 | 11 | test_that('extract_ranef.gam basic functionality', { 12 | expect_s3_class(extract_ranef(gam_2), 'data.frame') 13 | }) 14 | 15 | test_that('extract_vc.gam basic functionality: bam', { 16 | expect_s3_class(extract_ranef(bam_1), 'data.frame') 17 | }) 18 | 19 | test_that('extract_ranef.gam works with multiple re', { 20 | expect_equal( 21 | nrow(extract_ranef(gam_3, re = 's')), 22 | nlevels(gam_3$model$s) 23 | ) 24 | }) 25 | 26 | test_that('extract_ranef.gam errors with bad re name', { 27 | expect_error(extract_ranef(gam_2, re = 'subject')) 28 | }) 29 | 30 | test_that('extract_ranef.gam errors with only non-factor random effects', 31 | { 32 | d = mgcv::gamSim(n = 100, verbose = FALSE) 33 | m = mgcv::gam(y ~ s(x1, bs = 're'), data = d) 34 | expect_error(suppressWarnings(extract_ranef(m))) 35 | }) 36 | 37 | test_that('extract_ranef.gam warns with non-factor random effects', { 38 | set.seed(4) 39 | d = mgcv::gamSim(n = 100, verbose = FALSE) 40 | nb <- 10; n <- 100 41 | b <- rnorm(nb) * 2 ## random effect 42 | r <- sample(1:nb, n, replace = TRUE) ## r.e. levels 43 | y <- 2 + b[r] + rnorm(n) 44 | r <- factor(r) 45 | m = mgcv::gam(y ~ s(x1, bs = 're') + s(r, bs = 're'), 46 | data = cbind(d, r), 47 | method = 'REML') 48 | expect_warning(extract_ranef(m)) 49 | }) 50 | 51 | test_that('Fails if no factors', { 52 | 53 | ga_model_num_re = mgcv::gam(Reaction ~ s(Days) + s(Subject, bs='re') + s(Days, Subject, bs='re'), 54 | data = within(lme4::sleepstudy, {Subject = as.integer(Subject)}), 55 | method = 'REML') 56 | 57 | expect_error(suppressWarnings(extract_ranef(ga_model_num_re))) 58 | 59 | }) 60 | 61 | test_that('extract_ranef.brmsfit correct output', { 62 | expect_equal( 63 | nrow(extract_ranef(gam_2, re = 'Subject')), 64 | nlevels(lme4::sleepstudy$Subject)*2 65 | ) 66 | }) 67 | 68 | 69 | test_that('Ranef reflect lme4', { 70 | lmer_re = unlist(lme4::ranef(lme4::lmer(Reaction ~ Days 71 | + (Days || Subject), 72 | data=lme4::sleepstudy))) 73 | 74 | cor_re = cor(lmer_re, extract_ranef(gam_2)$value) 75 | expect_gt(cor_re, .99) 76 | }) 77 | 78 | test_that('Ranef do not include other smooths (for now)', { 79 | 80 | ga_model_sm = mgcv::gam(Reaction ~ s(Days) + s(Subject, bs='re') + s(Days, Subject, bs='re'), 81 | data = lme4::sleepstudy, 82 | method = 'REML') 83 | 84 | expect_s3_class(extract_ranef(ga_model_sm), 'data.frame') 85 | expect_equal(nrow(extract_ranef(ga_model_sm)), 36) 86 | 87 | }) 88 | 89 | test_that('Fails if RE is no factors', { 90 | 91 | ga_model_num_re = mgcv::gam(Reaction ~ s(Days) + s(Subject, bs='re') + s(Days, Subject, bs='re'), 92 | data = within(lme4::sleepstudy, {Subject = as.integer(Subject)}), 93 | method = 'REML') 94 | 95 | expect_error(suppressWarnings(extract_ranef(ga_model_num_re))) 96 | 97 | }) 98 | 99 | -------------------------------------------------------------------------------- /tests/testthat/test_extract_vc.R: -------------------------------------------------------------------------------- 1 | context('test extract variance components') 2 | 3 | 4 | ga_model = mgcv::gam(Reaction ~ Days + s(Subject, bs='re') + s(Days, Subject, bs='re'), 5 | data = lme4::sleepstudy, 6 | method = 'REML') 7 | 8 | 9 | 10 | # Test gam ---------------------------------------------------------------- 11 | 12 | 13 | 14 | test_that('Fails with non-gam', { 15 | expect_error(extract_vc(lm(mpg ~ wt, mtcars))) 16 | }) 17 | 18 | test_that('Fails with non-REML', { 19 | ga_model_noREML = mgcv::gam(Reaction ~ Days + s(Subject, bs='re') + s(Days, Subject, bs='re'), 20 | data = lme4::sleepstudy) 21 | expect_error(extract_vc(ga_model_noREML)) 22 | }) 23 | 24 | 25 | test_that('Works on single lme model', { 26 | expect_s3_class(extract_vc(gam_1), 'data.frame') 27 | }) 28 | 29 | 30 | test_that('extract_vc.gam basic functionality: random slopes', { 31 | expect_s3_class(extract_vc(gam_2), 'data.frame') 32 | }) 33 | 34 | test_that('extract_vc.gam basic functionality: multiple grouping factors', { 35 | expect_s3_class(extract_vc(gam_3), 'data.frame') 36 | }) 37 | 38 | test_that('extract_vc.gam basic functionality: bam', { 39 | expect_s3_class(extract_vc(bam_1), 'data.frame') 40 | }) 41 | 42 | test_that('extract_vc.gam basic functionality: correct results', { 43 | invisible( 44 | utils::capture.output( 45 | raw_output <- mgcv::gam.vcomp(gam_1)[,'std.dev'] 46 | ) 47 | ) 48 | names(raw_output) = NULL 49 | expect_equal(extract_vc(gam_1, digits = 10)$sd, raw_output) 50 | }) 51 | 52 | test_that('extract_vc.gam basic functionality: correct results', { 53 | invisible( 54 | utils::capture.output( 55 | raw_output <- mgcv::gam.vcomp(gam_2)[,'std.dev'] 56 | ) 57 | ) 58 | names(raw_output) = NULL 59 | expect_equal(extract_vc(gam_2, digits = 10)$sd, raw_output) 60 | }) 61 | 62 | test_that('extract_vc.gam works with ci_scale = var and alternate ci_level', { 63 | invisible( 64 | utils::capture.output( 65 | raw_output <- mgcv::gam.vcomp(gam_2, conf.lev = .9)[,'upper'] 66 | ) 67 | ) 68 | names(raw_output) = NULL 69 | expect_equal(extract_vc(gam_2, ci_level = .9, digits = 10)$sd_95, raw_output) 70 | }) 71 | 72 | 73 | test_that('extract_vc.gam works with ci_scale = var', { 74 | expect_type(extract_vc(gam_1, ci_scale = 'var')$var_2.5, 'double') 75 | expect_type(extract_vc(gam_1, ci_scale = 'sd')$sd_2.5, 'double') 76 | }) 77 | 78 | 79 | 80 | 81 | 82 | # Test bam ---------------------------------------------------------------- 83 | 84 | ba_model = mgcv::bam(Reaction ~ Days + s(Subject, bs='re') + s(Days, Subject, bs='re'), 85 | data = lme4::sleepstudy, 86 | method = 'REML') 87 | 88 | ba_model_bin = mgcv::bam(Reaction > median(Reaction) ~ Days + s(Subject, bs='re') + s(Days, Subject, bs='re'), 89 | data = lme4::sleepstudy, 90 | family = binomial, 91 | method = 'REML') 92 | 93 | 94 | test_that('Bam works on single cluster lme model', { 95 | expect_s3_class(extract_vc(ba_model), 'data.frame') 96 | }) 97 | 98 | test_that('Works on single cluster glme model', { 99 | expect_s3_class(extract_vc(ba_model_bin), 'data.frame') 100 | }) 101 | -------------------------------------------------------------------------------- /tests/testthat/test_predict_gamm.R: -------------------------------------------------------------------------------- 1 | context('test predict_gamm') 2 | 3 | ga_model = mgcv::gam(Reaction ~ Days 4 | + s(Subject, bs='re') 5 | + s(Days, Subject, bs='re'), 6 | data = lme4::sleepstudy, 7 | method = 'REML') 8 | 9 | sleepstudy = lme4::sleepstudy 10 | nd = sleepstudy[sample(1:180, 10),] 11 | 12 | # Basic checks 13 | test_that('Works on single lme model', { 14 | expect_s3_class(predict_gamm(ga_model), 'data.frame') 15 | }) 16 | 17 | test_that('Fails with non-gam', { 18 | expect_error(predict_gamm(lm(mpg ~ wt, mtcars))) 19 | }) 20 | 21 | test_that('Fails with non-character for include', { 22 | expect_error(predict_gamm(ga_model, include = TRUE)) 23 | }) 24 | 25 | test_that('Fails with non-character for exclude', { 26 | expect_error(predict_gamm(ga_model, exclude = TRUE)) 27 | }) 28 | 29 | test_that('Fails include in exclude', { 30 | expect_error(predict_gamm(ga_model, include = 's(Subject)', exclude = 's(Subject)')) 31 | }) 32 | 33 | test_that('Fails with non-character for re_form', { 34 | expect_error(predict_gamm(ga_model, re_form = TRUE)) 35 | }) 36 | 37 | test_that('Fails with non-logical for se', { 38 | expect_error(predict_gamm(ga_model, se = 'sure!')) 39 | }) 40 | 41 | test_that('Fails with non-logical for keep_prediction_data', { 42 | expect_error(predict_gamm(ga_model, keep_prediction_data = 'sure!')) 43 | }) 44 | 45 | 46 | # Other predictions ------------------------------------------------------- 47 | 48 | # newdata 49 | test_that('Ok for new data', { 50 | expect_s3_class(predict_gamm(ga_model, newdata = nd), 'data.frame') 51 | }) 52 | 53 | 54 | # random/fixed effects 55 | test_that('Can take specific re_form', { 56 | expect_s3_class(predict_gamm(ga_model, newdata = nd, re_form = 's(Subject)'), 'data.frame') 57 | }) 58 | 59 | test_that('Can take NA for re_form', { 60 | expect_s3_class(predict_gamm(ga_model, newdata = nd, re_form = NA), 'data.frame') 61 | }) 62 | 63 | # keeps data 64 | 65 | test_that('Can take arg for keep_prediction_data', { 66 | expect_equal( 67 | colnames(predict_gamm( 68 | ga_model, 69 | newdata = nd, 70 | keep_prediction_data = TRUE 71 | )), 72 | c(colnames(nd), 'prediction') 73 | ) 74 | }) 75 | 76 | test_that('Can take arg for keep_prediction_data', { 77 | expect_equal( 78 | colnames(predict_gamm( 79 | ga_model, 80 | keep_prediction_data = TRUE 81 | )), 82 | c(colnames(ga_model$model), 'prediction') 83 | ) 84 | }) 85 | 86 | # Other misc -------------------------------------------------------------- 87 | 88 | # can do se 89 | 90 | test_that('Test se', { 91 | expect_s3_class(predict_gamm(ga_model, se = TRUE), 'data.frame') 92 | }) 93 | 94 | # compare to lme4 95 | 96 | library(lme4); library(mgcv) 97 | lmer_model = lmer(Reaction ~ Days + (Days || Subject), data=sleepstudy) 98 | ga_model = gam(Reaction ~ Days + s(Subject, bs='re') 99 | + s(Days, Subject, bs='re'), 100 | data=sleepstudy, 101 | method = 'REML') 102 | 103 | cor_pred1 = cor(predict(lmer_model), predict_gamm(ga_model)) 104 | 105 | 106 | fe_only = cbind( 107 | lmer = predict(lmer_model, re.form = NA), 108 | gam1 = predict_gamm(ga_model, re_form = NA), 109 | gam2 = predict_gamm(ga_model, 110 | exclude = c('s(Subject)', "s(Days,Subject)")) 111 | ) 112 | 113 | # 114 | # head( 115 | # cbind(predict_gamm(ga_model, include = 'Days'), 116 | # predict(lm(Reaction ~ Days, sleepstudy)) 117 | # )) 118 | 119 | test_that('Can take NA for re_form', { 120 | expect_s3_class(predict_gamm(ga_model, newdata = nd, re_form = NA), 'data.frame') 121 | }) 122 | 123 | 124 | test_that('Predictions reflect lme4', { 125 | expect_gt(cor_pred1, .99) 126 | }) 127 | 128 | test_that('Predictions reflect lme4', { 129 | expect_equal(fe_only[,1], c(fe_only[,2])) 130 | }) 131 | 132 | test_that('exclude can equal re_form = NA', { 133 | expect_equal(fe_only[,2], fe_only[,3]) 134 | }) 135 | -------------------------------------------------------------------------------- /tests/testthat/test_summary_gamm.R: -------------------------------------------------------------------------------- 1 | context('summary_gamm') 2 | 3 | ga_model = mgcv::gam(Reaction ~ Days + s(Subject, bs='re') + s(Days, Subject, bs='re'), 4 | data = lme4::sleepstudy, 5 | method = 'REML') 6 | 7 | 8 | 9 | 10 | 11 | # test standard lme with single cluster var ------------------------------- 12 | 13 | test_that('Works on single cluster lme model', { 14 | expect_type(summary_gamm(ga_model), 'list') 15 | }) 16 | 17 | test_that('Fails with non-gam', { 18 | expect_error(summary_gamm(lm(mpg ~ wt, mtcars))) 19 | }) 20 | 21 | test_that('Returns df for vc', { 22 | expect_s3_class(summary_gamm(ga_model)$vc, 'data.frame') 23 | }) 24 | 25 | test_that('Returns df for fe', { 26 | expect_s3_class(summary_gamm(ga_model)$fe, 'data.frame') 27 | }) 28 | 29 | 30 | test_that('Returns invisible', { 31 | expect_invisible(summary_gamm(ga_model)) 32 | }) 33 | 34 | 35 | 36 | 37 | # Test alt dist ----------------------------------------------------------- 38 | 39 | ga_model_bin = mgcv::gam(Reaction > median(Reaction) ~ Days + s(Subject, bs='re') + s(Days, Subject, bs='re'), 40 | data = lme4::sleepstudy, 41 | family = binomial, 42 | method = 'REML') 43 | 44 | test_that('Works on single cluster glme model', { 45 | expect_type(summary_gamm(ga_model_bin), 'list') 46 | }) 47 | 48 | 49 | 50 | # Test bam ---------------------------------------------------------------- 51 | 52 | ba_model = mgcv::bam(Reaction ~ Days + s(Subject, bs='re') + s(Days, Subject, bs='re'), 53 | data = lme4::sleepstudy, 54 | method = 'REML') 55 | 56 | ba_model_bin = mgcv::bam(Reaction > median(Reaction) ~ Days + s(Subject, bs='re') + s(Days, Subject, bs='re'), 57 | data = lme4::sleepstudy, 58 | family = binomial, 59 | method = 'REML') 60 | 61 | 62 | test_that('Bam works on single cluster lme model', { 63 | expect_type(summary_gamm(ba_model), 'list') 64 | }) 65 | 66 | test_that('Works on single cluster glme model', { 67 | expect_type(summary_gamm(ba_model_bin), 'list') 68 | }) 69 | --------------------------------------------------------------------------------