diff --git a/DESCRIPTION b/DESCRIPTION index 9391ecf34..864dad20b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: performance Title: Assessment of Regression Models Performance -Version: 0.10.8.11 +Version: 0.10.8.12 Authors@R: c(person(given = "Daniel", family = "Lüdecke", diff --git a/NEWS.md b/NEWS.md index 0cc49b785..d9696e082 100644 --- a/NEWS.md +++ b/NEWS.md @@ -26,6 +26,9 @@ * `check_outliers()` now properly accept the `percentage_central` argument when using the `"mcd"` method. +* Fixed edge cases in `check_collinearity()` and `check_outliers()` for models + with response variables of classes `Date`, `POSIXct`, `POSIXlt` or `difftime`. + # performance 0.10.8 ## Changes diff --git a/R/check_collinearity.R b/R/check_collinearity.R index 2add49126..2a5437688 100644 --- a/R/check_collinearity.R +++ b/R/check_collinearity.R @@ -404,7 +404,18 @@ check_collinearity.zerocount <- function(x, .check_collinearity <- function(x, component, ci = 0.95, verbose = TRUE) { - v <- insight::get_varcov(x, component = component, verbose = FALSE) + v <- .safe(insight::get_varcov(x, component = component, verbose = FALSE)) + + # sanity check + if (is.null(v)) { + if (isTRUE(verbose)) { + insight::format_alert( + sprintf("Could not extract the variance-covariance matrix for the %s component of the model.", component) + ) + } + return(NULL) + } + term_assign <- .term_assignments(x, component, verbose = verbose) # any assignment found? @@ -432,10 +443,8 @@ check_collinearity.zerocount <- function(x, if (insight::has_intercept(x)) { v <- v[-1, -1] term_assign <- term_assign[-1] - } else { - if (isTRUE(verbose)) { - insight::format_alert("Model has no intercept. VIFs may not be sensible.") - } + } else if (isTRUE(verbose)) { + insight::format_alert("Model has no intercept. VIFs may not be sensible.") } f <- insight::find_formula(x) diff --git a/R/check_outliers.R b/R/check_outliers.R index f3bf7f5a9..40ec737e8 100644 --- a/R/check_outliers.R +++ b/R/check_outliers.R @@ -23,6 +23,7 @@ #' 'Details'). If a numeric value is given, it will be used as the threshold #' for any of the method run. #' @param ID Optional, to report an ID column along with the row number. +#' @param verbose Toggle warnings. #' @param ... When `method = "ics"`, further arguments in `...` are passed #' down to [ICSOutlier::ics.outlier()]. When `method = "mahalanobis"`, #' they are passed down to [stats::mahalanobis()]. `percentage_central` can @@ -348,6 +349,7 @@ check_outliers.default <- function(x, method = c("cook", "pareto"), threshold = NULL, ID = NULL, + verbose = TRUE, ...) { # Check args if (all(method == "all")) { @@ -391,8 +393,18 @@ check_outliers.default <- function(x, # Get data my_data <- insight::get_data(x, verbose = FALSE) + # sanity check for date, POSIXt and difftime variables + if (any(vapply(my_data, inherits, FUN.VALUE = logical(1), what = c("Date", "POSIXt", "difftime"))) && verbose) { + insight::format_alert("Date variables are not supported for outliers detection. These will be ignored.") + } + # Remove non-numerics - my_data <- datawizard::data_select(my_data, select = is.numeric) + my_data <- datawizard::data_select(my_data, select = is.numeric, verbose = FALSE) + + # check if any data left + if (is.null(my_data) || ncol(my_data) == 0) { + insight::format_error("No numeric variables found. No data to check for outliers.") + } # Thresholds if (is.null(threshold)) { @@ -409,7 +421,7 @@ check_outliers.default <- function(x, ) } - if (!missing(ID)) { + if (!missing(ID) && verbose) { insight::format_warning(paste0("ID argument not supported for model objects of class `", class(x)[1], "`.")) } diff --git a/man/check_outliers.Rd b/man/check_outliers.Rd index 8dc0326bb..22b88228c 100644 --- a/man/check_outliers.Rd +++ b/man/check_outliers.Rd @@ -14,6 +14,7 @@ check_outliers(x, ...) method = c("cook", "pareto"), threshold = NULL, ID = NULL, + verbose = TRUE, ... ) @@ -41,6 +42,8 @@ considered as outlier. If \code{NULL}, default values will be used (see for any of the method run.} \item{ID}{Optional, to report an ID column along with the row number.} + +\item{verbose}{Toggle warnings.} } \value{ A logical vector of the detected outliers with a nice printing diff --git a/tests/testthat/test-check_collinearity.R b/tests/testthat/test-check_collinearity.R index 3d68b87ac..6864ebcaf 100644 --- a/tests/testthat/test-check_collinearity.R +++ b/tests/testthat/test-check_collinearity.R @@ -211,3 +211,9 @@ test_that("check_collinearity, hurdle/zi models w/o zi-formula", { ) expect_equal(out$VIF, c(1.05772, 1.05772, 1.06587, 1.06587), tolerance = 1e-4) }) + +test_that("check_collinearity, invalid data", { + dd <- data.frame(y = as.difftime(0:5, units = "days")) + m1 <- lm(y ~ 1, data = dd) + expect_message(expect_null(check_collinearity(m1)), "Could not extract") +}) diff --git a/tests/testthat/test-check_outliers.R b/tests/testthat/test-check_outliers.R index 259f3eac9..8840e26bf 100644 --- a/tests/testthat/test-check_outliers.R +++ b/tests/testthat/test-check_outliers.R @@ -329,3 +329,16 @@ test_that("cook multiple methods which", { c("setosa", "versicolor", "virginica") ) }) + + +test_that("check_outliers with invald data", { + dd <- data.frame(y = as.difftime(0:5, units = "days")) + m1 <- lm(y ~ 1, data = dd) + expect_error( + expect_message( + check_outliers(m1), + regex = "Date variables are not supported" + ), + regex = "No numeric variables found" + ) +})