From dfc6ffbff27f9a173906c9b9a5af74f29b14bfe7 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 8 Oct 2025 14:35:18 +0200 Subject: [PATCH 1/4] `check_autocorrelation()` gets methods for `DHARMa` objects and objects from `simulate_residuals()`. --- DESCRIPTION | 2 +- NEWS.md | 3 ++ R/check_autocorrelation.R | 33 +++++++++++- .../test-check_autocorrelation_simres.R | 51 +++++++++++++++++++ 4 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 tests/testthat/test-check_autocorrelation_simres.R diff --git a/DESCRIPTION b/DESCRIPTION index 5f39651ce..061d9c639 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: performance Title: Assessment of Regression Models Performance -Version: 0.15.2.1 +Version: 0.15.2.2 Authors@R: c(person(given = "Daniel", family = "Lüdecke", diff --git a/NEWS.md b/NEWS.md index 087a94874..e67514eff 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,9 @@ ## Changes +* `check_autocorrelation()` gets methods for `DHARMa` objects and objects from + `simulate_residuals()`. + * Improved documentation for printing-methods. # performance 0.15.2 diff --git a/R/check_autocorrelation.R b/R/check_autocorrelation.R index e1ed952e0..bef3cce46 100644 --- a/R/check_autocorrelation.R +++ b/R/check_autocorrelation.R @@ -4,9 +4,12 @@ #' @description Check model for independence of residuals, i.e. for autocorrelation #' of error terms. #' -#' @param x A model object. +#' @param x A model object, or an object returned by `simulate_residuals()`. #' @param nsim Number of simulations for the Durbin-Watson-Test. -#' @param ... Currently not used. +#' @param time A vector with time values to specify the temporal order of the data. +#' Only used if `x` is an object returned by `simulate_residuals()` or by `DHARMa`. +#' @param ... Currently not used for models. For simulated residuals, arguments are +#' passed to `DHARMa::testTemporalAutocorrelation()`. #' #' @return Invisibly returns the p-value of the test statistics. A p-value < 0.05 #' indicates autocorrelated residuals. @@ -48,6 +51,32 @@ check_autocorrelation.default <- function(x, nsim = 1000, ...) { p.val } +#' @rdname check_autocorrelation +#' @export +check_autocorrelation.performance_simres <- function(x, time = NULL, ...) { + insight::check_if_installed("DHARMa") + + if (is.null(time)) { + insight::format_warning( + "Data are assumed to be ordered by time. If this is not the case, please provide a `time` argument." + ) + time <- seq_along(x$scaledResiduals) + } + + # Use DHARMa's temporal autocorrelation test + # This requires the residuals to be ordered by time + # DHARMa::testTemporalAutocorrelation expects a DHARMa object + result <- DHARMa::testTemporalAutocorrelation(x, time = time, plot = FALSE, ...) + + # Extract p-value from the result + p.val <- result$p.value + + class(p.val) <- c("check_autocorrelation", "see_check_autocorrelation", class(p.val)) + p.val +} + +#' @export +check_autocorrelation.DHARMa <- check_autocorrelation.performance_simres # methods ------------------------------ diff --git a/tests/testthat/test-check_autocorrelation_simres.R b/tests/testthat/test-check_autocorrelation_simres.R new file mode 100644 index 000000000..fa2479032 --- /dev/null +++ b/tests/testthat/test-check_autocorrelation_simres.R @@ -0,0 +1,51 @@ +test_that("check_autocorrelation works with simulated residuals", { + skip_if_not_installed("DHARMa") + skip_if_not_installed("glmmTMB") + skip_if_not(getRversion() >= "4.0.0") + + data(Salamanders, package = "glmmTMB") + + # Test with a simple Poisson GLM + m <- glm(count ~ spp + mined, family = poisson, data = Salamanders) + + # Simulate residuals + set.seed(123) + simres <- simulate_residuals(m) + + # Check autocorrelation + set.seed(123) + expect_warning({ + out <- check_autocorrelation(simres) + }) + + # Should return a p-value + expect_type(out, "double") + expect_s3_class(out, "check_autocorrelation") + + # P-value should be between 0 and 1 + expect_true(out >= 0 && out <= 1) +}) + + +test_that("check_autocorrelation.DHARMa works", { + skip_if_not_installed("DHARMa") + + # Test that the DHARMa method works + data(mtcars) + m <- lm(mpg ~ wt + cyl + gear + disp, data = mtcars) + + set.seed(123) + simres <- DHARMa::simulateResiduals(m, plot = FALSE) + + expect_warning(check_autocorrelation(simres), regex = "Data are assumed") + set.seed(123) + expect_silent({ + out <- check_autocorrelation(simres, time = seq_along(simres$scaledResiduals)) + }) + + # Should return a p-value + expect_type(out, "double") + expect_s3_class(out, "check_autocorrelation") + + expect_equal(as.vector(out), 0.4163168, tolerance = 1e-3, ignore_attr = TRUE) +}) From 455239bcc9e80fad724e5fed766455ee7c703d3e Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 8 Oct 2025 14:35:48 +0200 Subject: [PATCH 2/4] rd, namespace --- NAMESPACE | 2 ++ man/check_autocorrelation.Rd | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 2920eeb3d..e24788242 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -28,7 +28,9 @@ S3method(as.data.frame,r2_nakagawa) S3method(as.double,check_outliers) S3method(as.double,item_omega) S3method(as.double,performance_roc) +S3method(check_autocorrelation,DHARMa) S3method(check_autocorrelation,default) +S3method(check_autocorrelation,performance_simres) S3method(check_collinearity,BFBayesFactor) S3method(check_collinearity,MixMod) S3method(check_collinearity,afex_aov) diff --git a/man/check_autocorrelation.Rd b/man/check_autocorrelation.Rd index ce1cba6e4..d977bb3cf 100644 --- a/man/check_autocorrelation.Rd +++ b/man/check_autocorrelation.Rd @@ -3,18 +3,25 @@ \name{check_autocorrelation} \alias{check_autocorrelation} \alias{check_autocorrelation.default} +\alias{check_autocorrelation.performance_simres} \title{Check model for independence of residuals.} \usage{ check_autocorrelation(x, ...) \method{check_autocorrelation}{default}(x, nsim = 1000, ...) + +\method{check_autocorrelation}{performance_simres}(x, time = NULL, ...) } \arguments{ -\item{x}{A model object.} +\item{x}{A model object, or an object returned by \code{simulate_residuals()}.} -\item{...}{Currently not used.} +\item{...}{Currently not used for models. For simulated residuals, arguments are +passed to \code{DHARMa::testTemporalAutocorrelation()}.} \item{nsim}{Number of simulations for the Durbin-Watson-Test.} + +\item{time}{A vector with time values to specify the temporal order of the data. +Only used if \code{x} is an object returned by \code{simulate_residuals()} or by \code{DHARMa}.} } \value{ Invisibly returns the p-value of the test statistics. A p-value < 0.05 From 9aaadd9b144ce95d322b1b67e34e12673468c430 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 8 Oct 2025 14:39:19 +0200 Subject: [PATCH 3/4] test --- tests/testthat/test-check_autocorrelation_simres.R | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/testthat/test-check_autocorrelation_simres.R b/tests/testthat/test-check_autocorrelation_simres.R index fa2479032..a3abd1c44 100644 --- a/tests/testthat/test-check_autocorrelation_simres.R +++ b/tests/testthat/test-check_autocorrelation_simres.R @@ -22,8 +22,7 @@ test_that("check_autocorrelation works with simulated residuals", { expect_type(out, "double") expect_s3_class(out, "check_autocorrelation") - # P-value should be between 0 and 1 - expect_true(out >= 0 && out <= 1) + expect_equal(as.vector(out), 0.2211415, tolerance = 1e-3, ignore_attr = TRUE) }) From 35a51321e275c9586a0fe3379fdb7d15abff631f Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 8 Oct 2025 14:40:08 +0200 Subject: [PATCH 4/4] test --- tests/testthat/test-check_autocorrelation_simres.R | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-check_autocorrelation_simres.R b/tests/testthat/test-check_autocorrelation_simres.R index a3abd1c44..7a49d69f1 100644 --- a/tests/testthat/test-check_autocorrelation_simres.R +++ b/tests/testthat/test-check_autocorrelation_simres.R @@ -14,9 +14,12 @@ test_that("check_autocorrelation works with simulated residuals", { # Check autocorrelation set.seed(123) - expect_warning({ - out <- check_autocorrelation(simres) - }) + expect_warning( + { + out <- check_autocorrelation(simres) + }, + regex = "Data are assumed" + ) # Should return a p-value expect_type(out, "double")