From fc1ff25d761fd8e6e44312a96466def9a8f2b44c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 31 Aug 2025 05:16:02 +0000 Subject: [PATCH 1/2] Initial plan From fe1a3fcd889211116c2b53c3801f015f63b7a080 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 31 Aug 2025 05:38:45 +0000 Subject: [PATCH 2/2] Fix Kruskal test reporting failure with degenerate cases Co-authored-by: rempsyc <13123390+rempsyc@users.noreply.github.com> --- DESCRIPTION | 2 +- NEWS.md | 1 + R/report_htest_kruskal.R | 46 ++++++++++++++++--- .../_snaps/windows/report.lmer.new.md | 45 ++++++++++++++++++ tests/testthat/test-report.htest-kruskal.R | 20 ++++++++ 5 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 tests/testthat/_snaps/windows/report.lmer.new.md diff --git a/DESCRIPTION b/DESCRIPTION index b634d97b1..c9317338f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: report Type: Package Title: Automated Reporting of Results and Statistical Models -Version: 0.6.1.2 +Version: 0.6.1.3 Authors@R: c(person(given = "Dominique", family = "Makowski", diff --git a/NEWS.md b/NEWS.md index 2becfea3c..270940fb0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,7 @@ Bug fixes +* `report()`: fix failure when reporting Kruskal-Wallis tests with degenerate cases (one observation per group) (#454) * Fixed issue with missing effect size for the Intercept term in type 3 anova tables (#451) # report 0.6.1 diff --git a/R/report_htest_kruskal.R b/R/report_htest_kruskal.R index 05681e53c..67b8f56a4 100644 --- a/R/report_htest_kruskal.R +++ b/R/report_htest_kruskal.R @@ -10,7 +10,29 @@ .report_effectsize_kruskal <- function(x, table, dot_args, rules = "funder2019") { args <- c(list(x), dot_args) - table <- do.call(effectsize::effectsize, args) + + # Try to calculate effect size with confidence intervals + table <- tryCatch( + { + do.call(effectsize::effectsize, args) + }, + error = function(e) { + # If CI calculation fails (e.g., degenerate cases), fallback to no CI + if (grepl("confidence intervals", e$message, ignore.case = TRUE) || + grepl("differing number of rows", e$message)) { + args_no_ci <- c(list(x), dot_args, list(ci = NULL)) + do.call(effectsize::effectsize, args_no_ci) + } else if (grepl("Unable to retrieve data", e$message)) { + # Data retrieval failed - this happens with certain htest object forms + # For now, we'll let this error propagate as the user should use the formula interface + # or provide data manually as suggested in the main report.htest function + stop(e) + } else { + stop(e) + } + } + ) + ci <- attributes(table)$ci estimate <- names(table)[1] @@ -22,13 +44,23 @@ rules <- .text_effectsize(attr(attr(interpretation, "rules"), "rule_name")) main <- paste0("Epsilon squared (rank) = ", insight::format_value(table$rank_epsilon_squared)) - statistics <- paste0( - main, - ", ", - insight::format_ci(table$CI_low, table$CI_high, ci) - ) - table <- table[names(table)[-2]] + # Handle cases where CI calculation failed and CI columns are missing + if (all(c("CI_low", "CI_high") %in% names(table))) { + statistics <- paste0( + main, + ", ", + insight::format_ci(table$CI_low, table$CI_high, ci) + ) + } else { + # No CI available - report only the effect size + statistics <- main + } + + # Remove CI_lower column if present (original code logic) + if (ncol(table) > 1) { + table <- table[names(table)[-2]] + } list( table = table, statistics = statistics, interpretation = interpretation, diff --git a/tests/testthat/_snaps/windows/report.lmer.new.md b/tests/testthat/_snaps/windows/report.lmer.new.md new file mode 100644 index 000000000..564febbeb --- /dev/null +++ b/tests/testthat/_snaps/windows/report.lmer.new.md @@ -0,0 +1,45 @@ +# report-lmer + + Code + report(m1) + Output + We fitted a linear mixed model (estimated using REML and nloptwrap optimizer) + to predict Reaction with Days (formula: Reaction ~ Days). The model included + Days as random effects (formula: ~1 + Days | Subject). The model's total + explanatory power is substantial (conditional R2 = 0.80) and the part related + to the fixed effects alone (marginal R2) is of 0.28. The model's intercept, + corresponding to Days = 0, is at 251.41 (95% CI [237.94, 264.87], t(174) = + 36.84, p < .001). Within this model: + + - The effect of Days is statistically significant and positive (beta = 10.47, + 95% CI [7.42, 13.52], t(174) = 6.77, p < .001; Std. beta = 0.54, 95% CI [0.38, + 0.69]) + + Standardized parameters were obtained by fitting the model on a standardized + version of the dataset. 95% Confidence Intervals (CIs) and p-values were + computed using a Wald t-distribution approximation. + +--- + + Code + report(m2) + Message + boundary (singular) fit: see help('isSingular') + boundary (singular) fit: see help('isSingular') + Output + We fitted a linear mixed model (estimated using REML and nloptwrap optimizer) + to predict Reaction with Days (formula: Reaction ~ Days). The model included + mysubgrp as random effects (formula: list(~1 | mysubgrp:mygrp, ~1 | mygrp, ~1 | + Subject)). The model's total explanatory power is substantial (conditional R2 = + 0.71) and the part related to the fixed effects alone (marginal R2) is of 0.28. + The model's intercept, corresponding to Days = 0, is at 252.09 (95% CI [232.50, + 271.69], t(174) = 25.39, p < .001). Within this model: + + - The effect of Days is statistically significant and positive (beta = 10.35, + 95% CI [8.78, 11.93], t(174) = 12.95, p < .001; Std. beta = 0.53, 95% CI [0.45, + 0.61]) + + Standardized parameters were obtained by fitting the model on a standardized + version of the dataset. 95% Confidence Intervals (CIs) and p-values were + computed using a Wald t-distribution approximation. + diff --git a/tests/testthat/test-report.htest-kruskal.R b/tests/testthat/test-report.htest-kruskal.R index 4d518adff..b9580ddbd 100644 --- a/tests/testthat/test-report.htest-kruskal.R +++ b/tests/testthat/test-report.htest-kruskal.R @@ -7,3 +7,23 @@ test_that("report.htest-kruskal report", { report(x, verbose = FALSE) ) }) + +test_that("report.htest-kruskal degenerate case (one observation per group)", { + # Test case from issue #454: one observation per group causes CI calculation to fail + n <- 10 + set.seed(123) + df <- data.frame(a = as.factor(1:n), b = rnorm(n)) + # Use the formula interface to allow effectsize to retrieve data + test <- kruskal.test(b ~ a, data = df) + + # Should not fail and should complete quickly - provide data manually + expect_no_error({ + result <- report(test, data = df, verbose = FALSE) + }) + + # Result should contain effect size but no CI due to degenerate case + result <- report(test, data = df, verbose = FALSE) + result_text <- as.character(result) + expect_true(grepl("Epsilon squared \\(rank\\) = 1\\.00", result_text)) + expect_false(grepl("95% CI", result_text)) # No CI should be present +})