Skip to content

Commit cdd951b

Browse files
Copilotstrengejacke
andcommitted
Implement check_autocorrelation for simulated residuals and use simulated residuals for Poisson mixed models
Co-authored-by: strengejacke <26301769+strengejacke@users.noreply.github.com>
1 parent cd524bc commit cdd951b

File tree

3 files changed

+45
-13
lines changed

3 files changed

+45
-13
lines changed

R/check_autocorrelation.R

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
#' @description Check model for independence of residuals, i.e. for autocorrelation
55
#' of error terms.
66
#'
7-
#' @param x A model object.
7+
#' @param x A model object, or an object returned by `simulate_residuals()`.
88
#' @param nsim Number of simulations for the Durbin-Watson-Test.
9-
#' @param ... Currently not used.
9+
#' @param ... Currently not used for models. For simulated residuals, arguments are
10+
#' passed to `DHARMa::testTemporalAutocorrelation()`, which can include `time` (a
11+
#' vector with time values) to specify the temporal order of the data.
1012
#'
1113
#' @return Invisibly returns the p-value of the test statistics. A p-value < 0.05
1214
#' indicates autocorrelated residuals.
@@ -18,6 +20,11 @@
1820
#' results for the estimates, or maybe a mixed model with error term for the
1921
#' cluster groups should be used.
2022
#'
23+
#' For simulated residuals (from `simulate_residuals()`), the function uses
24+
#' `DHARMa::testTemporalAutocorrelation()` to check for temporal autocorrelation.
25+
#' This requires the data to be ordered by time. If the data are not ordered by
26+
#' time, you can provide a `time` argument to specify the temporal order.
27+
#'
2128
#' @examples
2229
#' m <- lm(mpg ~ wt + cyl + gear + disp, data = mtcars)
2330
#' check_autocorrelation(m)
@@ -49,6 +56,27 @@ check_autocorrelation.default <- function(x, nsim = 1000, ...) {
4956
}
5057

5158

59+
#' @rdname check_autocorrelation
60+
#' @export
61+
check_autocorrelation.performance_simres <- function(x, ...) {
62+
insight::check_if_installed("DHARMa")
63+
64+
# Use DHARMa's temporal autocorrelation test
65+
# This requires the residuals to be ordered by time
66+
# DHARMa::testTemporalAutocorrelation expects a DHARMa object
67+
result <- DHARMa::testTemporalAutocorrelation(x, plot = FALSE, ...)
68+
69+
# Extract p-value from the result
70+
p.val <- result$p.value
71+
72+
class(p.val) <- c("check_autocorrelation", "see_check_autocorrelation", class(p.val))
73+
p.val
74+
}
75+
76+
#' @export
77+
check_autocorrelation.DHARMa <- check_autocorrelation.performance_simres
78+
79+
5280
# methods ------------------------------
5381

5482
#' @export

R/check_overdispersion.R

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@
4040
#' [GLMM FAQ](http://bbolker.github.io/mixedmodels-misc/glmmFAQ.html),
4141
#' section *How can I deal with overdispersion in GLMMs?*. Note that this
4242
#' function only returns an *approximate* estimate of an overdispersion
43-
#' parameter. Using this approach would be inaccurate for zero-inflated or
44-
#' negative binomial mixed models (fitted with `glmmTMB`), thus, in such cases,
45-
#' the overdispersion test is based on [`simulate_residuals()`] (which is identical
46-
#' to `check_overdispersion(simulate_residuals(model))`).
43+
#' parameter. For Poisson, zero-inflated, or negative binomial mixed models
44+
#' (fitted with `glmmTMB` or `lme4`), the overdispersion test is based on
45+
#' [`simulate_residuals()`] (which is identical to
46+
#' `check_overdispersion(simulate_residuals(model))`).
4747
#'
4848
#' @inheritSection check_zeroinflation Tests based on simulated residuals
4949
#'
@@ -242,7 +242,8 @@ check_overdispersion.merMod <- function(x, ...) {
242242
obj_name <- insight::safe_deparse_symbol(substitute(x))
243243

244244
# for certain distributions, simulated residuals are more accurate
245-
use_simulated <- info$family == "genpois" || info$is_zero_inflated || info$is_bernoulli || info$is_binomial || (!info$is_count && !info$is_binomial) || info$is_negbin # nolint
245+
# Note: now including Poisson models for mixed models (see #595, #643)
246+
use_simulated <- info$family == "genpois" || info$is_zero_inflated || info$is_bernoulli || info$is_binomial || (!info$is_count && !info$is_binomial) || info$is_negbin || info$is_poisson # nolint
246247

247248
if (use_simulated) {
248249
return(check_overdispersion(simulate_residuals(x, ...), object_name = obj_name, ...))

R/check_zeroinflation.R

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@
2525
#' negative binomial or zero-inflated models.
2626
#'
2727
#' In case of negative binomial models, models with zero-inflation component,
28-
#' or hurdle models, the results from `check_zeroinflation()` are based on
29-
#' [`simulate_residuals()`], i.e. `check_zeroinflation(simulate_residuals(model))`
30-
#' is internally called if necessary.
28+
#' hurdle models, or Poisson mixed models, the results from `check_zeroinflation()`
29+
#' are based on [`simulate_residuals()`], i.e.
30+
#' `check_zeroinflation(simulate_residuals(model))` is internally called if necessary.
3131
#'
3232
#' @section Tests based on simulated residuals:
3333
#' For certain models, resp. model from certain families, tests are based on
@@ -88,9 +88,12 @@ check_zeroinflation.default <- function(x, tolerance = 0.05, ...) {
8888
# model classes not supported in DHARMa
8989
not_supported <- c("fixest", "glmx")
9090

91-
# for models with zero-inflation component or negative binomial families,
92-
# we use simulate_residuals()
93-
if (!inherits(x, not_supported) && (model_info$is_zero_inflated || model_info$is_negbin || model_info$family == "genpois")) { # nolint
91+
# for models with zero-inflation component, negative binomial families,
92+
# or Poisson mixed models, we use simulate_residuals()
93+
# Note: now including Poisson mixed models (see #595, #643)
94+
use_simulated <- model_info$is_zero_inflated || model_info$is_negbin || model_info$family == "genpois" || (model_info$is_mixed && model_info$is_poisson) # nolint
95+
96+
if (!inherits(x, not_supported) && use_simulated) {
9497
if (missing(tolerance)) {
9598
tolerance <- 0.1
9699
}

0 commit comments

Comments
 (0)