Skip to content

Commit c3c37f3

Browse files
committed
Release 0.17.2 on CRAN
1 parent 736fddc commit c3c37f3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1375
-862
lines changed

DESCRIPTION

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ Package: sjstats
22
Type: Package
33
Encoding: UTF-8
44
Title: Collection of Convenient Functions for Common Statistical Computations
5-
Version: 0.17.1.9000
6-
Date: 2018-10-05
5+
Version: 0.17.2
6+
Date: 2018-11-15
77
Authors@R: person("Daniel", "Lüdecke", role = c("aut", "cre"), email = "[email protected]", comment = c(ORCID = "0000-0002-8895-3206"))
88
Maintainer: Daniel Lüdecke <[email protected]>
99
Description: Collection of convenient functions for common statistical computations,

NAMESPACE

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ S3method(icc,brmsfit)
2020
S3method(icc,glmmTMB)
2121
S3method(icc,merMod)
2222
S3method(icc,stanreg)
23+
S3method(is_singular,glmmTMB)
24+
S3method(is_singular,merMod)
2325
S3method(mcse,brmsfit)
2426
S3method(mcse,stanmvreg)
2527
S3method(mcse,stanreg)
@@ -80,6 +82,7 @@ S3method(print,sj_pval)
8082
S3method(print,sj_r2)
8183
S3method(print,sj_resample)
8284
S3method(print,sj_revar)
85+
S3method(print,sj_revar_adjust)
8386
S3method(print,sj_rope)
8487
S3method(print,sj_se_icc)
8588
S3method(print,sj_splithalf)

R/S3-methods.R

