From 92b0f15fad564ee345bba20cd3c62c583e1caf08 Mon Sep 17 00:00:00 2001 From: Florence Bockting Date: Tue, 21 Jul 2026 10:29:58 +0300 Subject: [PATCH 01/11] feat: add simplify argument to print.compare.loo --- R/loo_compare.R | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/R/loo_compare.R b/R/loo_compare.R index ce5bea4a..b922a473 100644 --- a/R/loo_compare.R +++ b/R/loo_compare.R @@ -91,6 +91,7 @@ #' #' comp <- loo_compare(loo1, loo2, loo3) #' print(comp, digits = 2) +#' print(comp, simplify = FALSE) # full table #' #' # can use a list of objects with custom names #' # the names will be used in the output @@ -170,7 +171,13 @@ loo_compare.default <- function(x, ...) { #' @param p_worse For the print method only, should we include the normal #' approximation based probability of each model having worse performance than #' the best model? The default is `TRUE`. -print.compare.loo <- function(x, ..., digits = 1, p_worse = TRUE) { +#' @param simplify For the print method only, should the output be simplified +#' to only include the model names, ELPD differences, and (when `p_worse = +#' TRUE`) diagnostic columns? The default is `TRUE`, matching the printed +#' output in loo 2.10. Set to `FALSE` to also print the available estimate +#' columns (pointwise ELPD, LOOIC/WAIC, and their standard errors). +print.compare.loo <- function(x, ..., digits = 1, p_worse = TRUE, + simplify = TRUE) { if (inherits(x, "old_compare.loo")) { return(unclass(x)) } @@ -181,19 +188,33 @@ print.compare.loo <- function(x, ..., digits = 1, p_worse = TRUE) { print(as.data.frame(x)) return(x) } - x2 <- cbind( - model = x$model, - .fr(x[, c("elpd_diff", "se_diff")], digits) + base_cols <- c("model", "elpd_diff", "se_diff") + diag_cols <- c("p_worse", "diag_diff", "diag_elpd") + show_diag <- p_worse && "p_worse" %in% colnames(x) + + estimate_cols <- setdiff(colnames(x), c(base_cols, diag_cols)) + estimate_cols <- estimate_cols[vapply(x[estimate_cols], is.numeric, logical(1))] + + cols <- c( + base_cols, + if (show_diag) diag_cols, + if (!simplify) estimate_cols ) - if (p_worse && "p_worse" %in% colnames(x)) { - x2 <- cbind( - x2, - p_worse = .fr(x[, "p_worse"], digits = 2), - diag_diff = x[, "diag_diff"], - diag_elpd = x[, "diag_elpd"] - ) + cols <- intersect(cols, colnames(x)) + + x2 <- x[, cols, drop = FALSE] + + fmt_cols <- setdiff(cols, c("model", "diag_diff", "diag_elpd")) + if (length(fmt_cols)) { + if ("p_worse" %in% fmt_cols) { + x2$p_worse <- .fr(x2$p_worse, digits = 2) + fmt_cols <- setdiff(fmt_cols, "p_worse") + } + if (length(fmt_cols)) { + x2[fmt_cols] <- .fr(x2[fmt_cols], digits) + } } - print(x2, quote = FALSE, row.names = FALSE) + print(as.data.frame(x2), quote = FALSE, row.names = FALSE) # show glossary for diagnostic flags has_diag <- any(nzchar(x[["diag_diff"]], keepNA = FALSE), na.rm = TRUE) || From ce0f1149b94b7a8ea436d477ca7bf031e3420356 Mon Sep 17 00:00:00 2001 From: Florence Bockting Date: Tue, 21 Jul 2026 10:30:26 +0300 Subject: [PATCH 02/11] docs: update docs incl. simplify argument --- man/loo_compare.Rd | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/man/loo_compare.Rd b/man/loo_compare.Rd index c54b9f86..0899339f 100644 --- a/man/loo_compare.Rd +++ b/man/loo_compare.Rd @@ -12,7 +12,7 @@ loo_compare(x, ...) \method{loo_compare}{default}(x, ...) -\method{print}{compare.loo}(x, ..., digits = 1, p_worse = TRUE) +\method{print}{compare.loo}(x, ..., digits = 1, p_worse = TRUE, simplify = TRUE) \method{print}{compare.loo_ss}(x, ..., digits = 1) } @@ -30,6 +30,11 @@ printing.} \item{p_worse}{For the print method only, should we include the normal approximation based probability of each model having worse performance than the best model? The default is \code{TRUE}.} + +\item{simplify}{For the print method only, should the output be simplified +to only include the model names, ELPD differences, and (when \code{p_worse = TRUE}) diagnostic columns? The default is \code{TRUE}, matching the printed +output in loo 2.10. Set to \code{FALSE} to also print the available estimate +columns (pointwise ELPD, LOOIC/WAIC, and their standard errors).} } \value{ A data frame with class \code{"compare.loo"} that has its own @@ -118,6 +123,7 @@ loo3 <- loo(LL + 2) # should be best model when compared comp <- loo_compare(loo1, loo2, loo3) print(comp, digits = 2) +print(comp, simplify = FALSE) # full table # can use a list of objects with custom names # the names will be used in the output From a57cf2bcd7191fb5d495d006b52da37fff547d2b Mon Sep 17 00:00:00 2001 From: Florence Bockting Date: Tue, 21 Jul 2026 10:30:49 +0300 Subject: [PATCH 03/11] tests: add test for simplify argument --- tests/testthat/_snaps/compare.md | 17 +++++++++++++++++ tests/testthat/test_compare.R | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/tests/testthat/_snaps/compare.md b/tests/testthat/_snaps/compare.md index 8abb5cf3..c94c2d17 100644 --- a/tests/testthat/_snaps/compare.md +++ b/tests/testthat/_snaps/compare.md @@ -62,6 +62,23 @@ model1 0.0 0.0 model2 -4.1 0.1 +--- + + Code + print(comp2, simplify = FALSE) + Output + model elpd_diff se_diff p_worse diag_diff diag_elpd elpd_waic se_elpd_waic + model1 0.0 0.0 NA -83.5 4.3 + model2 -4.1 0.1 1.00 N < 100 -87.6 4.3 + p_waic se_p_waic waic se_waic + 3.3 1.1 167.1 8.5 + 11.2 1.1 175.2 8.6 + Message + + Diagnostic flags present. + See ?`loo-glossary` (sections `diag_diff` and `diag_elpd`) + or https://mc-stan.org/loo/reference/loo-glossary.html. + # loo_compare returns expected result (3 models) WAoAAAACAAQEAgACAwAAAAMTAAAADAAAABAAAAADAAQACQAAAAZtb2RlbDEABAAJAAAABm1v diff --git a/tests/testthat/test_compare.R b/tests/testthat/test_compare.R index 4a00a10a..4f6a5f42 100644 --- a/tests/testthat/test_compare.R +++ b/tests/testthat/test_compare.R @@ -109,6 +109,11 @@ test_that("loo_compare returns expected results (2 models)", { expect_snapshot_value(comp2, style = "serialize") expect_snapshot(print(comp2)) expect_snapshot(print(comp2, p_worse = FALSE)) + expect_snapshot(print(comp2, simplify = FALSE)) + out_full <- paste( + capture.output(suppressMessages(print(comp2, simplify = FALSE))), + collapse = "\n" + ) # specifying objects via ... and via arg x gives equal results expect_equal(comp2, loo_compare(x = list(w1, w2))) @@ -118,6 +123,18 @@ test_that("loo_compare returns expected results (2 models)", { expect_equal(comp3$model, c("B", "A")) }) +test_that("print.compare.loo simplify=FALSE shows loo estimate columns", { + loo1 <- suppressWarnings(loo(LLarr)) + loo2 <- suppressWarnings(loo(LLarr2)) + comp <- loo_compare(loo1, loo2) + out_full <- paste( + capture.output(suppressMessages(print(comp, simplify = FALSE))), + collapse = "\n" + ) + expect_match(out_full, "elpd_loo\\s+se_elpd_loo") + expect_match(out_full, "p_loo\\s+se_p_loo\\s+looic\\s+se_looic") +}) + test_that("loo_compare returns expected result (3 models)", { w3 <- suppressWarnings(waic(LLarr3)) From 6a9cb10ec41f0f58e80d0ca7458d2c107a303fa4 Mon Sep 17 00:00:00 2001 From: Florence Bockting Date: Tue, 21 Jul 2026 10:31:05 +0300 Subject: [PATCH 04/11] chore: update NEWS.md --- NEWS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS.md b/NEWS.md index d998539c..66e39306 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,8 @@ # loo (development version) +* `print.compare.loo()` regains a `simplify` argument for showing the full + comparison table with `simplify = FALSE` by florence-bockting in #383. + # loo 2.10.0 * Updates to `loo_compare` output by @jgabry, @avehtari, @florence-bockting in #300: From ccd78e3e6aee91d9b424d853dfc4acd16c7f3c2b Mon Sep 17 00:00:00 2001 From: Florence Bockting Date: Tue, 21 Jul 2026 10:43:37 +0300 Subject: [PATCH 05/11] tests: update tests for better coverage --- tests/testthat/_snaps/compare.md | 9 +++++++++ tests/testthat/test_compare.R | 5 +---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/testthat/_snaps/compare.md b/tests/testthat/_snaps/compare.md index c94c2d17..b83ecab4 100644 --- a/tests/testthat/_snaps/compare.md +++ b/tests/testthat/_snaps/compare.md @@ -79,6 +79,15 @@ See ?`loo-glossary` (sections `diag_diff` and `diag_elpd`) or https://mc-stan.org/loo/reference/loo-glossary.html. +--- + + Code + print(comp2, simplify = FALSE, p_worse = FALSE) + Output + model elpd_diff se_diff elpd_waic se_elpd_waic p_waic se_p_waic waic se_waic + model1 0.0 0.0 -83.5 4.3 3.3 1.1 167.1 8.5 + model2 -4.1 0.1 -87.6 4.3 11.2 1.1 175.2 8.6 + # loo_compare returns expected result (3 models) WAoAAAACAAQEAgACAwAAAAMTAAAADAAAABAAAAADAAQACQAAAAZtb2RlbDEABAAJAAAABm1v diff --git a/tests/testthat/test_compare.R b/tests/testthat/test_compare.R index 4f6a5f42..e269eadc 100644 --- a/tests/testthat/test_compare.R +++ b/tests/testthat/test_compare.R @@ -110,10 +110,7 @@ test_that("loo_compare returns expected results (2 models)", { expect_snapshot(print(comp2)) expect_snapshot(print(comp2, p_worse = FALSE)) expect_snapshot(print(comp2, simplify = FALSE)) - out_full <- paste( - capture.output(suppressMessages(print(comp2, simplify = FALSE))), - collapse = "\n" - ) + expect_snapshot(print(comp2, simplify = FALSE, p_worse = FALSE)) # specifying objects via ... and via arg x gives equal results expect_equal(comp2, loo_compare(x = list(w1, w2))) From 4d691927457d409dd175dd5d5e9ef68d8d90b0cd Mon Sep 17 00:00:00 2001 From: Florence Bockting Date: Tue, 21 Jul 2026 11:01:15 +0300 Subject: [PATCH 06/11] tests: add test equivalent to issue text --- tests/testthat/_snaps/compare.md | 19 +++++++++++++++++++ tests/testthat/test_compare.R | 11 ++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/tests/testthat/_snaps/compare.md b/tests/testthat/_snaps/compare.md index b83ecab4..c7b40534 100644 --- a/tests/testthat/_snaps/compare.md +++ b/tests/testthat/_snaps/compare.md @@ -121,6 +121,25 @@ See ?`loo-glossary` (sections `diag_diff` and `diag_elpd`) or https://mc-stan.org/loo/reference/loo-glossary.html. +# loo_compare with simplify=FALSE returns expected result + + Code + print(comp, simplify = FALSE) + Output + model elpd_diff se_diff p_worse diag_diff diag_elpd elpd_loo se_elpd_loo + model3 0.0 0.0 NA -19.6 4.3 + model2 -32.0 0.0 1.00 N < 100 -51.6 4.3 + model1 -64.0 0.0 1.00 N < 100 -83.6 4.3 + p_loo se_p_loo looic se_looic + 3.3 1.2 39.2 8.6 + 3.3 1.2 103.2 8.6 + 3.3 1.2 167.2 8.6 + Message + + Diagnostic flags present. + See ?`loo-glossary` (sections `diag_diff` and `diag_elpd`) + or https://mc-stan.org/loo/reference/loo-glossary.html. + # compare returns expected result (3 models) WAoAAAACAAQFAAACAwAAAAMOAAAAGAAAAAAAAAAAwBA6U1+cRe7AMA3KkbYEGAAAAAAAAAAA diff --git a/tests/testthat/test_compare.R b/tests/testthat/test_compare.R index e269eadc..3d10acfc 100644 --- a/tests/testthat/test_compare.R +++ b/tests/testthat/test_compare.R @@ -151,6 +151,15 @@ test_that("loo_compare returns expected result (3 models)", { expect_equal(comp1, loo_compare(x = list(w1, w2, w3)), ignore_attr = TRUE) }) +test_that("loo_compare with simplify=FALSE returns expected result", { + LL <- example_loglik_array() + loo1 <- loo(LL) + loo2 <- loo(LL + 1) + loo3 <- loo(LL + 2) + comp <- loo_compare(loo1, loo2, loo3) + expect_snapshot(print(comp, simplify = FALSE)) +}) + # Tests for deprecated compare() ------------------------------------------ test_that("compare throws deprecation warnings", { @@ -227,4 +236,4 @@ test_that("compare throws appropriate errors", { suppressWarnings(loo::compare(x = list(w1, w2, w3))), "same number of data points" ) -}) +}) \ No newline at end of file From db219456175799056988ed917c2ca5725418e1d5 Mon Sep 17 00:00:00 2001 From: Florence Bockting <48919471+florence-bockting@users.noreply.github.com> Date: Wed, 22 Jul 2026 12:07:52 +0300 Subject: [PATCH 07/11] Update NEWS.md Co-authored-by: Jonah Gabry --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 66e39306..dfe2897c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,7 @@ # loo (development version) * `print.compare.loo()` regains a `simplify` argument for showing the full - comparison table with `simplify = FALSE` by florence-bockting in #383. + comparison table with `simplify = FALSE` by @florence-bockting in #383. # loo 2.10.0 From a866616d4298b64f4b539c6509ddd2e9a11a9bdb Mon Sep 17 00:00:00 2001 From: Florence Bockting Date: Wed, 22 Jul 2026 12:41:12 +0300 Subject: [PATCH 08/11] fix: comment explaining as.data.frame usage --- R/loo_compare.R | 2 ++ 1 file changed, 2 insertions(+) diff --git a/R/loo_compare.R b/R/loo_compare.R index b922a473..66620368 100644 --- a/R/loo_compare.R +++ b/R/loo_compare.R @@ -214,6 +214,8 @@ print.compare.loo <- function(x, ..., digits = 1, p_worse = TRUE, x2[fmt_cols] <- .fr(x2[fmt_cols], digits) } } + # Use `as.data.frame(x2)` here to drop "compare.loo" + # so print() uses print.data.frame. print(as.data.frame(x2), quote = FALSE, row.names = FALSE) # show glossary for diagnostic flags From a70c4a30769df68a60998eef2a5ba6ff72447008 Mon Sep 17 00:00:00 2001 From: Florence Bockting Date: Wed, 22 Jul 2026 12:41:37 +0300 Subject: [PATCH 09/11] tests: remove redundant test and add line at end of file --- tests/testthat/test_compare.R | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/tests/testthat/test_compare.R b/tests/testthat/test_compare.R index 3d10acfc..e672ef07 100644 --- a/tests/testthat/test_compare.R +++ b/tests/testthat/test_compare.R @@ -120,19 +120,6 @@ test_that("loo_compare returns expected results (2 models)", { expect_equal(comp3$model, c("B", "A")) }) -test_that("print.compare.loo simplify=FALSE shows loo estimate columns", { - loo1 <- suppressWarnings(loo(LLarr)) - loo2 <- suppressWarnings(loo(LLarr2)) - comp <- loo_compare(loo1, loo2) - out_full <- paste( - capture.output(suppressMessages(print(comp, simplify = FALSE))), - collapse = "\n" - ) - expect_match(out_full, "elpd_loo\\s+se_elpd_loo") - expect_match(out_full, "p_loo\\s+se_p_loo\\s+looic\\s+se_looic") -}) - - test_that("loo_compare returns expected result (3 models)", { w3 <- suppressWarnings(waic(LLarr3)) comp1 <- loo_compare(w1, w2, w3) @@ -236,4 +223,4 @@ test_that("compare throws appropriate errors", { suppressWarnings(loo::compare(x = list(w1, w2, w3))), "same number of data points" ) -}) \ No newline at end of file +}) From 5b8236e4110347d5b15906bb0aadd79a6b4d377c Mon Sep 17 00:00:00 2001 From: jgabry Date: Wed, 22 Jul 2026 08:48:50 -0600 Subject: [PATCH 10/11] tiny doc edit --- R/loo_compare.R | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/R/loo_compare.R b/R/loo_compare.R index 66620368..4e7146b6 100644 --- a/R/loo_compare.R +++ b/R/loo_compare.R @@ -171,11 +171,11 @@ loo_compare.default <- function(x, ...) { #' @param p_worse For the print method only, should we include the normal #' approximation based probability of each model having worse performance than #' the best model? The default is `TRUE`. -#' @param simplify For the print method only, should the output be simplified -#' to only include the model names, ELPD differences, and (when `p_worse = -#' TRUE`) diagnostic columns? The default is `TRUE`, matching the printed -#' output in loo 2.10. Set to `FALSE` to also print the available estimate -#' columns (pointwise ELPD, LOOIC/WAIC, and their standard errors). +#' @param simplify For the print method only, should the output be simplified to +#' only include the model names, ELPD differences, and (when `p_worse = TRUE`) +#' diagnostic columns? The default is `TRUE`. Set to `FALSE` to also print the +#' available estimate columns (pointwise ELPD, LOOIC/WAIC, and their standard +#' errors). print.compare.loo <- function(x, ..., digits = 1, p_worse = TRUE, simplify = TRUE) { if (inherits(x, "old_compare.loo")) { From 4eafadd901140633c563a7197896230441c5927d Mon Sep 17 00:00:00 2001 From: jgabry Date: Wed, 22 Jul 2026 08:48:53 -0600 Subject: [PATCH 11/11] Update loo_compare.Rd --- man/loo_compare.Rd | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/man/loo_compare.Rd b/man/loo_compare.Rd index 0899339f..11dae77d 100644 --- a/man/loo_compare.Rd +++ b/man/loo_compare.Rd @@ -31,10 +31,11 @@ printing.} approximation based probability of each model having worse performance than the best model? The default is \code{TRUE}.} -\item{simplify}{For the print method only, should the output be simplified -to only include the model names, ELPD differences, and (when \code{p_worse = TRUE}) diagnostic columns? The default is \code{TRUE}, matching the printed -output in loo 2.10. Set to \code{FALSE} to also print the available estimate -columns (pointwise ELPD, LOOIC/WAIC, and their standard errors).} +\item{simplify}{For the print method only, should the output be simplified to +only include the model names, ELPD differences, and (when \code{p_worse = TRUE}) +diagnostic columns? The default is \code{TRUE}. Set to \code{FALSE} to also print the +available estimate columns (pointwise ELPD, LOOIC/WAIC, and their standard +errors).} } \value{ A data frame with class \code{"compare.loo"} that has its own