Skip to content

Commit

Permalink
Merge branch 'main' into update_outlier_vignette
Browse files Browse the repository at this point in the history
  • Loading branch information
strengejacke authored Jul 13, 2024
2 parents be6c24d + 413d85b commit 5a4dd64
Show file tree
Hide file tree
Showing 33 changed files with 590 additions and 200 deletions.
24 changes: 13 additions & 11 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Type: Package
Package: performance
Title: Assessment of Regression Models Performance
Version: 0.12.0.4
Authors@R:
Version: 0.12.0.9
Authors@R:
c(person(given = "Daniel",
family = "Lüdecke",
role = c("aut", "cre"),
Expand Down Expand Up @@ -39,18 +39,18 @@ Authors@R:
email = "[email protected]",
comment = c(ORCID = "0000-0003-4315-6788", Twitter = "@rempsyc")),
person(given = "Vincent",
family = "Arel-Bundock",
email = "[email protected]",
family = "Arel-Bundock",
email = "[email protected]",
role = "ctb",
comment = c(ORCID = "0000-0003-2042-7063")),
person(given = "Martin",
family = "Jullum",
role = "rev"),
person(given = "gjo11",
role = "rev"),
person("Etienne",
"Bacher", ,
"[email protected]",
person("Etienne",
"Bacher", ,
"[email protected]",
role = "ctb",
comment = c(ORCID = "0000-0002-9271-5075")))
Maintainer: Daniel Lüdecke <[email protected]>
Expand All @@ -70,8 +70,8 @@ Depends:
R (>= 3.6)
Imports:
bayestestR (>= 0.13.2),
insight (>= 0.20.1),
datawizard (>= 0.11.0),
insight (>= 0.20.2),
datawizard (>= 0.10.0),
stats,
utils
Suggests:
Expand All @@ -93,14 +93,15 @@ Suggests:
DHARMa,
estimatr,
fixest,
flextable,
forecast,
gamm4,
geomtextpath,
ggplot2,
glmmTMB,
graphics,
Hmisc,
httr,
httr2,
ICS,
ICSOutlier,
ISLR,
Expand Down Expand Up @@ -130,6 +131,8 @@ Suggests:
quantreg,
qqplotr (>= 0.0.6),
randomForest,
RcppEigen,
rempsyc,
rmarkdown,
rstanarm,
rstantools,
Expand All @@ -152,4 +155,3 @@ Config/Needs/website:
r-lib/pkgdown,
easystats/easystatstemplate
Config/rcmdcheck/ignore-inconsequential-notes: true
Remotes: easystats/insight
4 changes: 4 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ S3method(display,test_performance)
S3method(fitted,BFBayesFactor)
S3method(format,compare_performance)
S3method(format,performance_model)
S3method(format,performance_rmse)
S3method(format,test_performance)
S3method(logLik,cpglm)
S3method(logLik,iv_robust)
Expand Down Expand Up @@ -319,6 +320,7 @@ S3method(print,performance_hosmer)
S3method(print,performance_model)
S3method(print,performance_pcp)
S3method(print,performance_pp_check)
S3method(print,performance_rmse)
S3method(print,performance_roc)
S3method(print,performance_score)
S3method(print,performance_simres)
Expand Down Expand Up @@ -451,6 +453,7 @@ S3method(r2_coxsnell,survreg)
S3method(r2_coxsnell,svycoxph)
S3method(r2_coxsnell,truncreg)
S3method(r2_efron,default)
S3method(r2_ferrari,default)
S3method(r2_kullback,default)
S3method(r2_kullback,glm)
S3method(r2_loo_posterior,BFBayesFactor)
Expand Down Expand Up @@ -597,6 +600,7 @@ export(r2)
export(r2_bayes)
export(r2_coxsnell)
export(r2_efron)
export(r2_ferrari)
export(r2_kullback)
export(r2_loo)
export(r2_loo_posterior)
Expand Down
7 changes: 7 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
* `icc()` and `r2_nakagawa()` get a `model_component` argument indicating the
component for zero-inflation or hurdle models.

* `performance_rmse()` (resp. `rmse()`) can now compute analytical and
bootstrapped confidence intervals. The function gains following new arguments:
`ci`, `ci_method` and `iterations`.

* New function `r2_ferrari()` to compute Ferrari & Cribari-Neto's R2 for
generalized linear models, in particular beta-regression.

# performance 0.12.0

## Breaking
Expand Down
14 changes: 7 additions & 7 deletions R/check_distribution.R
Original file line number Diff line number Diff line change
Expand Up @@ -191,33 +191,33 @@ check_distribution.numeric <- function(model) {
# validation check, remove missings
x <- x[!is.na(x)]

mode <- NULL
mode_value <- NULL
# find mode for integer, or MAP for distributions
if (all(.is_integer(x))) {
mode <- datawizard::distribution_mode(x)
mode_value <- datawizard::distribution_mode(x)
} else {
# this might fail, so we wrap in ".safe()"
mode <- tryCatch(
mode_value <- tryCatch(
as.numeric(bayestestR::map_estimate(x, bw = "nrd0")),
error = function(e) NULL
)
if (is.null(mode)) {
mode <- tryCatch(
if (is.null(mode_value)) {
mode_value <- tryCatch(
as.numeric(bayestestR::map_estimate(x, bw = "kernel")),
error = function(e) NULL
)
}
}

if (is.null(mode)) {
if (is.null(mode_value)) {
mean_mode_diff <- mean(x) - datawizard::distribution_mode(x)
msg <- "Could not accurately estimate the mode."
if (!is.null(type)) {
msg <- paste(msg, "Predicted distribution of the", type, "may be less accurate.")
}
insight::format_alert(msg)
} else {
mean_mode_diff <- .safe(mean(x) - mode)
mean_mode_diff <- .safe(mean(x) - mode_value)
}

data.frame(
Expand Down
2 changes: 1 addition & 1 deletion R/check_homogeneity.R
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ check_homogeneity.afex_aov <- function(x, method = "levene", ...) {
between <- between[!is_covar]
}

form <- stats::formula(paste0(dv, "~", paste0(between, collapse = "*")))
form <- stats::formula(paste0(dv, "~", paste(between, collapse = "*")))
test <- car::leveneTest(form, ag_data, center = mean, ...)

p.val <- test[1, "Pr(>F)"]
Expand Down
2 changes: 1 addition & 1 deletion R/helpers.R
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# small wrapper around this commonly used try-catch
.safe <- function(code, on_error = NULL) {
if (getOption("easystats_erros", FALSE) && is.null(on_error)) {
if (isTRUE(getOption("easystats_errors", FALSE) && is.null(on_error))) {
code
} else {
tryCatch(code, error = function(e) on_error)
Expand Down
73 changes: 43 additions & 30 deletions R/icc.R
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#' Intraclass Correlation Coefficient (ICC)
#' @title Intraclass Correlation Coefficient (ICC)
#' @name icc
#'
#' @description
#' This function calculates the intraclass-correlation coefficient (ICC) -
#' sometimes also called *variance partition coefficient* (VPC) or
#' *repeatability* - for mixed effects models. The ICC can be calculated for all
Expand All @@ -15,32 +17,32 @@
#' Else, for instance for nested models, name a specific group-level effect
#' to calculate the variance decomposition for this group-level. See 'Details'
#' and `?brms::posterior_predict`.
#' @param ci Confidence resp. credible interval level. For `icc()` and `r2()`,
#' confidence intervals are based on bootstrapped samples from the ICC resp.
#' R2 value. See `iterations`.
#' @param by_group Logical, if `TRUE`, `icc()` returns the variance
#' components for each random-effects level (if there are multiple levels).
#' See 'Details'.
#' @param ci Confidence resp. credible interval level. For `icc()`, `r2()`, and
#' `rmse()`, confidence intervals are based on bootstrapped samples from the
#' ICC, R2 or RMSE value. See `iterations`.
#' @param by_group Logical, if `TRUE`, `icc()` returns the variance components
#' for each random-effects level (if there are multiple levels). See 'Details'.
#' @param iterations Number of bootstrap-replicates when computing confidence
#' intervals for the ICC or R2.
#' intervals for the ICC, R2, RMSE etc.
#' @param ci_method Character string, indicating the bootstrap-method. Should
#' be `NULL` (default), in which case `lme4::bootMer()` is used for
#' bootstrapped confidence intervals. However, if bootstrapped intervals cannot
#' be calculated this was, try `ci_method = "boot"`, which falls back to
#' `boot::boot()`. This may successfully return bootstrapped confidence intervals,
#' but bootstrapped samples may not be appropriate for the multilevel structure
#' of the model. There is also an option `ci_method = "analytical"`, which tries
#' to calculate analytical confidence assuming a chi-squared distribution.
#' However, these intervals are rather inaccurate and often too narrow. It is
#' recommended to calculate bootstrapped confidence intervals for mixed models.
#' be `NULL` (default), in which case `lme4::bootMer()` is used for bootstrapped
#' confidence intervals. However, if bootstrapped intervals cannot be calculated
#' this way, try `ci_method = "boot"`, which falls back to `boot::boot()`. This
#' may successfully return bootstrapped confidence intervals, but bootstrapped
#' samples may not be appropriate for the multilevel structure of the model.
#' There is also an option `ci_method = "analytical"`, which tries to calculate
#' analytical confidence assuming a chi-squared distribution. However, these
#' intervals are rather inaccurate and often too narrow. It is recommended to
#' calculate bootstrapped confidence intervals for mixed models.
#' @param verbose Toggle warnings and messages.
#' @param null_model Optional, a null model to compute the random effect variances,
#' which is passed to [`insight::get_variance()`]. Usually only required if
#' calculation of r-squared or ICC fails when `null_model` is not specified. If
#' calculating the null model takes longer and you already have fit the null
#' model, you can pass it here, too, to speed up the process.
#' @param ... Arguments passed down to `lme4::bootMer()` or `boot::boot()`
#' for bootstrapped ICC or R2.
#' for bootstrapped ICC, R2, RMSE etc.; for `variance_decomposition()`,
#' arguments are passed down to `brms::posterior_predict()`.
#'
#' @inheritParams r2_bayes
#' @inheritParams insight::get_variance
Expand Down Expand Up @@ -247,7 +249,12 @@ icc <- function(model,
# iccs between groups
# n_grps <- length(vars$var.intercept)
# level_combinations <- utils::combn(1:n_grps, m = n_grps - 1, simplify = FALSE)
# icc_grp <- sapply(level_combinations, function(v) vars$var.intercept[v[1]] / (vars$var.intercept[v[1]] + vars$var.intercept[v[2]]))
# icc_grp <- sapply(
# level_combinations,
# function(v) {
# vars$var.intercept[v[1]] / (vars$var.intercept[v[1]] + vars$var.intercept[v[2]])
# }
# )
#
# out2 <- data.frame(
# Group1 = group_names[sapply(level_combinations, function(i) i[1])],
Expand All @@ -273,11 +280,11 @@ icc <- function(model,
# this is experimental!
if (identical(ci_method, "analytical")) {
result <- .safe(.analytical_icc_ci(model, ci))
if (!is.null(result)) {
if (is.null(result)) {
icc_ci_adjusted <- icc_ci_unadjusted <- NA
} else {
icc_ci_adjusted <- result$ICC_adjusted
icc_ci_unadjusted <- result$ICC_unadjusted
} else {
icc_ci_adjusted <- icc_ci_unadjusted <- NA
}
} else {
result <- .bootstrap_icc(model, iterations, tolerance, ci_method, ...)
Expand Down Expand Up @@ -321,8 +328,6 @@ icc <- function(model,



#' @param ... Arguments passed down to `brms::posterior_predict()`.
#' @inheritParams icc
#' @rdname icc
#' @export
variance_decomposition <- function(model,
Expand Down Expand Up @@ -428,7 +433,7 @@ print.icc <- function(x, digits = 3, ...) {
}

# separate lines for multiple R2
out <- paste0(out, collapse = "\n")
out <- paste(out, collapse = "\n")

cat(out)
cat("\n")
Expand Down Expand Up @@ -591,7 +596,11 @@ print.icc_decomposed <- function(x, digits = 2, ...) {
.boot_icc_fun <- function(data, indices, model, tolerance) {
d <- data[indices, ] # allows boot to select sample
fit <- suppressWarnings(suppressMessages(stats::update(model, data = d)))
vars <- .compute_random_vars(fit, tolerance, verbose = FALSE)
vars <- .compute_random_vars(
fit,
tolerance,
verbose = isTRUE(getOption("easystats_errors", FALSE))
)
if (is.null(vars) || all(is.na(vars))) {
return(c(NA, NA))
}
Expand All @@ -604,7 +613,11 @@ print.icc_decomposed <- function(x, digits = 2, ...) {

# bootstrapping using "lme4::bootMer"
.boot_icc_fun_lme4 <- function(model) {
vars <- .compute_random_vars(model, tolerance = 1e-05, verbose = FALSE)
vars <- .compute_random_vars(
model,
tolerance = 1e-10,
verbose = isTRUE(getOption("easystats_errors", FALSE))
)
if (is.null(vars) || all(is.na(vars))) {
return(c(NA, NA))
}
Expand Down Expand Up @@ -685,10 +698,10 @@ print.icc_decomposed <- function(x, digits = 2, ...) {
}

model_rank <- tryCatch(
if (!is.null(model$rank)) {
model$rank - df_int
} else {
if (is.null(model$rank)) {
insight::n_parameters(model) - df_int
} else {
model$rank - df_int
},
error = function(e) insight::n_parameters(model) - df_int
)
Expand Down
Loading

0 comments on commit 5a4dd64

Please sign in to comment.