+28-2
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ print.sj_r2 <- function(x, digits = 3, ...) {
186186
#' @importFrom purrr map_chr map2_chr
187187
#' @export
188188
print.sj_icc <- function(x, digits = 4, ...) {
189-
cat("\nIntra-Class Correlation Coefficient for Generalized Linear Mixed Model\n\n")
189+
cat("\nIntraclass Correlation Coefficient for Generalized Linear Mixed Model\n\n")
190190
print_icc_and_r2(x, digits, ...)
191191
}
192192

@@ -216,7 +216,7 @@ print_icc_and_r2 <- function(x, digits, ...) {
216216
#' @export
217217
print.sj_icc_merMod <- function(x, comp, ...) {
218218
# print model information
219-
cat(sprintf("\n%s\n\n", attr(x, "model", exact = T)))
219+
cat(sprintf("\nIntraclass Correlation Coefficient for %s\n\n", attr(x, "model", exact = T)))
220220

221221
cat(crayon::blue(
222222
sprintf("Family : %s (%s)\nFormula: %s\n\n",
@@ -287,6 +287,8 @@ print.sj_icc_merMod <- function(x, comp, ...) {
287287
as.vector(x[i])))
288288
}
289289
}
290+
291+
cat("\n")
290292
}
291293

292294

@@ -1424,6 +1426,30 @@ print.sj_grpmeans <- function(x, ...) {
14241426
}
14251427

14261428

1429+
#' @importFrom crayon blue cyan
1430+
#' @export
1431+
print.sj_revar_adjust <- function(x, ...) {
1432+
cat("\nVariance Components of Mixed Models\n\n")
1433+
cat(crayon::blue(sprintf("Family : %s (%s)\nFormula: %s\n\n", x$family, x$link, deparse(x$formula))))
1434+
1435+
vals <- c(
1436+
sprintf("%.3f", x$var.fixef),
1437+
sprintf("%.3f", x$var.ranef),
1438+
sprintf("%.3f", x$var.disp),
1439+
sprintf("%.3f", x$var.dist),
1440+
sprintf("%.3f", x$var.resid)
1441+
)
1442+
1443+
vals <- format(vals, justify = "right")
1444+
1445+
cat(sprintf(" fixed: %s\n", vals[1]))
1446+
cat(sprintf(" random: %s\n", vals[2]))
1447+
cat(sprintf(" residual: %s\n", vals[5]))
1448+
cat(crayon::cyan(sprintf(" dispersion: %s\n", vals[3])))
1449+
cat(crayon::cyan(sprintf(" distribution: %s\n\n", vals[4])))
1450+
}
1451+
1452+
14271453
#' @export
14281454
print.sj_revar <- function(x, ...) {
14291455
# get parameters

R/converge_ok.R

+46-27
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,40 @@
1212
#' @param tolerance Indicates up to which value the convergence result is
1313
#' accepted. The smaller \code{tolerance} is, the stricter the test
1414
#' will be.
15+
#' @param ... Currently not used.
1516
#'
1617
#' @return For \code{converge_ok()}, a logical vector, which is \code{TRUE} if
1718
#' convergence is fine and \code{FALSE} if convergence is suspicious.
1819
#' Additionally, the convergence value is returned as return value's name.
1920
#' \code{is_singluar()} returns \code{TRUE} if the model fit is singular.
2021
#'
2122
#' @details \code{converge_ok()} provides an alternative convergence test for
22-
#' \code{\link[lme4]{merMod}}-objects, as discussed
23-
#' \href{https://github.com/lme4/lme4/issues/120}{here}
24-
#' and suggested by Ben Bolker in
25-
#' \href{https://github.com/lme4/lme4/issues/120#issuecomment-39920269}{this comment}.
26-
#' \cr \cr
27-
#' \code{is_singular()} checks if a model fit is singular, and can
28-
#' be used in case of post-fitting convergence warnings, such as
29-
#' warnings about negative eigenvalues of the Hessian. If the fit
30-
#' is singular (i.e. \code{is_singular()} returns \code{TRUE}), these
31-
#' warnings can most likely be ignored.
23+
#' \code{\link[lme4]{merMod}}-objects, as discussed
24+
#' \href{https://github.com/lme4/lme4/issues/120}{here}
25+
#' and suggested by Ben Bolker in
26+
#' \href{https://github.com/lme4/lme4/issues/120#issuecomment-39920269}{this comment}.
27+
#' \cr \cr
28+
#' If a model is "singular", this means that some dimensions of the variance-covariance
29+
#' matrix have been estimated as exactly zero. \code{is_singular()} checks if
30+
#' a model fit is singular, and can be used in case of post-fitting convergence
31+
#' warnings, such as warnings about negative eigenvalues of the Hessian. If the fit
32+
#' is singular (i.e. \code{is_singular()} returns \code{TRUE}), these warnings
33+
#' can most likely be ignored.
34+
#' \cr \cr
35+
#' There is no gold-standard about how to deal with singularity and which
36+
#' random-effects specification to choose. Beside using fully Bayesian methods
37+
#' (with informative priors), proposals in a frequentist framework are:
38+
#' \itemize{
39+
#' \item avoid fitting overly complex models, such that the variance-covariance matrices can be estimated precisely enough (\cite{Matuschek et al. 2017})
40+
#' \item use some form of model selection to choose a model that balances predictive accuracy and overfitting/type I error (\cite{Bates et al. 2015}, \cite{Matuschek et al. 2017})
41+
#' \item \dQuote{keep it maximal}, i.e. fit the most complex model consistent with the experimental design, removing only terms required to allow a non-singular fit (\cite{Barr et al. 2013})
42+
#' }
43+
#'
44+
#' @references \itemize{
45+
#' \item Bates D, Kliegl R, Vasishth S, Baayen H. Parsimonious Mixed Models. arXiv:1506.04967, June 2015.
46+
#' \item Barr DJ, Levy R, Scheepers C, Tily HJ. Random effects structure for confirmatory hypothesis testing: Keep it maximal. Journal of Memory and Language, 68(3):255–278, April 2013.
47+
#' \item Matuschek H, Kliegl R, Vasishth S, Baayen H, Bates D. Balancing type I error and power in linear mixed models. Journal of Memory and Language, 94:305–315, 2017.
48+
#' }
3249
#'
3350
#' @examples
3451
#' library(sjmisc)
@@ -74,23 +91,25 @@ converge_ok <- function(x, tolerance = 0.001) {
7491
}
7592

7693

77-
#' @importFrom lme4 getME
78-
#' @importFrom glmmTMB getME
7994
#' @rdname converge_ok
8095
#' @export
81-
is_singular <- function(x, tolerance = 1e-5) {
82-
if (is_merMod(x)) {
83-
theta <- lme4::getME(x, "theta")
84-
# diagonal elements are identifiable because they are fitted
85-
# with a lower bound of zero ...
86-
diag.element <- lme4::getME(x, "lower") == 0
87-
any(abs(theta[diag.element]) < tolerance)
88-
} else if (inherits(x, "glmmTMB")) {
89-
theta <- glmmTMB::getME(x, "theta")
90-
# diagonal elements are identifiable because they are fitted
91-
# with a lower bound of zero ...
92-
diag.element <- glmmTMB::getME(x, "lower") == 0
93-
any(abs(theta[diag.element]) < tolerance)
94-
} else
95-
warning("`x` must be a merMod- or glmmTMB-object.", call. = F)
96+
is_singular <- function(x, tolerance = 1e-5, ...) {
97+
UseMethod("is_singular")
98+
}
99+
100+
#' @importFrom lme4 getME
101+
#' @export
102+
is_singular.merMod <- function(x, tolerance = 1e-5, ...) {
103+
theta <- lme4::getME(x, "theta")
104+
# diagonal elements are identifiable because they are fitted
105+
# with a lower bound of zero ...
106+
diag.element <- lme4::getME(x, "lower") == 0
107+
any(abs(theta[diag.element]) < tolerance)
108+
}
109+
110+
#' @importFrom lme4 VarCorr
111+
#' @export
112+
is_singular.glmmTMB <- function(x, tolerance = 1e-5, ...) {
113+
vc <- collapse_cond(lme4::VarCorr(x))
114+
any(sapply(vc, function(.x) any(abs(diag(.x)) < tolerance)))
96115
}

R/icc.R

+59-20
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@
1919
#' @param ppd Logical, if \code{TRUE}, variance decomposition is based on the
2020
#' posterior predictive distribution, which is the correct way for Bayesian
2121
#' non-Gaussian models.
22-
#' @param adjusted Logical, if \code{TRUE}, the adjusted (and conditional) ICC
23-
#' is calculated, which reflects the uncertainty of all random effects (see
24-
#' 'Details'). \strong{Note} that if \code{adjusted = TRUE}, \strong{no}
25-
#' additional information on the variance components is returned.
26-
#'
22+
#' @param adjusted Logical, if \code{TRUE}, the adjusted (and
23+
#' conditional) ICC is calculated, which reflects the uncertainty of all
24+
#' random effects (see 'Details').
2725
#'
2826
#' @inheritParams hdi
2927
#'
@@ -103,7 +101,7 @@
103101
#' To get a meaningful ICC also for models with random slopes, use \code{adjusted = TRUE}.
104102
#' The adjusted ICC used the mean random effect variance, which is based
105103
#' on the random effect variances for each value of the random slope
106-
#' (see \cite{Johnson 2014}).
104+
#' (see \cite{Johnson et al. 2014}).
107105
#' \cr \cr
108106
#' \strong{ICC for models with multiple or nested random effects}
109107
#' \cr \cr
@@ -759,15 +757,23 @@ icc.brmsfit <- function(x, re.form = NULL, typical = "mean", prob = .89, ppd = F
759757
#' objects are supported.
760758
#'
761759
#' @param x Fitted mixed effects model (of class \code{merMod}, \code{glmmTMB},
762-
#' \code{stanreg} or \code{brmsfit}). \code{get_re_var()} also accepts
763-
#' an object of class \code{icc.lme4}, as returned by the
764-
#' \code{\link{icc}} function.
760+
#' \code{stanreg} or \code{brmsfit}). \code{get_re_var()} also accepts
761+
#' an object of class \code{icc.lme4}, as returned by the
762+
#' \code{\link{icc}} function.
765763
#' @param comp Name of the variance component to be returned. See 'Details'.
764+
#' @param adjusted Logical, if \code{TRUE}, returns the variance of the fixed
765+
#' and random effects as well as of the additive dispersion and
766+
#' distribution-specific variance, which are used to calculate the
767+
#' adjusted and conditional \code{\link{r2}} and \code{\link{icc}}.
766768
#'
767769
#' @return \code{get_re_var()} returns the value of the requested variance component,
768770
#' \code{re_var()} returns all random effects variances.
769771
#'
770-
#' @references Aguinis H, Gottfredson RK, Culpepper SA. 2013. Best-Practice Recommendations for Estimating Cross-Level Interaction Effects Using Multilevel Modeling. Journal of Management 39(6): 1490–1528 (\doi{10.1177/0149206313478188})
772+
#' @references \itemize{
773+
#' \item Aguinis H, Gottfredson RK, Culpepper SA. 2013. Best-Practice Recommendations for Estimating Cross-Level Interaction Effects Using Multilevel Modeling. Journal of Management 39(6): 1490–1528 (\doi{10.1177/0149206313478188})
774+
#' \item Johnson PC, O'Hara RB. 2014. Extension of Nakagawa & Schielzeth's R2GLMM to random slopes models. Methods Ecol Evol, 5: 944-946. (\doi{10.1111/2041-210X.12225})
775+
#' \item Nakagawa S, Johnson P, Schielzeth H (2017) The coefficient of determination R2 and intra-class correlation coefficient from generalized linear mixed-effects models revisted and expanded. J. R. Soc. Interface 14. \doi{10.1098/rsif.2017.0213}
776+
#' }
771777
#'
772778
#' @details The random effect variances indicate the between- and within-group
773779
#' variances as well as random-slope variance and random-slope-intercept
@@ -785,6 +791,18 @@ icc.brmsfit <- function(x, re.form = NULL, typical = "mean", prob = .89, ppd = F
785791
#' direct effects) affect the between-group-variance. Cross-level
786792
#' interaction effects are group-level factors that explain the
787793
#' variance in random slopes (Aguinis et al. 2013).
794+
#' \cr \cr
795+
#' If \code{adjusted = TRUE}, the variance of the fixed and random
796+
#' effects as well as of the additive dispersion and
797+
#' distribution-specific variance are returned (see \cite{Johnson et al. 2014}
798+
#' and \cite{Nakagawa et al. 2017}):
799+
#' \describe{
800+
#' \item{\code{"fixed"}}{variance attributable to the fixed effects}
801+
#' \item{\code{"random"}}{variance of random effects}
802+
#' \item{\code{"dispersion"}}{variance due to additive dispersion}
803+
#' \item{\code{"distribution"}}{distribution-specific variance}
804+
#' \item{\code{"residual"}}{sum of dispersion and distribution}
805+
#' }
788806
#'
789807
#' @seealso \code{\link{icc}}
790808
#'
@@ -794,6 +812,7 @@ icc.brmsfit <- function(x, re.form = NULL, typical = "mean", prob = .89, ppd = F
794812
#'
795813
#' # all random effect variance components
796814
#' re_var(fit1)
815+
#' re_var(fit1, adjusted = TRUE)
797816
#'
798817
#' # just the rand. slope-intercept covariance
799818
#' get_re_var(fit1, "tau.01")
@@ -806,20 +825,40 @@ icc.brmsfit <- function(x, re.form = NULL, typical = "mean", prob = .89, ppd = F
806825
#' @importFrom purrr map map2 flatten_dbl flatten_chr
807826
#' @importFrom sjmisc trim
808827
#' @export
809-
re_var <- function(x) {
810-
# iterate all attributes and return them as vector
811-
rv <- c("sigma_2", "tau.00", "tau.11", "tau.01", "rho.01")
828+
re_var <- function(x, adjusted = FALSE) {
812829

813-
# compute icc
814-
icc_ <- suppressMessages(icc(x))
830+
if (adjusted) {
815831

816-
rv_ <- purrr::map(rv, ~ attr(icc_, .x, exact = TRUE))
817-
rn <- purrr::map2(1:length(rv_), rv, ~ sjmisc::trim(paste(names(rv_[[.x]]), .y, sep = "_")))
818-
rv_ <- purrr::flatten_dbl(rv_)
832+
rv <- r2(x)
819833

820-
names(rv_) <- purrr::flatten_chr(rn)[1:length(rv_)]
834+
rv_ <- list(
835+
var.fixef = attr(rv, "var.fixef", exact = TRUE),
836+
var.ranef = attr(rv, "var.ranef", exact = TRUE),
837+
var.disp = attr(rv, "var.disp", exact = TRUE),
838+
var.dist = attr(rv, "var.dist", exact = TRUE),
839+
var.resid = attr(rv, "var.resid", exact = TRUE),
840+
formula = attr(rv, "formula", exact = TRUE),
841+
family = attr(rv, "family", exact = TRUE),
842+
link = attr(rv, "link", exact = TRUE)
843+
)
844+
845+
class(rv_) <- c("sj_revar_adjust", class(rv_))
846+
847+
} else {
848+
# iterate all attributes and return them as vector
849+
rv <- c("sigma_2", "tau.00", "tau.11", "tau.01", "rho.01")
821850

822-
class(rv_) <- c("sj_revar", class(rv_))
851+
# compute icc
852+
icc_ <- suppressMessages(icc(x))
853+
854+
rv_ <- purrr::map(rv, ~ attr(icc_, .x, exact = TRUE))
855+
rn <- purrr::map2(1:length(rv_), rv, ~ sjmisc::trim(paste(names(rv_[[.x]]), .y, sep = "_")))
856+
rv_ <- purrr::flatten_dbl(rv_)
857+
858+
names(rv_) <- purrr::flatten_chr(rn)[1:length(rv_)]
859+
860+
class(rv_) <- c("sj_revar", class(rv_))
861+
}
823862

824863
rv_
825864
}

R/pred_vars.R

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#'
44
#' @description Several functions to retrieve information from model objects,
55
#' like variable names, link-inverse function, model frame,
6-
#' model_family etc., in a tidy and consistent way.
6+
#' model family etc., in a tidy and consistent way.
77
#'
88
#' @param x A fitted model; for \code{var_names()}, \code{x} may also be a
99
#' character vector.

0 commit comments

Comments
 (0)