Skip to content

Commit 88f63b5

Browse files
authored
Merge pull request #383 from stan-dev/feat/add-simplify
Add `simplify` argument to `print.compare.loo`
2 parents 1a9afd3 + 4eafadd commit 88f63b5

5 files changed

Lines changed: 102 additions & 14 deletions

File tree

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# loo (development version)
22

3+
* `print.compare.loo()` regains a `simplify` argument for showing the full
4+
comparison table with `simplify = FALSE` by @florence-bockting in #383.
5+
36
# loo 2.10.0
47

58
* Updates to `loo_compare` output by @jgabry, @avehtari, @florence-bockting in #300:

R/loo_compare.R

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
#'
9292
#' comp <- loo_compare(loo1, loo2, loo3)
9393
#' print(comp, digits = 2)
94+
#' print(comp, simplify = FALSE) # full table
9495
#'
9596
#' # can use a list of objects with custom names
9697
#' # the names will be used in the output
@@ -170,7 +171,13 @@ loo_compare.default <- function(x, ...) {
170171
#' @param p_worse For the print method only, should we include the normal
171172
#' approximation based probability of each model having worse performance than
172173
#' the best model? The default is `TRUE`.
173-
print.compare.loo <- function(x, ..., digits = 1, p_worse = TRUE) {
174+
#' @param simplify For the print method only, should the output be simplified to
175+
#' only include the model names, ELPD differences, and (when `p_worse = TRUE`)
176+
#' diagnostic columns? The default is `TRUE`. Set to `FALSE` to also print the
177+
#' available estimate columns (pointwise ELPD, LOOIC/WAIC, and their standard
178+
#' errors).
179+
print.compare.loo <- function(x, ..., digits = 1, p_worse = TRUE,
180+
simplify = TRUE) {
174181
if (inherits(x, "old_compare.loo")) {
175182
return(unclass(x))
176183
}
@@ -181,19 +188,35 @@ print.compare.loo <- function(x, ..., digits = 1, p_worse = TRUE) {
181188
print(as.data.frame(x))
182189
return(x)
183190
}
184-
x2 <- cbind(
185-
model = x$model,
186-
.fr(x[, c("elpd_diff", "se_diff")], digits)
191+
base_cols <- c("model", "elpd_diff", "se_diff")
192+
diag_cols <- c("p_worse", "diag_diff", "diag_elpd")
193+
show_diag <- p_worse && "p_worse" %in% colnames(x)
194+
195+
estimate_cols <- setdiff(colnames(x), c(base_cols, diag_cols))
196+
estimate_cols <- estimate_cols[vapply(x[estimate_cols], is.numeric, logical(1))]
197+
198+
cols <- c(
199+
base_cols,
200+
if (show_diag) diag_cols,
201+
if (!simplify) estimate_cols
187202
)
188-
if (p_worse && "p_worse" %in% colnames(x)) {
189-
x2 <- cbind(
190-
x2,
191-
p_worse = .fr(x[, "p_worse"], digits = 2),
192-
diag_diff = x[, "diag_diff"],
193-
diag_elpd = x[, "diag_elpd"]
194-
)
203+
cols <- intersect(cols, colnames(x))
204+
205+
x2 <- x[, cols, drop = FALSE]
206+
207+
fmt_cols <- setdiff(cols, c("model", "diag_diff", "diag_elpd"))
208+
if (length(fmt_cols)) {
209+
if ("p_worse" %in% fmt_cols) {
210+
x2$p_worse <- .fr(x2$p_worse, digits = 2)
211+
fmt_cols <- setdiff(fmt_cols, "p_worse")
212+
}
213+
if (length(fmt_cols)) {
214+
x2[fmt_cols] <- .fr(x2[fmt_cols], digits)
215+
}
195216
}
196-
print(x2, quote = FALSE, row.names = FALSE)
217+
# Use `as.data.frame(x2)` here to drop "compare.loo"
218+
# so print() uses print.data.frame.
219+
print(as.data.frame(x2), quote = FALSE, row.names = FALSE)
197220

198221
# show glossary for diagnostic flags
199222
has_diag <- any(nzchar(x[["diag_diff"]], keepNA = FALSE), na.rm = TRUE) ||

man/loo_compare.Rd

Lines changed: 8 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/_snaps/compare.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,32 @@
6262
model1 0.0 0.0
6363
model2 -4.1 0.1
6464

65+
---
66+
67+
Code
68+
print(comp2, simplify = FALSE)
69+
Output
70+
model elpd_diff se_diff p_worse diag_diff diag_elpd elpd_waic se_elpd_waic
71+
model1 0.0 0.0 NA -83.5 4.3
72+
model2 -4.1 0.1 1.00 N < 100 -87.6 4.3
73+
p_waic se_p_waic waic se_waic
74+
3.3 1.1 167.1 8.5
75+
11.2 1.1 175.2 8.6
76+
Message
77+
78+
Diagnostic flags present.
79+
See ?`loo-glossary` (sections `diag_diff` and `diag_elpd`)
80+
or https://mc-stan.org/loo/reference/loo-glossary.html.
81+
82+
---
83+
84+
Code
85+
print(comp2, simplify = FALSE, p_worse = FALSE)
86+
Output
87+
model elpd_diff se_diff elpd_waic se_elpd_waic p_waic se_p_waic waic se_waic
88+
model1 0.0 0.0 -83.5 4.3 3.3 1.1 167.1 8.5
89+
model2 -4.1 0.1 -87.6 4.3 11.2 1.1 175.2 8.6
90+
6591
# loo_compare returns expected result (3 models)
6692

6793
WAoAAAACAAQEAgACAwAAAAMTAAAADAAAABAAAAADAAQACQAAAAZtb2RlbDEABAAJAAAABm1v
@@ -95,6 +121,25 @@
95121
See ?`loo-glossary` (sections `diag_diff` and `diag_elpd`)
96122
or https://mc-stan.org/loo/reference/loo-glossary.html.
97123

124+
# loo_compare with simplify=FALSE returns expected result
125+
126+
Code
127+
print(comp, simplify = FALSE)
128+
Output
129+
model elpd_diff se_diff p_worse diag_diff diag_elpd elpd_loo se_elpd_loo
130+
model3 0.0 0.0 NA -19.6 4.3
131+
model2 -32.0 0.0 1.00 N < 100 -51.6 4.3
132+
model1 -64.0 0.0 1.00 N < 100 -83.6 4.3
133+
p_loo se_p_loo looic se_looic
134+
3.3 1.2 39.2 8.6
135+
3.3 1.2 103.2 8.6
136+
3.3 1.2 167.2 8.6
137+
Message
138+
139+
Diagnostic flags present.
140+
See ?`loo-glossary` (sections `diag_diff` and `diag_elpd`)
141+
or https://mc-stan.org/loo/reference/loo-glossary.html.
142+
98143
# compare returns expected result (3 models)
99144

100145
WAoAAAACAAQFAAACAwAAAAMOAAAAGAAAAAAAAAAAwBA6U1+cRe7AMA3KkbYEGAAAAAAAAAAA

tests/testthat/test_compare.R

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ test_that("loo_compare returns expected results (2 models)", {
109109
expect_snapshot_value(comp2, style = "serialize")
110110
expect_snapshot(print(comp2))
111111
expect_snapshot(print(comp2, p_worse = FALSE))
112+
expect_snapshot(print(comp2, simplify = FALSE))
113+
expect_snapshot(print(comp2, simplify = FALSE, p_worse = FALSE))
112114

113115
# specifying objects via ... and via arg x gives equal results
114116
expect_equal(comp2, loo_compare(x = list(w1, w2)))
@@ -118,7 +120,6 @@ test_that("loo_compare returns expected results (2 models)", {
118120
expect_equal(comp3$model, c("B", "A"))
119121
})
120122

121-
122123
test_that("loo_compare returns expected result (3 models)", {
123124
w3 <- suppressWarnings(waic(LLarr3))
124125
comp1 <- loo_compare(w1, w2, w3)
@@ -137,6 +138,15 @@ test_that("loo_compare returns expected result (3 models)", {
137138
expect_equal(comp1, loo_compare(x = list(w1, w2, w3)), ignore_attr = TRUE)
138139
})
139140

141+
test_that("loo_compare with simplify=FALSE returns expected result", {
142+
LL <- example_loglik_array()
143+
loo1 <- loo(LL)
144+
loo2 <- loo(LL + 1)
145+
loo3 <- loo(LL + 2)
146+
comp <- loo_compare(loo1, loo2, loo3)
147+
expect_snapshot(print(comp, simplify = FALSE))
148+
})
149+
140150
# Tests for deprecated compare() ------------------------------------------
141151

142152
test_that("compare throws deprecation warnings", {

0 commit comments

Comments
 (0)