diff --git a/NEWS.md b/NEWS.md index d3f2f1dae..66d3c7e43 100644 --- a/NEWS.md +++ b/NEWS.md @@ -9,6 +9,10 @@ * `check_collinearity()` now properly warns when the `vcov` matrix is rank deficient (#922). +* `r2()` (and hence `model_performance()`) no longer errors for `glmmTMB` + negative-binomial models (`nbinom1`/`nbinom2`) without random effects, and now + returns McFadden's R2 for them. + # performance 0.17.1 ## Changes diff --git a/R/r2.R b/R/r2.R index a6e077cb4..20852aca3 100644 --- a/R/r2.R +++ b/R/r2.R @@ -544,6 +544,11 @@ r2.glmmTMB <- function(model, ci = NULL, tolerance = 1e-5, verbose = TRUE, ...) names(out$R2_Nagelkerke) <- "Nagelkerke's R2" attr(out, "model_type") <- "Generalized Linear" class(out) <- c("r2_pseudo", class(out)) + } else if (info$is_negbin && !info$is_zero_inflated) { + # negative-binomial regression uses McFadden's R2. Nagelkerke's is unstable + # here (the null-model refit finds a different dispersion, which can yield + # nonsensical negative values), so mirror the beta-binomial branch above. + out <- r2_mcfadden(model) } else if (info$is_zero_inflated) { # zero-inflated models use the default method out <- r2_zeroinflated(model) diff --git a/tests/testthat/test-r2_mcfadden.R b/tests/testthat/test-r2_mcfadden.R index 7456127a8..586553945 100644 --- a/tests/testthat/test-r2_mcfadden.R +++ b/tests/testthat/test-r2_mcfadden.R @@ -69,3 +69,21 @@ withr::with_environment( }) } ) + +test_that("r2, glmmTMB negative-binomial without random effects", { + skip_if_not_installed("glmmTMB") + set.seed(101) + dd <- data.frame(x = rnorm(200)) + dd$y <- rnbinom(200, mu = exp(0.5 + 1 * dd$x), size = 2) + + # nbinom2 previously errored ("does not support models of class `glmmTMB` + # without random effects and from nbinom2-family ..."); now returns McFadden's. + m2 <- glmmTMB::glmmTMB(y ~ 1 + x, data = dd, family = glmmTMB::nbinom2()) + out <- r2(m2) + expect_equal(out$R2, r2_mcfadden(m2)$R2, tolerance = 1e-4, ignore_attr = TRUE) + expect_equal(out$R2, 0.1521543, tolerance = 1e-4, ignore_attr = TRUE) + + # nbinom1 is handled by the same branch. + m1 <- glmmTMB::glmmTMB(y ~ 1 + x, data = dd, family = glmmTMB::nbinom1()) + expect_equal(r2(m1)$R2, 0.1406573, tolerance = 1e-4, ignore_attr = TRUE) +})