From e57320ad8be82acb0508504cc7b4918bca6c5822 Mon Sep 17 00:00:00 2001 From: Ken Kellner Date: Mon, 16 Sep 2024 10:38:54 -0400 Subject: [PATCH] Clarify how ranef works and add option to not add mean, fixes #82 --- DESCRIPTION | 4 ++-- R/ranef.R | 14 ++++++++++++-- man/ranef-ubmsFit-method.Rd | 12 +++++++++++- tests/testthat/test_ranef.R | 9 +++++++++ 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 20fb5a2..ddbe6f6 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: ubms -Version: 1.2.6.9001 -Date: 2024-09-15 +Version: 1.2.6.9002 +Date: 2024-09-16 Title: Bayesian Models for Data from Unmarked Animals using 'Stan' Authors@R: person("Ken", "Kellner", email="contact@kenkellner.com", role=c("cre","aut")) diff --git a/R/ranef.R b/R/ranef.R index 9d66a81..6e135c6 100644 --- a/R/ranef.R +++ b/R/ranef.R @@ -5,11 +5,19 @@ #' \code{ranef} for \code{unmarkedFit} objects. To get functionality similar #' to that of \code{unmarkedFit}, use \code{posterior_predict}. #' +#' Note: by default this function adds the overall intercept or slope +#' to the (mean-0) random effect to get the complete random intercept or slope. +#' In this way the output is more like the output of \code{lme4::coef} +#' and not \code{lme4::ranef}. You can turn this off and return just the +#' mean-0 random effect by setting argument \code{add_mean = FALSE}. +#' #' @param object A fitted model of class \code{ubmsFit} #' @param submodel The name of the submodel, as a character string, for #' which to generate the random effects #' @param summary If \code{TRUE}, calculate mean, SD, and 95% uncertainty interval #' for each random effect term +#' @param add_mean If \code{TRUE} (the default) add the overall intercept or +#' slope mean and return the complete random intercept or slope. #' @param ... Currently ignored #' #' @return If \code{summary=FALSE}, a list of random effect values; if @@ -21,7 +29,8 @@ #' @include fit.R #' @importFrom unmarked ranef #' @export -setMethod("ranef","ubmsFit", function(object, submodel, summary=FALSE, ...){ +setMethod("ranef","ubmsFit", function(object, submodel, summary=FALSE, + add_mean = TRUE, ...){ sm <- object[submodel] if(!has_random(sm)){ @@ -42,7 +51,8 @@ setMethod("ranef","ubmsFit", function(object, submodel, summary=FALSE, ...){ re_samples <- re_samples[,b_ind[1]:b_ind[2]] #Add mean value if this is an effects parameterization - if(trm %in% beta_names(sm)){ + if(trm %in% beta_names(sm) & add_mean){ + message("Adding the mean to get the complete random slope/intercept") beta_ind <- which(beta_names(sm) == trm) mn_samples <- extract(object, paste0("beta_",submodel))[[1]] mn_samples <- mn_samples[,beta_ind] diff --git a/man/ranef-ubmsFit-method.Rd b/man/ranef-ubmsFit-method.Rd index 2a1d466..46d0a44 100644 --- a/man/ranef-ubmsFit-method.Rd +++ b/man/ranef-ubmsFit-method.Rd @@ -5,7 +5,7 @@ \alias{ranef} \title{Extract Random Effects} \usage{ -\S4method{ranef}{ubmsFit}(object, submodel, summary = FALSE, ...) +\S4method{ranef}{ubmsFit}(object, submodel, summary = FALSE, add_mean = TRUE, ...) } \arguments{ \item{object}{A fitted model of class \code{ubmsFit}} @@ -16,6 +16,9 @@ which to generate the random effects} \item{summary}{If \code{TRUE}, calculate mean, SD, and 95% uncertainty interval for each random effect term} +\item{add_mean}{If \code{TRUE} (the default) add the overall intercept or +slope mean and return the complete random intercept or slope.} + \item{...}{Currently ignored} } \value{ @@ -29,6 +32,13 @@ works like \code{ranef} for \code{merMod} objects from \code{lme4}, not like \code{ranef} for \code{unmarkedFit} objects. To get functionality similar to that of \code{unmarkedFit}, use \code{posterior_predict}. } +\details{ +Note: by default this function adds the overall intercept or slope +to the (mean-0) random effect to get the complete random intercept or slope. +In this way the output is more like the output of \code{lme4::coef} +and not \code{lme4::ranef}. You can turn this off and return just the +mean-0 random effect by setting argument \code{add_mean = FALSE}. +} \seealso{ \code{\link[lme4]{ranef}}, \code{\link{posterior_predict}} } diff --git a/tests/testthat/test_ranef.R b/tests/testthat/test_ranef.R index 3ef9882..32f3bc7 100644 --- a/tests/testthat/test_ranef.R +++ b/tests/testthat/test_ranef.R @@ -69,6 +69,15 @@ test_that("ranef works with multiple random effects",{ r2 <- ranef(fit3, "state", summary=TRUE) }) +test_that("setting add_mean = FALSE works", { + r <- expect_message(ranef(fit, 'state')) + r2 <- expect_no_message(ranef(fit, 'state', add_mean=FALSE)) + + # manually add the mean + r2_mn <- coef(fit)[1] + r2$x2[[1]] + expect_equal(r$x2[[1]], r2_mn) +}) + test_that("combine_same_name combines lists properly",{ test1 <- list(a=list(a1=c(1,1)), a=list(a2=c(2,2)), b=list(b1=c(1,1))) expect_equal(length(test1$a), 1)