diff --git a/R/helpers-ppc.R b/R/helpers-ppc.R index 618b9fca..948e5a23 100644 --- a/R/helpers-ppc.R +++ b/R/helpers-ppc.R @@ -58,15 +58,20 @@ validate_y <- function(y) { #' Validate predictions (`yrep` or `ypred`) #' #' Checks that `predictions` is a numeric matrix, doesn't have any NAs, and has -#' the correct number of columns. +#' the correct number of columns. If `predictions` is a `posterior::draws` +#' object it is first coerced to a matrix. #' -#' @param predictions The user's `yrep` or `ypred` object (SxN matrix). +#' @param predictions The user's `yrep` or `ypred` object (SxN matrix or a +#' `posterior::draws` object). #' @param `n_obs` The number of observations (columns) that `predictions` should #' have, if applicable. #' @return Either throws an error or returns a numeric matrix. #' @noRd validate_predictions <- function(predictions, n_obs = NULL) { - # sanity checks + if (posterior::is_draws(predictions)) { + predictions <- posterior::as_draws_matrix(predictions) + predictions <- unclass(predictions) + } stopifnot(is.matrix(predictions), is.numeric(predictions)) if (!is.null(n_obs)) { stopifnot(length(n_obs) == 1, n_obs == as.integer(n_obs)) diff --git a/man-roxygen/args-y-yrep.R b/man-roxygen/args-y-yrep.R index ccaf2e14..4cfb06dc 100644 --- a/man-roxygen/args-y-yrep.R +++ b/man-roxygen/args-y-yrep.R @@ -1,8 +1,9 @@ #' @param y A vector of observations. See **Details**. #' @param yrep An `S` by `N` matrix of draws from the posterior (or prior) -#' predictive distribution. The number of rows, `S`, is the size of the -#' posterior (or prior) sample used to generate `yrep`. The number of columns, -#' `N` is the number of predicted observations (`length(y)`). The columns of -#' `yrep` should be in the same order as the data points in `y` for the plots -#' to make sense. See the **Details** and **Plot Descriptions** sections for -#' additional advice specific to particular plots. +#' predictive distribution, or a [`posterior::draws`] object. The number of +#' rows, `S`, is the size of the posterior (or prior) sample used to generate +#' `yrep`. The number of columns, `N` is the number of predicted observations +#' (`length(y)`). The columns of `yrep` should be in the same order as the +#' data points in `y` for the plots to make sense. See the **Details** and +#' **Plot Descriptions** sections for additional advice specific to particular +#' plots. diff --git a/man-roxygen/args-ypred.R b/man-roxygen/args-ypred.R index 1c4d342b..84e0c567 100644 --- a/man-roxygen/args-ypred.R +++ b/man-roxygen/args-ypred.R @@ -1,4 +1,5 @@ #' @param ypred An `S` by `N` matrix of draws from the posterior (or prior) -#' predictive distribution. The number of rows, `S`, is the size of the -#' posterior (or prior) sample used to generate `ypred`. The number of -#' columns, `N`, is the number of predicted observations. +#' predictive distribution, or a [`posterior::draws`] object. The number of +#' rows, `S`, is the size of the posterior (or prior) sample used to generate +#' `ypred`. The number of columns, `N`, is the number of predicted +#' observations. diff --git a/man/PPC-censoring.Rd b/man/PPC-censoring.Rd index ddf011b4..68026b20 100644 --- a/man/PPC-censoring.Rd +++ b/man/PPC-censoring.Rd @@ -33,12 +33,13 @@ ppc_km_overlay_grouped( \item{y}{A vector of observations. See \strong{Details}.} \item{yrep}{An \code{S} by \code{N} matrix of draws from the posterior (or prior) -predictive distribution. The number of rows, \code{S}, is the size of the -posterior (or prior) sample used to generate \code{yrep}. The number of columns, -\code{N} is the number of predicted observations (\code{length(y)}). The columns of -\code{yrep} should be in the same order as the data points in \code{y} for the plots -to make sense. See the \strong{Details} and \strong{Plot Descriptions} sections for -additional advice specific to particular plots.} +predictive distribution, or a \code{\link[posterior:draws]{posterior::draws}} object. The number of +rows, \code{S}, is the size of the posterior (or prior) sample used to generate +\code{yrep}. The number of columns, \code{N} is the number of predicted observations +(\code{length(y)}). The columns of \code{yrep} should be in the same order as the +data points in \code{y} for the plots to make sense. See the \strong{Details} and +\strong{Plot Descriptions} sections for additional advice specific to particular +plots.} \item{...}{Currently only used internally.} diff --git a/man/PPC-discrete.Rd b/man/PPC-discrete.Rd index b672daa2..5f832a78 100644 --- a/man/PPC-discrete.Rd +++ b/man/PPC-discrete.Rd @@ -63,12 +63,13 @@ ppc_bars_data(y, yrep, group = NULL, prob = 0.9, freq = TRUE) \item{y}{A vector of observations. See \strong{Details}.} \item{yrep}{An \code{S} by \code{N} matrix of draws from the posterior (or prior) -predictive distribution. The number of rows, \code{S}, is the size of the -posterior (or prior) sample used to generate \code{yrep}. The number of columns, -\code{N} is the number of predicted observations (\code{length(y)}). The columns of -\code{yrep} should be in the same order as the data points in \code{y} for the plots -to make sense. See the \strong{Details} and \strong{Plot Descriptions} sections for -additional advice specific to particular plots.} +predictive distribution, or a \code{\link[posterior:draws]{posterior::draws}} object. The number of +rows, \code{S}, is the size of the posterior (or prior) sample used to generate +\code{yrep}. The number of columns, \code{N} is the number of predicted observations +(\code{length(y)}). The columns of \code{yrep} should be in the same order as the +data points in \code{y} for the plots to make sense. See the \strong{Details} and +\strong{Plot Descriptions} sections for additional advice specific to particular +plots.} \item{...}{Currently unused.} diff --git a/man/PPC-distributions.Rd b/man/PPC-distributions.Rd index b02cc26c..1aed7318 100644 --- a/man/PPC-distributions.Rd +++ b/man/PPC-distributions.Rd @@ -150,12 +150,13 @@ ppc_pit_ecdf_grouped( \item{y}{A vector of observations. See \strong{Details}.} \item{yrep}{An \code{S} by \code{N} matrix of draws from the posterior (or prior) -predictive distribution. The number of rows, \code{S}, is the size of the -posterior (or prior) sample used to generate \code{yrep}. The number of columns, -\code{N} is the number of predicted observations (\code{length(y)}). The columns of -\code{yrep} should be in the same order as the data points in \code{y} for the plots -to make sense. See the \strong{Details} and \strong{Plot Descriptions} sections for -additional advice specific to particular plots.} +predictive distribution, or a \code{\link[posterior:draws]{posterior::draws}} object. The number of +rows, \code{S}, is the size of the posterior (or prior) sample used to generate +\code{yrep}. The number of columns, \code{N} is the number of predicted observations +(\code{length(y)}). The columns of \code{yrep} should be in the same order as the +data points in \code{y} for the plots to make sense. See the \strong{Details} and +\strong{Plot Descriptions} sections for additional advice specific to particular +plots.} \item{group}{A grouping variable of the same length as \code{y}. Will be coerced to \link[base:factor]{factor} if not already a factor. diff --git a/man/PPC-errors.Rd b/man/PPC-errors.Rd index e23b29e9..f3931c26 100644 --- a/man/PPC-errors.Rd +++ b/man/PPC-errors.Rd @@ -85,12 +85,13 @@ ppc_error_data(y, yrep, group = NULL) \item{y}{A vector of observations. See \strong{Details}.} \item{yrep}{An \code{S} by \code{N} matrix of draws from the posterior (or prior) -predictive distribution. The number of rows, \code{S}, is the size of the -posterior (or prior) sample used to generate \code{yrep}. The number of columns, -\code{N} is the number of predicted observations (\code{length(y)}). The columns of -\code{yrep} should be in the same order as the data points in \code{y} for the plots -to make sense. See the \strong{Details} and \strong{Plot Descriptions} sections for -additional advice specific to particular plots.} +predictive distribution, or a \code{\link[posterior:draws]{posterior::draws}} object. The number of +rows, \code{S}, is the size of the posterior (or prior) sample used to generate +\code{yrep}. The number of columns, \code{N} is the number of predicted observations +(\code{length(y)}). The columns of \code{yrep} should be in the same order as the +data points in \code{y} for the plots to make sense. See the \strong{Details} and +\strong{Plot Descriptions} sections for additional advice specific to particular +plots.} \item{...}{Currently unused.} diff --git a/man/PPC-intervals.Rd b/man/PPC-intervals.Rd index 6ad715e0..5b3bea32 100644 --- a/man/PPC-intervals.Rd +++ b/man/PPC-intervals.Rd @@ -88,12 +88,13 @@ ppc_ribbon_data( \item{y}{A vector of observations. See \strong{Details}.} \item{yrep}{An \code{S} by \code{N} matrix of draws from the posterior (or prior) -predictive distribution. The number of rows, \code{S}, is the size of the -posterior (or prior) sample used to generate \code{yrep}. The number of columns, -\code{N} is the number of predicted observations (\code{length(y)}). The columns of -\code{yrep} should be in the same order as the data points in \code{y} for the plots -to make sense. See the \strong{Details} and \strong{Plot Descriptions} sections for -additional advice specific to particular plots.} +predictive distribution, or a \code{\link[posterior:draws]{posterior::draws}} object. The number of +rows, \code{S}, is the size of the posterior (or prior) sample used to generate +\code{yrep}. The number of columns, \code{N} is the number of predicted observations +(\code{length(y)}). The columns of \code{yrep} should be in the same order as the +data points in \code{y} for the plots to make sense. See the \strong{Details} and +\strong{Plot Descriptions} sections for additional advice specific to particular +plots.} \item{x}{A numeric vector to use as the x-axis variable. For example, \code{x} could be a predictor variable from a diff --git a/man/PPC-loo.Rd b/man/PPC-loo.Rd index 7e9ebe02..6c57dc5c 100644 --- a/man/PPC-loo.Rd +++ b/man/PPC-loo.Rd @@ -112,12 +112,13 @@ ppc_loo_ribbon( \item{y}{A vector of observations. See \strong{Details}.} \item{yrep}{An \code{S} by \code{N} matrix of draws from the posterior (or prior) -predictive distribution. The number of rows, \code{S}, is the size of the -posterior (or prior) sample used to generate \code{yrep}. The number of columns, -\code{N} is the number of predicted observations (\code{length(y)}). The columns of -\code{yrep} should be in the same order as the data points in \code{y} for the plots -to make sense. See the \strong{Details} and \strong{Plot Descriptions} sections for -additional advice specific to particular plots.} +predictive distribution, or a \code{\link[posterior:draws]{posterior::draws}} object. The number of +rows, \code{S}, is the size of the posterior (or prior) sample used to generate +\code{yrep}. The number of columns, \code{N} is the number of predicted observations +(\code{length(y)}). The columns of \code{yrep} should be in the same order as the +data points in \code{y} for the plots to make sense. See the \strong{Details} and +\strong{Plot Descriptions} sections for additional advice specific to particular +plots.} \item{lw}{A matrix of (smoothed) log weights with the same dimensions as \code{yrep}. See \code{\link[loo:psis]{loo::psis()}} and the associated \code{weights()} method as well as diff --git a/man/PPC-scatterplots.Rd b/man/PPC-scatterplots.Rd index 2727b38c..edec930a 100644 --- a/man/PPC-scatterplots.Rd +++ b/man/PPC-scatterplots.Rd @@ -49,12 +49,13 @@ ppc_scatter_avg_data(y, yrep, group = NULL, stat = "mean") \item{y}{A vector of observations. See \strong{Details}.} \item{yrep}{An \code{S} by \code{N} matrix of draws from the posterior (or prior) -predictive distribution. The number of rows, \code{S}, is the size of the -posterior (or prior) sample used to generate \code{yrep}. The number of columns, -\code{N} is the number of predicted observations (\code{length(y)}). The columns of -\code{yrep} should be in the same order as the data points in \code{y} for the plots -to make sense. See the \strong{Details} and \strong{Plot Descriptions} sections for -additional advice specific to particular plots.} +predictive distribution, or a \code{\link[posterior:draws]{posterior::draws}} object. The number of +rows, \code{S}, is the size of the posterior (or prior) sample used to generate +\code{yrep}. The number of columns, \code{N} is the number of predicted observations +(\code{length(y)}). The columns of \code{yrep} should be in the same order as the +data points in \code{y} for the plots to make sense. See the \strong{Details} and +\strong{Plot Descriptions} sections for additional advice specific to particular +plots.} \item{...}{Currently unused.} diff --git a/man/PPC-test-statistics.Rd b/man/PPC-test-statistics.Rd index 4c39620b..da1c2aca 100644 --- a/man/PPC-test-statistics.Rd +++ b/man/PPC-test-statistics.Rd @@ -68,12 +68,13 @@ ppc_stat_data(y, yrep, group = NULL, stat) \item{y}{A vector of observations. See \strong{Details}.} \item{yrep}{An \code{S} by \code{N} matrix of draws from the posterior (or prior) -predictive distribution. The number of rows, \code{S}, is the size of the -posterior (or prior) sample used to generate \code{yrep}. The number of columns, -\code{N} is the number of predicted observations (\code{length(y)}). The columns of -\code{yrep} should be in the same order as the data points in \code{y} for the plots -to make sense. See the \strong{Details} and \strong{Plot Descriptions} sections for -additional advice specific to particular plots.} +predictive distribution, or a \code{\link[posterior:draws]{posterior::draws}} object. The number of +rows, \code{S}, is the size of the posterior (or prior) sample used to generate +\code{yrep}. The number of columns, \code{N} is the number of predicted observations +(\code{length(y)}). The columns of \code{yrep} should be in the same order as the +data points in \code{y} for the plots to make sense. See the \strong{Details} and +\strong{Plot Descriptions} sections for additional advice specific to particular +plots.} \item{stat}{A single function or a string naming a function, except for the 2D plot which requires a vector of exactly two names or functions. In all diff --git a/man/PPD-distributions.Rd b/man/PPD-distributions.Rd index 7517ec25..758658ac 100644 --- a/man/PPD-distributions.Rd +++ b/man/PPD-distributions.Rd @@ -68,9 +68,10 @@ ppd_boxplot(ypred, ..., notch = TRUE, size = 0.5, alpha = 1) } \arguments{ \item{ypred}{An \code{S} by \code{N} matrix of draws from the posterior (or prior) -predictive distribution. The number of rows, \code{S}, is the size of the -posterior (or prior) sample used to generate \code{ypred}. The number of -columns, \code{N}, is the number of predicted observations.} +predictive distribution, or a \code{\link[posterior:draws]{posterior::draws}} object. The number of +rows, \code{S}, is the size of the posterior (or prior) sample used to generate +\code{ypred}. The number of columns, \code{N}, is the number of predicted +observations.} \item{group}{A grouping variable of the same length as \code{y}. Will be coerced to \link[base:factor]{factor} if not already a factor. diff --git a/man/PPD-intervals.Rd b/man/PPD-intervals.Rd index 9548709f..edadf8e9 100644 --- a/man/PPD-intervals.Rd +++ b/man/PPD-intervals.Rd @@ -78,9 +78,10 @@ ppd_ribbon_data( } \arguments{ \item{ypred}{An \code{S} by \code{N} matrix of draws from the posterior (or prior) -predictive distribution. The number of rows, \code{S}, is the size of the -posterior (or prior) sample used to generate \code{ypred}. The number of -columns, \code{N}, is the number of predicted observations.} +predictive distribution, or a \code{\link[posterior:draws]{posterior::draws}} object. The number of +rows, \code{S}, is the size of the posterior (or prior) sample used to generate +\code{ypred}. The number of columns, \code{N}, is the number of predicted +observations.} \item{x}{A numeric vector to use as the x-axis variable. For example, \code{x} could be a predictor variable from a diff --git a/man/PPD-test-statistics.Rd b/man/PPD-test-statistics.Rd index 7c8b41f3..142f414a 100644 --- a/man/PPD-test-statistics.Rd +++ b/man/PPD-test-statistics.Rd @@ -62,9 +62,10 @@ ppd_stat_data(ypred, group = NULL, stat) } \arguments{ \item{ypred}{An \code{S} by \code{N} matrix of draws from the posterior (or prior) -predictive distribution. The number of rows, \code{S}, is the size of the -posterior (or prior) sample used to generate \code{ypred}. The number of -columns, \code{N}, is the number of predicted observations.} +predictive distribution, or a \code{\link[posterior:draws]{posterior::draws}} object. The number of +rows, \code{S}, is the size of the posterior (or prior) sample used to generate +\code{ypred}. The number of columns, \code{N}, is the number of predicted +observations.} \item{stat}{A single function or a string naming a function, except for the 2D plot which requires a vector of exactly two names or functions. In all diff --git a/tests/testthat/test-helpers-ppc.R b/tests/testthat/test-helpers-ppc.R index 36f921d3..506b666a 100644 --- a/tests/testthat/test-helpers-ppc.R +++ b/tests/testthat/test-helpers-ppc.R @@ -113,6 +113,85 @@ test_that("get_interpolation_values catches impossible values", { ) }) +# validate_predictions with posterior::draws objects ---------------------- +test_that("validate_predictions accepts draws objects", { + result <- validate_predictions(posterior::as_draws_matrix(yrep), ncol(yrep)) + expect_true(is.matrix(result)) + expect_equal(dim(result), dim(yrep)) + expect_true(is.numeric(result)) + + result <- validate_predictions(posterior::as_draws_array(yrep)) + expect_true(is.matrix(result)) + expect_equal(dim(result), dim(yrep)) + + result <- validate_predictions(posterior::as_draws_df(yrep)) + expect_true(is.matrix(result)) + expect_equal(dim(result), dim(yrep)) + + result <- validate_predictions(posterior::as_draws_list(yrep)) + expect_true(is.matrix(result)) + expect_equal(dim(result), dim(yrep)) + + result <- validate_predictions(posterior::as_draws_rvars(yrep)) + expect_true(is.matrix(result)) + expect_equal(dim(result), dim(yrep)) +}) + + +draws_arr <- posterior::bind_draws( + posterior::as_draws_array(matrix(rnorm(1000), nrow = 10, ncol = 100, dimnames = list(NULL, paste0("V", 1:100)))), + posterior::as_draws_array(matrix(rnorm(1000), nrow = 10, ncol = 100, dimnames = list(NULL, paste0("V", 1:100)))), + posterior::as_draws_array(matrix(rnorm(1000), nrow = 10, ncol = 100, dimnames = list(NULL, paste0("V", 1:100)))), + along = "chain" +) + +test_that("validate_predictions merges chains from multi-chain draws objects", { + # 10 iterations x 3 chains x 100 variables -> 30 x 100 matrix + result <- validate_predictions(draws_arr) + expect_equal(nrow(result), 30) + expect_equal(ncol(result), 100) + + result <- validate_predictions(posterior::as_draws_df(draws_arr)) + expect_equal(nrow(result), 30) + expect_equal(ncol(result), 100) + + result <- validate_predictions(posterior::as_draws_list(draws_arr)) + expect_equal(nrow(result), 30) + expect_equal(ncol(result), 100) + + result <- validate_predictions(posterior::as_draws_rvars(draws_arr)) + expect_equal(nrow(result), 30) + expect_equal(ncol(result), 100) +}) + +test_that("posterior::draws input results in identical ggplot data", { + # comparing to regular yrep + p0 <- ggplot2::ggplot_build(ppc_dens_overlay(y, yrep)) + p1 <- ggplot2::ggplot_build(ppc_dens_overlay(y, posterior::as_draws_matrix(yrep))) + p2 <- ggplot2::ggplot_build(ppc_dens_overlay(y, posterior::as_draws_array(yrep))) + p3 <- ggplot2::ggplot_build(ppc_dens_overlay(y, posterior::as_draws_df(yrep))) + p4 <- ggplot2::ggplot_build(ppc_dens_overlay(y, posterior::as_draws_list(yrep))) + p5 <- ggplot2::ggplot_build(ppc_dens_overlay(y, posterior::as_draws_rvars(yrep))) + expect_identical(p1@data, p0@data) + expect_identical(p2@data, p0@data) + expect_identical(p3@data, p0@data) + expect_identical(p4@data, p0@data) + expect_identical(p5@data, p0@data) + + # comparing to converted draws_arr + p1 <- ggplot2::ggplot_build(ppc_dens_overlay(y, draws_arr)) + p2 <- ggplot2::ggplot_build(ppc_dens_overlay(y, posterior::as_draws_matrix(draws_arr))) + p3 <- ggplot2::ggplot_build(ppc_dens_overlay(y, posterior::as_draws_df(draws_arr))) + p4 <- ggplot2::ggplot_build(ppc_dens_overlay(y, posterior::as_draws_list(draws_arr))) + p5 <- ggplot2::ggplot_build(ppc_dens_overlay(y, posterior::as_draws_rvars(draws_arr))) + expect_identical(p2@data, p1@data) + expect_identical(p3@data, p1@data) + expect_identical(p4@data, p1@data) + expect_identical(p5@data, p1@data) +}) + + + # ecdf_intervals --------------------------------------------------------- test_that("ecdf_intervals returns right dimensions and values", { lims <- ecdf_intervals(.0001, N = 100, K = 100, L = 1)