diff --git a/.gitignore b/.gitignore index dd821f77e..ae7df4125 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ inst/doc .Rprofile renv.lock renv/ +.Renviron diff --git a/DESCRIPTION b/DESCRIPTION index 1994f2cc1..d56033357 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: epipredict Title: Basic epidemiology forecasting methods -Version: 0.1.10 +Version: 0.1.11 Authors@R: c( person("Daniel J.", "McDonald", , "daniel@stat.ubc.ca", role = c("aut", "cre")), person("Ryan", "Tibshirani", , "ryantibs@cmu.edu", role = "aut"), @@ -38,6 +38,7 @@ Imports: glue, hardhat (>= 1.3.0), lifecycle, + lubridate, magrittr, recipes (>= 1.0.4), rlang (>= 1.1.0), @@ -54,7 +55,6 @@ Suggests: fs, grf, knitr, - lubridate, poissonreg, purrr, quantreg, diff --git a/NAMESPACE b/NAMESPACE index 3a1fed508..40cc8232a 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -20,6 +20,7 @@ S3method(autoplot,epi_workflow) S3method(bake,check_enough_train_data) S3method(bake,epi_recipe) S3method(bake,step_adjust_latency) +S3method(bake,step_climate) S3method(bake,step_epi_ahead) S3method(bake,step_epi_lag) S3method(bake,step_epi_slide) @@ -59,6 +60,7 @@ S3method(predict,flatline) S3method(prep,check_enough_train_data) S3method(prep,epi_recipe) S3method(prep,step_adjust_latency) +S3method(prep,step_climate) S3method(prep,step_epi_ahead) S3method(prep,step_epi_lag) S3method(prep,step_epi_slide) @@ -72,6 +74,7 @@ S3method(print,arx_fcast) S3method(print,canned_epipred) S3method(print,cdc_baseline_fcast) S3method(print,check_enough_train_data) +S3method(print,climate_fcast) S3method(print,epi_recipe) S3method(print,epi_workflow) S3method(print,flat_fcast) @@ -89,6 +92,7 @@ S3method(print,layer_residual_quantiles) S3method(print,layer_threshold) S3method(print,layer_unnest) S3method(print,step_adjust_latency) +S3method(print,step_climate) S3method(print,step_epi_ahead) S3method(print,step_epi_lag) S3method(print,step_epi_slide) @@ -150,6 +154,8 @@ export(cdc_baseline_args_list) export(cdc_baseline_forecaster) export(check_enough_train_data) export(clean_f_name) +export(climate_args_list) +export(climatological_forecaster) export(default_epi_recipe_blueprint) export(detect_layer) export(dist_quantiles) @@ -198,6 +204,7 @@ export(remove_model) export(slather) export(smooth_quantile_reg) export(step_adjust_latency) +export(step_climate) export(step_epi_ahead) export(step_epi_lag) export(step_epi_naomit) @@ -272,6 +279,10 @@ importFrom(glue,glue) importFrom(hardhat,extract_recipe) importFrom(hardhat,refresh_blueprint) importFrom(hardhat,run_mold) +importFrom(lubridate,"%m-%") +importFrom(lubridate,leap_year) +importFrom(lubridate,month) +importFrom(lubridate,yday) importFrom(magrittr,"%>%") importFrom(magrittr,extract2) importFrom(recipes,bake) diff --git a/NEWS.md b/NEWS.md index 28f5bb99e..8d0d60651 100644 --- a/NEWS.md +++ b/NEWS.md @@ -11,6 +11,7 @@ Pre-1.0.0 numbering scheme: 0.x will indicate releases, while 0.0.x will indicat `data()`, but can be accessed with `data(, package = "epidatasets")`, `epidatasets::` or, after loading the package, the name of the dataset alone (#382). +- `step_adjust_latency()` no longer allows empty column selection. - Addresses upstream breaking changes from cmu-delphi/epiprocess#595 (`growth_rate()`). `step_growth_rate()` has lost its `additional_gr_args_list` argument and now has an `na_rm` argument. @@ -23,8 +24,11 @@ Pre-1.0.0 numbering scheme: 0.x will indicate releases, while 0.0.x will indicat - Fix `quantile_reg()` producing error when asked to output just median-level predictions. - (temporary) ahead negative is allowed for `step_epi_ahead` until we have `step_epi_shift` - Add `reference_date` as an argument to `epi_recipe()` +- Add `step_climate()` to create "climate" predictor in forecast workflows +- Add `climatological_forecaster()` to automatically create climate baselines ## Bug fixes + - Shifting no columns results in no error for either `step_epi_ahead` and `step_epi_lag` - Quantiles produced by `grf` were sometimes out of order. - dist_quantiles can have all `NA` values without causing unrelated errors diff --git a/R/arx_forecaster.R b/R/arx_forecaster.R index 5397ca881..6d95839a4 100644 --- a/R/arx_forecaster.R +++ b/R/arx_forecaster.R @@ -92,7 +92,7 @@ arx_forecaster <- function( #' #' @return An unfitted `epi_workflow`. #' @export -#' @seealso [arx_forecaster()] +#' @seealso [arx_forecaster()], [arx_args_list()] #' #' @examples #' library(dplyr) @@ -283,6 +283,7 @@ arx_fcast_epi_workflow <- function( #' #' @return A list containing updated parameter choices with class `arx_flist`. #' @export +#' @seealso [arx_forecaster()] #' #' @examples #' arx_args_list() diff --git a/R/autoplot.R b/R/autoplot.R index c0e3c68dd..ce6f4ce51 100644 --- a/R/autoplot.R +++ b/R/autoplot.R @@ -120,12 +120,13 @@ autoplot.epi_workflow <- function( shift <- -as.numeric(old_name_y[2]) new_name_y <- paste(old_name_y[-c(1:2)], collapse = "_") edf <- rename(edf, !!new_name_y := !!names(y)) + } else { + new_name_y <- names(y) + shift <- 0 } - if (!is.null(shift)) { - edf <- mutate(edf, time_value = time_value + shift) - } - other_keys <- setdiff(key_colnames(object), c("geo_value", "time_value")) + edf <- mutate(edf, time_value = time_value + shift) + other_keys <- key_colnames(object, exclude = c("geo_value", "time_value")) edf <- as_epi_df(edf, as_of = object$fit$meta$as_of, other_keys = other_keys diff --git a/R/canned-epipred.R b/R/canned-epipred.R index 8a5baa586..48e984168 100644 --- a/R/canned-epipred.R +++ b/R/canned-epipred.R @@ -112,37 +112,39 @@ print.canned_epipred <- function(x, name, ...) { "At forecast date{?s}: {.val {fds}},", "For target date{?s}: {.val {tds}}," )) - fit_recipe <- extract_recipe(x$epi_workflow) - if (detect_step(fit_recipe, "adjust_latency")) { - is_adj_latency <- map_lgl(fit_recipe$steps, function(x) inherits(x, "step_adjust_latency")) - latency_step <- fit_recipe$steps[is_adj_latency][[1]] - # all steps after adjust_latency - later_steps <- fit_recipe$steps[-(1:which(is_adj_latency))] - if (latency_step$method == "extend_ahead") { - step_names <- "step_epi_ahead" - type_str <- "Aheads" - } else if (latency_step$method == "extend_lags") { - step_names <- "step_epi_lag" - type_str <- "Lags" - } else { - step_names <- "" - type_str <- "columns locf" - } - later_steps[[1]]$columns - valid_columns <- later_steps %>% - keep(function(x) inherits(x, step_names)) %>% - purrr::map("columns") %>% - reduce(c) - latency_per_base_col <- latency_step$latency_table %>% - filter(col_name %in% valid_columns) %>% - mutate(latency = abs(latency)) - if (latency_step$method != "locf" && nrow(latency_per_base_col) > 1) { - intro_text <- glue::glue("{type_str} adjusted per column: ") - } else if (latency_step$method != "locf") { - intro_text <- glue::glue("{type_str} adjusted for ") + if ("actions" %in% names(x$pre) && "recipe" %in% names(x$pre$actions)) { + fit_recipe <- extract_recipe(x$epi_workflow) + if (detect_step(fit_recipe, "adjust_latency")) { + is_adj_latency <- map_lgl(fit_recipe$steps, function(x) inherits(x, "step_adjust_latency")) + latency_step <- fit_recipe$steps[is_adj_latency][[1]] + # all steps after adjust_latency + later_steps <- fit_recipe$steps[-(1:which(is_adj_latency))] + if (latency_step$method == "extend_ahead") { + step_names <- "step_epi_ahead" + type_str <- "Aheads" + } else if (latency_step$method == "extend_lags") { + step_names <- "step_epi_lag" + type_str <- "Lags" + } else { + step_names <- "" + type_str <- "columns locf" + } + later_steps[[1]]$columns + valid_columns <- later_steps %>% + keep(function(x) inherits(x, step_names)) %>% + purrr::map("columns") %>% + reduce(c) + latency_per_base_col <- latency_step$latency_table %>% + filter(col_name %in% valid_columns) %>% + mutate(latency = abs(latency)) + if (latency_step$method != "locf" && nrow(latency_per_base_col) > 1) { + intro_text <- glue::glue("{type_str} adjusted per column: ") + } else if (latency_step$method != "locf") { + intro_text <- glue::glue("{type_str} adjusted for ") + } + latency_info <- paste0(intro_text, paste(apply(latency_per_base_col, 1, paste0, collapse = "="), collapse = ", ")) + cli::cli_ul(latency_info) } - latency_info <- paste0(intro_text, paste(apply(latency_per_base_col, 1, paste0, collapse = "="), collapse = ", ")) - cli::cli_ul(latency_info) } cli::cli_text("") } diff --git a/R/climatological_forecaster.R b/R/climatological_forecaster.R new file mode 100644 index 000000000..7df853252 --- /dev/null +++ b/R/climatological_forecaster.R @@ -0,0 +1,266 @@ +#' Climatological forecaster +#' +#' This is another "baseline" type forecaster, but it is especially appropriate +#' for strongly seasonal diseases (e.g., influenza). The idea is to predict +#' the "typical season" by summarizing over all available history in the +#' `epi_data`. This is analogous to a "climate" forecast rather than a "weather" +#' forecast, essentially predicting "typical January" behavior by relying on a +#' long history of such periods rather than heavily using recent data. +#' +#' The point forecast is either the mean or median of the `outcome` in a small +#' window around the target period, computed over the entire available history, +#' separately for each key in the `epi_df` (`geo_value` and any additional keys). +#' The forecast quantiles are computed from the residuals for this point prediction. +#' By default, the residuals are ungrouped, meaning every key will have the same +#' shape distribution (though different centers). Note that if your data is not +#' or comparable scales across keys, this default is likely inappropriate. In that +#' case, you can choose by which keys quantiles are computed using +#' `climate_args_list(quantile_by_key = ...)`. +#' +#' @inheritParams flatline_forecaster +#' @param args_list A list of additional arguments as created by the +#' [climate_args_list()] constructor function. +#' +#' @return A data frame of point and interval) forecasts at a all horizons +#' for each unique combination of `key_vars`. +#' @export +#' @seealso [step_climate()] +#' +#' @examples +#' cases <- cases_deaths_subset +#' # set as_of to the last day in the data +#' # "case_rate_7d_av" is on the same scale for all geographies +#' attr(cases, "metadata")$as_of <- as.Date("2021-12-31") +#' fcast <- climatological_forecaster(cases, "case_rate_7d_av") +#' autoplot(fcast) +#' +#' # Compute quantiles separately by location, and a backcast +#' # "cases" is on different scales by geography, due to population size +#' # so, it is better to compute quantiles separately +#' backcast <- climatological_forecaster( +#' cases, "case_rate_7d_av", +#' climate_args_list( +#' quantile_by_key = "geo_value", +#' forecast_date = as.Date("2021-06-01") +#' ) +#' ) +#' autoplot(backcast) +#' +#' # compute the climate "daily" rather than "weekly" +#' # use a two week window (on both sides) +#' # "cases" is on different scales by geography, due to population size +#' daily_fcast <- climatological_forecaster( +#' cases, "cases", +#' climate_args_list( +#' quantile_by_key = "geo_value", +#' time_type = "day", +#' window_size = 14L, +#' forecast_horizon = 0:30 +#' ) +#' ) +#' autoplot(daily_fcast) + +#' ggplot2::coord_cartesian(xlim = c(as.Date("2021-10-01"), NA)) +climatological_forecaster <- function(epi_data, + outcome, + args_list = climate_args_list()) { + if (!is_epi_df(epi_data)) { + cli_abort( + "`epi_data` must be an {.cls epi_df}, not a {.cls {class(epi_data)}}." + ) + } + edf_time_type <- attr(epi_data, "metadata")$time_type + if (edf_time_type == "custom") { + cli_abort("This forecaster only works with daily, weekly, or yearmonth data.") + } + if (!inherits(args_list, c("climate_fcast", "alist"))) { + cli_abort("`args_list` was not created using `climate_args_list()`.") + } + arg_is_chr_scalar(outcome) + hardhat::check_column_names(epi_data, c(outcome, args_list$quantile_by_key)) + forecast_date <- args_list$forecast_date %||% attr(epi_data, "metadata")$as_of + horizon <- args_list$forecast_horizon + window_size <- args_list$window_size + time_type <- args_list$time_type + # check that the prediction time type is more granular than epi_data's + # time_type + ttype_ord <- match(time_type, c("day", "epiweek", "week", "month")) + ttype_ord <- ttype_ord - as.integer(ttype_ord > 2) + edf_ttype_ord <- match(edf_time_type, c("day", "week", "yearmonth")) + if (ttype_ord < edf_ttype_ord) { + cli_abort(c("Climate forecasts for more granular time types are not possible + if the `epi_data` has a higher level of aggregation", + i = "Here, the data is in {.val {edf_time_type}}s while + `time_type` is {.val {time_type}}." + )) + } + # process the time types + sym_outcome <- sym(outcome) + epi_data <- epi_data %>% + filter(!is.na(!!outcome)) %>% + select(all_of(c(key_colnames(epi_data), outcome))) + if (time_type %in% c("week", "epiweek")) { + ttype_dur <- lubridate::weeks + time_aggr <- ifelse(time_type == "week", epiweek_leap, isoweek_leap) + modulus <- 52L + } else if (time_type == "month") { + ttype_dur <- function(x) lubridate::period(month = x) + time_aggr <- lubridate::month + modulus <- 12L + } else if (time_type == "day") { + ttype_dur <- lubridate::days + time_aggr <- yday_leap + modulus <- 365L + } + center_fn <- switch(args_list$center_method, + mean = function(x, w) mean(x, na.rm = TRUE), + median = function(x, w) stats::median(x, na.rm = TRUE) + ) + # get the point predictions + keys <- key_colnames(epi_data, exclude = "time_value") + epi_data <- epi_data %>% mutate(.idx = time_aggr(time_value), .weights = 1) + climate_center <- epi_data %>% + select(.idx, .weights, all_of(c(outcome, keys))) %>% + dplyr::reframe( + roll_modular_multivec( + !!sym_outcome, .idx, .weights, center_fn, window_size, + modulus + ), + .by = all_of(keys) + ) %>% + rename(.pred = climate_pred) + # get the quantiles + Quantile <- function(x, w) { + if (args_list$symmetrize) x <- c(x, -x) + list(unname(quantile( + x, + probs = args_list$quantile_levels, na.rm = TRUE, type = 8 + ))) + } + climate_quantiles <- epi_data %>% + left_join(climate_center, by = c(".idx", keys)) %>% + mutate({{ outcome }} := !!sym_outcome - .pred) %>% + select(.idx, .weights, all_of(c(outcome, args_list$quantile_by_key))) %>% + dplyr::reframe( + roll_modular_multivec( + !!sym_outcome, .idx, .weights, Quantile, window_size, + modulus + ), + .by = all_of(args_list$quantile_by_key) + ) %>% + rename(.pred_distn = climate_pred) %>% + mutate(.pred_distn = dist_quantiles(.pred_distn, args_list$quantile_levels)) + # combine them together + climate_table <- climate_center %>% + left_join(climate_quantiles, by = c(".idx", args_list$quantile_by_key)) %>% + mutate(.pred_distn = .pred_distn + .pred) + # create the predictions + predictions <- epi_data %>% + select(all_of(keys)) %>% + dplyr::distinct() %>% + mutate(forecast_date = forecast_date, .idx = time_aggr(forecast_date)) + predictions <- map(horizon, ~ { + predictions %>% + mutate(.idx = .idx + .x, target_date = forecast_date + ttype_dur(.x)) + }) %>% + purrr::list_rbind() %>% + mutate( + .idx = .idx %% modulus, + .idx = dplyr::case_when(.idx == 0 ~ modulus, TRUE ~ .idx) + ) %>% + left_join(climate_table, by = c(".idx", keys)) %>% + select(-.idx) + if (args_list$nonneg) { + predictions <- mutate( + predictions, + .pred = snap(.pred, 0, Inf), + .pred_distn = snap(.pred_distn, 0, Inf) + ) + } + + # fill in some extras for plotting methods, etc. + ewf <- epi_workflow() + ewf$trained <- TRUE + ewf$original_data <- epi_data + ewf$pre <- list(mold = list( + outcomes = select(epi_data, !!sym_outcome), + extras = list(roles = list( + geo_value = select(epi_data, geo_value), + time_value = select(epi_data, time_value) + )) + )) + other_keys <- key_colnames(epi_data, exclude = c("time_value", "geo_value")) + if (length(other_keys) > 0) { + ewf$pre$mold$extras$roles$key <- epi_data %>% select(all_of(other_keys)) + } + + structure( + list( + predictions = predictions, + epi_workflow = ewf, + metadata = list( + training = attr(epi_data, "metadata"), + forecast_created = Sys.time() + ) + ), + class = c("climate_fcast", "canned_epipred") + ) +} + +#' Climatological forecaster argument constructor +#' +#' @inheritParams epi_recipe +#' @param forecast_horizon Vector of integers giving the number of time steps, +#' in units of the `time_type`, +#' from the `reference_date` for which predictions should be produced. +#' @inheritParams step_climate +#' @inheritParams flatline_args_list +#' +#' @return A list containing updated parameter choices with class `climate_alist`. +#' @export +#' @seealso [climatological_forecaster()], [step_climate()] +#' +#' @examples +#' climate_args_list() +#' climate_args_list( +#' forecast_horizon = 0:10, +#' quantile_levels = c(.01, .025, 1:19 / 20, .975, .99) +#' ) +#' +climate_args_list <- function( + forecast_date = NULL, + forecast_horizon = 0:4, + time_type = c("epiweek", "week", "month", "day"), + center_method = c("median", "mean"), + window_size = 3L, + quantile_levels = c(.05, .1, .25, .5, .75, .9, .95), + symmetrize = FALSE, + nonneg = TRUE, + quantile_by_key = character(0L), + ...) { + rlang::check_dots_empty() + time_type <- arg_match(time_type) + center_method <- rlang::arg_match(center_method) + arg_is_scalar(window_size, symmetrize, nonneg) + arg_is_chr(quantile_by_key, allow_empty = TRUE) + arg_is_scalar(forecast_date, allow_null = TRUE) + arg_is_date(forecast_date, allow_null = TRUE) + arg_is_nonneg_int(window_size) + arg_is_int(forecast_horizon) + arg_is_lgl(symmetrize, nonneg) + arg_is_probabilities(quantile_levels) + quantile_levels <- sort(unique(c(0.5, quantile_levels))) + + structure( + enlist( + forecast_date, forecast_horizon, time_type, center_method, window_size, + quantile_levels, symmetrize, nonneg, quantile_by_key + ), + class = c("climate_fcast", "alist") + ) +} + +#' @export +print.climate_fcast <- function(x, ...) { + name <- "ARX Forecaster" + NextMethod(name = name, ...) +} diff --git a/R/flatline_forecaster.R b/R/flatline_forecaster.R index 7faad31b3..bf7ecb5b0 100644 --- a/R/flatline_forecaster.R +++ b/R/flatline_forecaster.R @@ -16,7 +16,7 @@ #' #' @param epi_data An [epiprocess::epi_df][epiprocess::as_epi_df] #' @param outcome A scalar character for the column name we wish to predict. -#' @param args_list A list of dditional arguments as created by the +#' @param args_list A list of additional arguments as created by the #' [flatline_args_list()] constructor function. #' #' @return A data frame of point (and optionally interval) forecasts at a single @@ -34,7 +34,7 @@ flatline_forecaster <- function( args_list = flatline_args_list()) { validate_forecaster_inputs(epi_data, outcome, "time_value") if (!inherits(args_list, c("flat_fcast", "alist"))) { - cli_abort("`args_list` was not created using `flatline_args_list().") + cli_abort("`args_list` was not created using `flatline_args_list()`.") } keys <- key_colnames(epi_data) ek <- kill_time_value(keys) diff --git a/R/layer_threshold_preds.R b/R/layer_threshold_preds.R index 7b8ca0252..0f7fe7008 100644 --- a/R/layer_threshold_preds.R +++ b/R/layer_threshold_preds.R @@ -61,6 +61,7 @@ layer_threshold_new <- +# restrict various objects to the interval [lower, upper] snap <- function(x, lower, upper, ...) { UseMethod("snap") } diff --git a/R/step_adjust_latency.R b/R/step_adjust_latency.R index 3d9f19891..ae9db6ef2 100644 --- a/R/step_adjust_latency.R +++ b/R/step_adjust_latency.R @@ -31,7 +31,7 @@ #' 1. `"ca"` is latent by 2 days, whereas `"ma"` is latent by 1 #' 2. if we want to use `b` as an exogenous variable, for `"ma"` it is latent by 3 days instead of just 1. #' -#' Regardless of `method`, `epi_keys_checked="geo_value"` guarantees tha the +#' Regardless of `method`, `epi_keys_checked="geo_value"` guarantees that the #' difference between `"ma"` and `"ca"` is accounted for by making the #' latency adjustment at least 2. For some comparison, here's what the various #' methods will do: @@ -47,7 +47,7 @@ #' forward to the `forecast_date`: #' ```{r toy_df} #' toy_recipe <- epi_recipe(toy_df) %>% -#' step_adjust_latency(method="locf") +#' step_adjust_latency(has_role("raw"), method="locf") #' #' toy_recipe %>% #' prep(toy_df) %>% @@ -62,9 +62,9 @@ #' latencies, the lags for each are adjusted separately. In the toy example: #' ```{r toy_df} #' toy_recipe <- epi_recipe(toy_df) %>% -#' step_adjust_latency(method="extend_lags") %>% -#' step_epi_lag(a,lag=1) %>% -#' step_epi_lag(b,lag=1) %>% +#' step_adjust_latency(has_role("raw"), method = "extend_lags") %>% +#' step_epi_lag(a, lag=1) %>% +#' step_epi_lag(b, lag=1) %>% #' step_epi_ahead(a, ahead=1) #' #' toy_recipe %>% @@ -89,8 +89,8 @@ #' the most latent data to insure there is data available. In the toy example: #' ```{r toy_df} #' toy_recipe <- epi_recipe(toy_df) %>% -#' step_adjust_latency(method="extend_ahead") %>% -#' step_epi_lag(a,lag=0) %>% +#' step_adjust_latency(has_role("raw"), method="extend_ahead") %>% +#' step_epi_lag(a, lag=0) %>% #' step_epi_ahead(a, ahead=1) #' #' toy_recipe %>% @@ -180,22 +180,22 @@ #' @rdname step_adjust_latency #' @export #' @examples -#' jhu <- covid_case_death_rates %>% +#' rates <- covid_case_death_rates %>% #' dplyr::filter(time_value > "2021-11-01", geo_value %in% c("ak", "ca", "ny")) #' # setting the `as_of` to something realistic -#' attributes(jhu)$metadata$as_of <- max(jhu$time_value) + 3 +#' attributes(rates)$metadata$as_of <- max(rates$time_value) + 3 #' -#' r <- epi_recipe(covid_case_death_rates) %>% -#' step_adjust_latency(method = "extend_ahead") %>% +#' r <- epi_recipe(rates) %>% +#' step_adjust_latency(recipes::has_role("raw"), method = "extend_ahead") %>% #' step_epi_ahead(death_rate, ahead = 7) %>% #' step_epi_lag(death_rate, lag = c(0, 7, 14)) #' r #' -#' jhu_fit <- epi_workflow() %>% +#' rates_fit <- epi_workflow() %>% #' add_epi_recipe(r) %>% #' add_model(linear_reg()) %>% -#' fit(data = jhu) -#' jhu_fit +#' fit(data = rates) +#' rates_fit #' #' @importFrom recipes detect_step #' @importFrom rlang enquos is_empty @@ -275,20 +275,15 @@ step_adjust_latency_new <- #' @importFrom dplyr rowwise prep.step_adjust_latency <- function(x, training, info = NULL, ...) { latency <- x$latency + col_names <- recipes::recipes_eval_select(x$terms, training, info) + forecast_date <- x$fixed_forecast_date %||% get_forecast_date(training, info, x$epi_keys_checked, latency) latency_table <- get_latency_table( - training, NULL, forecast_date, latency, + training, col_names, forecast_date, latency, get_sign(x), x$epi_keys_checked, x$keys_to_ignore, info, x$terms ) - # get the columns used, even if it's all of them - terms_used <- x$terms - if (is_empty(terms_used)) { - terms_used <- info %>% - filter(role == "raw") %>% - pull(variable) - } step_adjust_latency_new( terms = x$terms, @@ -304,7 +299,7 @@ prep.step_adjust_latency <- function(x, training, info = NULL, ...) { epi_keys_checked = x$epi_keys_checked, keys_to_ignore = x$keys_to_ignore, check_latency_length = x$check_latency_length, - columns = recipes_eval_select(latency_table$col_name, training, info), + columns = col_names, skip = x$skip, id = x$id ) @@ -350,64 +345,21 @@ bake.step_adjust_latency <- function(object, new_data, ...) { print.step_adjust_latency <- function(x, width = max(20, options$width - 35), ...) { if (!is.null(x$forecast_date)) { - conj <- "with forecast date" + conj <- "w/ forecast date" extra_text <- x$forecast_date } else if (!is.null(x$latency_table)) { conj <- if (nrow(x$latency) == 1) { - "with latency" + "w/ latency" } else { - "with latencies" + "w/ latencies" } extra_text <- unique(x$latency_table$latency) } else { - conj <- "with latency" - extra_text <- "set at train time" - } - # what follows is a somewhat modified version of print_epi_step, since the case of no arguments for adjust_latency means apply to all relevant columns, and not none of them - theme_div_id <- cli::cli_div( - theme = list(.pkg = list(`vec-trunc` = Inf, `vec-last` = ", ")) - ) - # this is a slightly modified copy of - title <- trimws(x$method) - trained_text <- dplyr::if_else(x$trained, "Trained", "") - vline_seperator <- dplyr::if_else(trained_text == "", "", "|") - comma_seperator <- dplyr::if_else( - trained_text != "", true = ",", false = "" - ) - extra_text <- recipes::format_ch_vec(extra_text) - width_title <- nchar(paste0( - "* ", title, ":", " ", conj, " ", extra_text, " ", vline_seperator, - " ", trained_text, " " - )) - width_diff <- cli::console_width() * 1 - width_title - if (x$trained) { - elements <- x$columns - } else { - if (is_empty(x$terms)) { - elements <- "all future predictors" - } else { - elements <- lapply(x$terms, function(x) { - rlang::expr_deparse(rlang::quo_get_expr(x), width = Inf) - }) - elements <- vctrs::list_unchop(elements, ptype = character()) - } + conj <- "latency" + extra_text <- "TBD at train time" } - - element_print_lengths <- cumsum(nchar(elements)) + - c(0L, cumsum(rep(2L, length(elements) - 1))) + - c(rep(5L, length(elements) - 1), 0L) - first_line <- which(width_diff >= element_print_lengths) - first_line <- unname(first_line) - first_line <- ifelse( - test = identical(first_line, integer(0)), - yes = length(element_print_lengths), - no = max(first_line) - ) - more_dots <- ifelse(first_line == length(elements), "", ", ...") - cli::cli_bullets( - c("\n {title}: \\\n {.pkg {cli::cli_vec(elements[seq_len(first_line)])}}\\\n {more_dots} \\\n {conj} \\\n {.pkg {extra_text}} \\\n {vline_seperator} \\\n {.emph {trained_text}}") + title <- trimws(paste("Adj.", x$method)) + print_epi_step(x$columns, x$terms, x$trained, title, + conjunction = conj, extra_text = extra_text ) - - cli::cli_end(theme_div_id) - invisible(x) } diff --git a/R/step_climate.R b/R/step_climate.R new file mode 100644 index 000000000..800de5357 --- /dev/null +++ b/R/step_climate.R @@ -0,0 +1,419 @@ +#' Calculate a climatological variable based on the history +#' +#' `step_climate()` creates a *specification* of a recipe step that will +#' generate one or more new columns of derived data. This step examines all +#' available seasons in the training data and calculates the a measure of center +#' for the "typical" season. Think of this like with the weather: to predict the +#' temperature in January in Pittsburgh, PA, I might look at all previous +#' January's on record, average their temperatures, and include that in my +#' model. So it is important to _align_ the forecast horizon with the climate. +#' This step will work best if added after `step_epi_ahead()`, but that is not +#' strictly required. See the details for more information. +#' +#' @details +#' Construction of a climate predictor can be helpful with strongly seasonal +#' data. But its utility is greatest when the estimated "climate" is aligned +#' to the forecast horizon. +#' For example, if today is December 1, and we want +#' to make a prediction for December 15, we want to know the climate for the +#' week of December 15 to use in our model. But we also want to align the rest +#' of our training data with the climate _2 weeks after_ those dates. +#' +#' To accomplish +#' this, if we have daily data, we could use `time_type = "week"` and +#' `forecast_ahead = 2`. The climate predictor would be created by taking +#' averages over each week (with a window of a few weeks before and after, as +#' determined by `window_size`), and then aligning these with the appropriate dates +#' in the training data so that each `time_value` will "see" the typical climate 2 +#' weeks in the future. +#' +#' Alternatively, in the same scenario, we could use `time_type = "day"` and +#' `forecast_ahead = 14`. The climate predictor would be created by taking +#' averages over a small window around each _day_, and then aligning these with +#' the appropriate dates in the training data so that each `time_value` will +#' "see" the climate 14 days in the future. +#' +#' The only differences between these options is the type of averaging performed +#' over the historical data. In the first case, days in the same week will get +#' the same value of the climate predictor (because we're looking at weekly +#' windows), while in the second case, every day in the data will have the +#' average climate for the _day_ that happens 14 days in the future. +#' +#' Autodetecting the forecast horizon can only be guaranteed to work correctly +#' when the time types are the same: for example using daily data for training +#' and daily climate calculations. However, using weekly data, predicting 4 +#' weeks ahead, and setting `time_type = "month"` is perfectly reasonable. It's +#' just that the climate is calculated over _months_ (January, February, March, +#' etc.) so how to properly align this when producing a forecast for the 5th week +#' in the year is challenging. For scenarios like these, it may be best to +#' approximately match the times with `forecast_ahead = 1`, for example. +#' +#' +#' @inheritParams step_growth_rate +#' @param forecast_ahead The forecast horizon. By default, this step will try to +#' detect whether a forecast horizon has already been specified with +#' [step_epi_ahead()]. Alternatively, one can specify an explicit +#' horizon with a scalar integer. Auto-detection is only possible +#' when the time type of the `epi_df` used to create the `epi_recipe` is the +#' same as the aggregation +#' `time_type` specified in this step (say, both daily or both weekly). If, +#' for example, daily data is used with monthly time aggregation, then +#' auto-detection is not possible (and may in fact lead to strange behaviour +#' even if `forecast_ahead` is specified with an integer). See details below. +#' @param time_type The duration over which time aggregation should be performed. +#' @param center_method The measure of center to be calculated over the time +#' window. +#' @param window_size Scalar integer. How many time units on each side should +#' be included. For example, if `window_size = 3` and `time_type = "day"`, +#' then on each day in the data, the center will be calculated using 3 days +#' before and three days after. So, in this case, it operates like a weekly +#' rolling average, centered at each day. +#' @param epi_keys Character vector or `NULL`. Any columns mentioned will be +#' grouped before performing any center calculation. So for example, given +#' state-level data, a national climate would be calculated if `NULL`, but +#' passing `epi_keys = "geo_value"` would calculate the climate separately +#' by state. +#' @param role What role should be assigned for any variables created by this +#' step? "predictor" is the most likely choice. +#' @template step-return +#' +#' +#' @export +#' @examples +#' # automatically detects the horizon +#' r <- epi_recipe(covid_case_death_rates) %>% +#' step_epi_ahead(death_rate, ahead = 7) %>% +#' step_climate(death_rate, time_type = "day") +#' r +#' +#' r %>% +#' prep(covid_case_death_rates) %>% +#' bake(new_data = NULL) +#' +#' # same idea, but using weekly climate +#' r <- epi_recipe(covid_case_death_rates) %>% +#' step_epi_ahead(death_rate, ahead = 7) %>% +#' step_climate(death_rate, +#' forecast_ahead = 1, time_type = "epiweek", +#' window_size = 1L +#' ) +#' r +#' +#' r %>% +#' prep(covid_case_death_rates) %>% +#' bake(new_data = NULL) +#' +#' # switching the order is possible if you specify `forecast_ahead` +#' r <- epi_recipe(covid_case_death_rates) %>% +#' step_climate(death_rate, forecast_ahead = 7, time_type = "day") %>% +#' step_epi_ahead(death_rate, ahead = 7) +#' r +#' +#' r %>% +#' prep(covid_case_death_rates) %>% +#' bake(new_data = NULL) +step_climate <- + function(recipe, + ..., + forecast_ahead = "detect", + role = "predictor", + time_type = c("detect", "epiweek", "week", "month", "day"), + center_method = c("median", "mean"), + window_size = 3L, + epi_keys = NULL, + prefix = "climate_", + skip = FALSE, + id = rand_id("climate")) { + if (!is_epi_recipe(recipe)) { + cli_abort("This recipe step can only operate on an {.cls epi_recipe}.") + } + + ## Handle ahead autodetection, single outcome, time type + n_outcomes <- sum(recipe$var_info$role == "outcome") + time_type <- rlang::arg_match(time_type) + edf_time_type <- attr(recipe$template, "metadata")$time_type + if (time_type == "detect") time_type <- edf_time_type + if (edf_time_type == "custom") { + cli_abort("This step only works with daily, weekly, or yearmonth data.") + } + if (n_outcomes > 1L) { + cli_abort("Only one {.var outcome} role can be used with this step.") + } + if (is.character(forecast_ahead)) { + forecast_ahead <- rlang::arg_match(forecast_ahead) + if (detect_step(recipe, "epi_ahead")) { + outcomes <- extract_argument(recipe, "step_epi_ahead", "role") == "outcome" + forecast_ahead <- extract_argument(recipe, "step_epi_ahead", "ahead")[outcomes] + if (length(forecast_ahead) != 1L) { + cli_abort(c( + "To detect the `forecast_ahead` automatically, `step_epi_ahead()` + with role = 'outcome' must be specified.", + i = "Check your recipe, or specify this argument directly in `step_climate()`." + )) + } + ttype_ord <- match(time_type, c("day", "epiweek", "week", "month")) + ttype_ord <- ttype_ord - as.integer(ttype_ord > 2) + edf_ttype_ord <- match(edf_time_type, c("day", "week", "yearmonth")) + if (ttype_ord != edf_ttype_ord) { + cli_abort(c("Automatic detection of the `forecast_ahead` is only + supported if the original data and the time type for aggregation + are in the same units.", + i = "Here, the data is in {.val {edf_time_type}}s while + `time_type` is {.val {time_type}}.", + i = "This is resolved most easily by specifying `forecast_ahead`." + )) + } + } else { + forecast_ahead <- 0L + } + } + arg_is_int(forecast_ahead) + + # check other args + center_method <- rlang::arg_match(center_method) + arg_is_chr(role) + arg_is_chr(epi_keys, allow_null = TRUE) + arg_is_nonneg_int(window_size) + arg_is_scalar(window_size) + arg_is_chr_scalar(prefix, id) + arg_is_lgl_scalar(skip) + + time_aggr <- switch(time_type, + epiweek = epiweek_leap, + week = isoweek_leap, + month = lubridate::month, + day = yday_leap + ) + + recipes::add_step( + recipe, + step_climate_new( + terms = enquos(...), + role = role, + trained = FALSE, + forecast_ahead = forecast_ahead, + time_type = time_type, + time_aggr = time_aggr, + modulus = NULL, + center_method = center_method, + window_size = window_size, + epi_keys = epi_keys, + climate_table = NULL, + prefix = prefix, + columns = NULL, + skip = skip, + id = id, + case_weights = NULL + ) + ) + } + + +step_climate_new <- + function(terms, + role, + trained, + forecast_ahead, + time_type, + time_aggr, + modulus, + center_method, + window_size, + epi_keys, + climate_table, + prefix, + columns, + skip, + id, + case_weights) { + recipes::step( + subclass = "climate", + terms = terms, + role = role, + trained = trained, + forecast_ahead = forecast_ahead, + time_type = time_type, + time_aggr = time_aggr, + modulus = modulus, + center_method = center_method, + window_size = window_size, + epi_keys = epi_keys, + climate_table = climate_table, + prefix = prefix, + columns = columns, + skip = skip, + id = id, + case_weights = case_weights + ) + } + + + +#' @export +prep.step_climate <- function(x, training, info = NULL, ...) { + col_names <- recipes_eval_select(x$terms, training, info) + recipes::check_type(training[, col_names], types = c("double", "integer")) + wts <- recipes::get_case_weights(info, training) + wts_used <- !is.null(wts) + wts <- wts %||% rep(1, nrow(training)) + + modulus <- switch(x$time_type, + epiweek = 52L, # only sometimes true + week = 52L, + month = 12L, + day = 365L # only sometimes true + ) + + fn <- switch(x$center_method, + mean = function(x, w) stats::weighted.mean(x, w, na.rm = TRUE), + median = function(x, w) median(x, na.rm = TRUE) + ) + # suppose it's week 52, and there is no week 53 this year; then + # as originally written for 1 week ahead this grabs from week 52+1 %% 53 + # which will be week 53, not week 1. + ahead_period <- switch(x$time_type, + epiweek = lubridate::weeks(x$forecast_ahead), + week = lubridate::weeks(x$forecast_ahead), + month = months(x$forecast_ahead), + day = lubridate::days(x$forecast_ahead), + ) + climate_table <- + training %>% + mutate( + # subtracts a month w/o rollover (usual behavior on weeks/days) + .idx = time_value %m-% ahead_period, + .idx = x$time_aggr(.idx), + .weights = wts + ) %>% + select(.idx, .weights, all_of(c(col_names, x$epi_keys))) %>% + tidyr::pivot_longer(all_of(unname(col_names))) %>% + dplyr::reframe( + roll_modular_multivec(value, .idx, .weights, fn, x$window_size, modulus), + .by = c("name", x$epi_keys) + ) %>% + tidyr::pivot_wider( + names_from = "name", values_from = "climate_pred", names_prefix = x$prefix + ) + + step_climate_new( + terms = x$terms, + role = x$role, + trained = TRUE, + forecast_ahead = x$forecast_ahead, + time_type = x$time_type, + time_aggr = x$time_aggr, + modulus = modulus, + center_method = x$center_method, + window_size = x$window_size, + epi_keys = x$epi_keys, + climate_table = climate_table, + prefix = x$prefix, + columns = col_names, + skip = x$skip, + id = x$id, + case_weights = wts_used + ) +} + + +#' @export +bake.step_climate <- function(object, new_data, ...) { + climate_table <- object$climate_table + new_data %>% + mutate(.idx = object$time_aggr(time_value)) %>% + left_join(climate_table, by = c(".idx", object$epi_keys)) %>% + select(-.idx) +} + + +#' @export +print.step_climate <- function(x, width = max(20, options()$width - 30), ...) { + print_epi_step( + x$columns, x$terms, x$trained, + title = "Calculating climate_predictor for ", + conjunction = "by", + extra_text = paste(x$time_type, "using the", x$center_method) + ) + invisible(x) +} + +#' group col by .idx values and sum windows around each .idx value +#' @param .idx the relevant periodic part of time value, e.g. the week number +#' @param col the list of values indexed by `.idx` +#' @param weights how much to weigh each particular datapoint +#' @param aggr the aggregation function, probably Quantile, mean or median +#' @param window_size the number of .idx entries before and after to include in +#' the aggregation +#' @param modulus the maximum value of `.idx` +#' @importFrom lubridate %m-% +roll_modular_multivec <- function(col, .idx, weights, aggr, window_size, modulus) { + tib <- tibble(col = col, weights = weights, .idx = .idx) |> + arrange(.idx) |> + tidyr::nest(data = c(col, weights), .by = .idx) + out <- double(modulus + 1) + for (iter in seq_along(out)) { + # +1 from 1-indexing + entries <- (iter - window_size):(iter + window_size) %% modulus + entries[entries == 0] <- modulus + # note that because we are 1-indexing, we're looking for indices that are 1 + # larger than the actual day/week in the year + if (modulus == 365) { + # we need to grab just the window around the leap day on the leap day + if (iter == 366) { + # there's an extra data point in front of the leap day + entries <- (59 - window_size):(59 + window_size - 1) %% modulus + entries[entries == 0] <- modulus + # adding in the leap day itself + entries <- c(entries, 999) + } else if ((59 %in% entries) || (60 %in% entries)) { + # if we're on the Feb/March boundary for daily data, we need to add in the + # leap day data + entries <- c(entries, 999) + } + } else if (modulus == 52) { + # we need to grab just the window around the leap week on the leap week + if (iter == 53) { + entries <- (53 - window_size):(53 + window_size - 1) %% 52 + entries[entries == 0] <- 52 + entries <- c(entries, 999) + } else if ((52 %in% entries) || (1 %in% entries)) { + # if we're on the year boundary for weekly data, we need to add in the + # leap week data (which is the extra week at the end) + entries <- c(entries, 999) + } + } + out[iter] <- with( + purrr::list_rbind(tib %>% filter(.idx %in% entries) %>% pull(data)), + aggr(col, weights) + ) + } + tibble(.idx = unique(tib$.idx), climate_pred = out[seq_len(nrow(tib))]) +} + + +#' a function that assigns Feb 29th to 999, and aligns all other dates the same +#' number in the year, regardless of whether it's a leap year +#' @keywords internal +#' @importFrom lubridate yday month leap_year +yday_leap <- function(time_value) { + dplyr::case_when( + !leap_year(time_value) ~ yday(time_value), + leap_day(time_value) ~ 999, + TRUE ~ yday(time_value) - as.numeric(month(time_value) > 2L) + ) +} +leap_day <- function(x) lubridate::month(x) == 2 & lubridate::day(x) == 29 +#' epiweek, but it assigns week 53 the value of 999 instead so it mirrors the assignments in yday_leap +#' @keywords internal +epiweek_leap <- function(time_value) { + week_values <- lubridate::epiweek(time_value) + week_values[week_values == 53] <- 999 + week_values +} +#' isoweek, but it assigns week 53 the value of 999 instead so it mirrors the assignments in yday_leap +#' @keywords internal +isoweek_leap <- function(time_value) { + week_values <- lubridate::isoweek(time_value) + week_values[week_values == 53] <- 999 + week_values +} diff --git a/R/step_epi_shift.R b/R/step_epi_shift.R index beda182e6..ae4bd3f31 100644 --- a/R/step_epi_shift.R +++ b/R/step_epi_shift.R @@ -66,7 +66,10 @@ step_epi_lag <- )) } arg_is_nonneg_int(lag) - arg_is_chr_scalar(prefix, id) + arg_is_chr_scalar(prefix, id, role) + if (role == "outcome" && length(lag) > 1L) { + cli_abort("Only one {.val outcome} may be created with this step.") + } recipes::add_step( recipe, @@ -111,7 +114,7 @@ step_epi_ahead <- i = "Did you perhaps pass an integer in `...` accidentally?" )) } - arg_is_chr_scalar(prefix, id) + arg_is_chr_scalar(prefix, id, role) recipes::add_step( recipe, diff --git a/R/utils-latency.R b/R/utils-latency.R index d854cb9cf..398cc9072 100644 --- a/R/utils-latency.R +++ b/R/utils-latency.R @@ -319,8 +319,7 @@ get_latency_table <- function(training, columns, forecast_date, latency, if (length(columns) > 0) { latency_table <- latency_table %>% filter(col_name %in% columns) } - training_dropped <- training %>% - drop_ignored_keys(keys_to_ignore) + training_dropped <- training %>% drop_ignored_keys(keys_to_ignore) if (is.null(latency)) { latency_table <- latency_table %>% rowwise() %>% @@ -479,8 +478,7 @@ compare_bake_prep_latencies <- function(object, new_data, call = caller_env()) { #' @keywords internal create_shift_grid <- function(prefix, amount, target_sign, columns, latency_table, latency_sign) { - if (!is.null(latency_table) && - latency_sign == target_sign) { + if (!is.null(latency_table) && latency_sign == target_sign) { # get the actually used latencies rel_latency <- latency_table %>% filter(col_name %in% columns) latency_adjusted <- TRUE diff --git a/README.md b/README.md index 174196343..1f24bab2b 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ covid_case_death_rates #> An `epi_df` object, 20,496 x 4 with metadata: #> * geo_type = state #> * time_type = day -#> * as_of = 2022-05-31 +#> * as_of = 2023-03-10 #> #> # A tibble: 20,496 × 4 #> geo_value time_value case_rate death_rate @@ -88,8 +88,8 @@ covid_case_death_rates #> 3 ar 2020-12-31 66.0 1.27 #> 4 as 2020-12-31 0 0 #> 5 az 2020-12-31 76.8 1.10 -#> 6 ca 2020-12-31 96.0 0.751 -#> 7 co 2020-12-31 35.8 0.649 +#> 6 ca 2020-12-31 95.9 0.755 +#> 7 co 2020-12-31 37.8 0.376 #> 8 ct 2020-12-31 52.1 0.819 #> 9 dc 2020-12-31 31.0 0.601 #> 10 de 2020-12-31 64.3 0.912 @@ -113,12 +113,12 @@ two_week_ahead <- arx_forecaster( two_week_ahead #> ══ A basic forecaster of type ARX Forecaster ═══════════════════════════════ #> -#> This forecaster was fit on 2025-01-23 14:01:04. +#> This forecaster was fit on 2025-02-11 12:32:56. #> #> Training data was an with: #> • Geography: state, #> • Time type: day, -#> • Using data up-to-date as of: 2022-05-31. +#> • Using data up-to-date as of: 2023-03-10. #> • With the last data available on 2021-12-31 #> #> ── Predictions ───────────────────────────────────────────────────────────── @@ -162,11 +162,11 @@ two_week_ahead$epi_workflow #> #> Coefficients: #> (Intercept) lag_0_case_rate lag_1_case_rate lag_2_case_rate -#> -0.0072151 0.0030311 0.0012525 0.0009551 +#> -0.0071026 0.0040340 0.0007863 0.0003699 #> lag_3_case_rate lag_7_case_rate lag_14_case_rate lag_0_death_rate -#> 0.0011488 0.0012238 0.0003301 0.1348459 +#> 0.0012887 0.0011980 0.0002527 0.1348573 #> lag_7_death_rate lag_14_death_rate -#> 0.1468325 0.1056316 +#> 0.1479274 0.1067074 #> #> ── Postprocessor ─────────────────────────────────────────────────────────── #> @@ -189,16 +189,16 @@ two_week_ahead$predictions #> # A tibble: 56 × 5 #> geo_value .pred .pred_distn forecast_date target_date #> -#> 1 ak 0.448 quantiles(0.45)[2] 2021-12-31 2022-01-14 -#> 2 al 0.574 quantiles(0.57)[2] 2021-12-31 2022-01-14 -#> 3 ar 0.673 quantiles(0.67)[2] 2021-12-31 2022-01-14 -#> 4 as 0 quantiles(0.12)[2] 2021-12-31 2022-01-14 -#> 5 az 0.678 quantiles(0.68)[2] 2021-12-31 2022-01-14 -#> 6 ca 0.575 quantiles(0.57)[2] 2021-12-31 2022-01-14 -#> 7 co 0.862 quantiles(0.86)[2] 2021-12-31 2022-01-14 -#> 8 ct 1.07 quantiles(1.07)[2] 2021-12-31 2022-01-14 -#> 9 dc 2.12 quantiles(2.12)[2] 2021-12-31 2022-01-14 -#> 10 de 1.09 quantiles(1.09)[2] 2021-12-31 2022-01-14 +#> 1 ak 0.450 quantiles(0.45)[7] 2021-12-31 2022-01-14 +#> 2 al 0.602 quantiles(0.6)[7] 2021-12-31 2022-01-14 +#> 3 ar 0.694 quantiles(0.69)[7] 2021-12-31 2022-01-14 +#> 4 as 0 quantiles(0)[7] 2021-12-31 2022-01-14 +#> 5 az 0.699 quantiles(0.7)[7] 2021-12-31 2022-01-14 +#> 6 ca 0.592 quantiles(0.59)[7] 2021-12-31 2022-01-14 +#> 7 co 1.47 quantiles(1.47)[7] 2021-12-31 2022-01-14 +#> 8 ct 1.08 quantiles(1.08)[7] 2021-12-31 2022-01-14 +#> 9 dc 2.14 quantiles(2.14)[7] 2021-12-31 2022-01-14 +#> 10 de 1.13 quantiles(1.13)[7] 2021-12-31 2022-01-14 #> # ℹ 46 more rows ``` diff --git a/epipredict.Rproj b/epipredict.Rproj index c1a626913..0c2659d89 100644 --- a/epipredict.Rproj +++ b/epipredict.Rproj @@ -1,5 +1,5 @@ Version: 1.0 -ProjectId: 51641a05-0347-438c-a50e-466a31e886c2 +ProjectId: a71c2044-10c8-46a9-9702-f4bfc95042c8 RestoreWorkspace: No SaveWorkspace: No diff --git a/man/arx_args_list.Rd b/man/arx_args_list.Rd index 5ece7109b..650c4a614 100644 --- a/man/arx_args_list.Rd +++ b/man/arx_args_list.Rd @@ -101,3 +101,6 @@ arx_args_list() arx_args_list(symmetrize = FALSE) arx_args_list(quantile_levels = c(.1, .3, .7, .9), n_training = 120) } +\seealso{ +\code{\link[=arx_forecaster]{arx_forecaster()}} +} diff --git a/man/arx_fcast_epi_workflow.Rd b/man/arx_fcast_epi_workflow.Rd index c2e38218f..61d293ba1 100644 --- a/man/arx_fcast_epi_workflow.Rd +++ b/man/arx_fcast_epi_workflow.Rd @@ -58,5 +58,5 @@ arx_fcast_epi_workflow(jhu, "death_rate", ) } \seealso{ -\code{\link[=arx_forecaster]{arx_forecaster()}} +\code{\link[=arx_forecaster]{arx_forecaster()}}, \code{\link[=arx_args_list]{arx_args_list()}} } diff --git a/man/climate_args_list.Rd b/man/climate_args_list.Rd new file mode 100644 index 000000000..3a889e5c7 --- /dev/null +++ b/man/climate_args_list.Rd @@ -0,0 +1,83 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/climatological_forecaster.R +\name{climate_args_list} +\alias{climate_args_list} +\title{Climatological forecaster argument constructor} +\usage{ +climate_args_list( + forecast_date = NULL, + forecast_horizon = 0:4, + time_type = c("epiweek", "week", "month", "day"), + center_method = c("median", "mean"), + window_size = 3L, + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95), + symmetrize = FALSE, + nonneg = TRUE, + quantile_by_key = character(0L), + ... +) +} +\arguments{ +\item{forecast_date}{Date. The date from which the forecast is occurring. +The default \code{NULL} will determine this automatically from either +\enumerate{ +\item the maximum time value for which there's data if there is no latency +adjustment (the default case), or +\item the \code{as_of} date of \code{epi_data} if \code{adjust_latency} is +non-\code{NULL}. +}} + +\item{forecast_horizon}{Vector of integers giving the number of time steps, +in units of the \code{time_type}, +from the \code{reference_date} for which predictions should be produced.} + +\item{time_type}{The duration over which time aggregation should be performed.} + +\item{center_method}{The measure of center to be calculated over the time +window.} + +\item{window_size}{Scalar integer. How many time units on each side should +be included. For example, if \code{window_size = 3} and \code{time_type = "day"}, +then on each day in the data, the center will be calculated using 3 days +before and three days after. So, in this case, it operates like a weekly +rolling average, centered at each day.} + +\item{quantile_levels}{Vector or \code{NULL}. A vector of probabilities to produce +prediction intervals. These are created by computing the quantiles of +training residuals. A \code{NULL} value will result in point forecasts only.} + +\item{symmetrize}{Logical. The default \code{TRUE} calculates +symmetric prediction intervals. This argument only applies when +residual quantiles are used. It is not applicable with +\code{trainer = quantile_reg()}, for example.} + +\item{nonneg}{Logical. The default \code{TRUE} enforces nonnegative predictions +by hard-thresholding at 0.} + +\item{quantile_by_key}{Character vector. Groups residuals by listed keys +before calculating residual quantiles. See the \code{by_key} argument to +\code{\link[=layer_residual_quantiles]{layer_residual_quantiles()}} for more information. The default, +\code{character(0)} performs no grouping. This argument only applies when +residual quantiles are used. It is not applicable with +\code{trainer = quantile_reg()}, for example.} + +\item{...}{Further arguments passed to or from other methods (not currently +used).} +} +\value{ +A list containing updated parameter choices with class \code{climate_alist}. +} +\description{ +Climatological forecaster argument constructor +} +\examples{ +climate_args_list() +climate_args_list( + forecast_horizon = 0:10, + quantile_levels = c(.01, .025, 1:19 / 20, .975, .99) +) + +} +\seealso{ +\code{\link[=climatological_forecaster]{climatological_forecaster()}}, \code{\link[=step_climate]{step_climate()}} +} diff --git a/man/climatological_forecaster.Rd b/man/climatological_forecaster.Rd new file mode 100644 index 000000000..d773ebce6 --- /dev/null +++ b/man/climatological_forecaster.Rd @@ -0,0 +1,77 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/climatological_forecaster.R +\name{climatological_forecaster} +\alias{climatological_forecaster} +\title{Climatological forecaster} +\usage{ +climatological_forecaster(epi_data, outcome, args_list = climate_args_list()) +} +\arguments{ +\item{epi_data}{An \link[epiprocess:epi_df]{epiprocess::epi_df}} + +\item{outcome}{A scalar character for the column name we wish to predict.} + +\item{args_list}{A list of additional arguments as created by the +\code{\link[=climate_args_list]{climate_args_list()}} constructor function.} +} +\value{ +A data frame of point and interval) forecasts at a all horizons +for each unique combination of \code{key_vars}. +} +\description{ +This is another "baseline" type forecaster, but it is especially appropriate +for strongly seasonal diseases (e.g., influenza). The idea is to predict +the "typical season" by summarizing over all available history in the +\code{epi_data}. This is analogous to a "climate" forecast rather than a "weather" +forecast, essentially predicting "typical January" behavior by relying on a +long history of such periods rather than heavily using recent data. +} +\details{ +The point forecast is either the mean or median of the \code{outcome} in a small +window around the target period, computed over the entire available history, +separately for each key in the \code{epi_df} (\code{geo_value} and any additional keys). +The forecast quantiles are computed from the residuals for this point prediction. +By default, the residuals are ungrouped, meaning every key will have the same +shape distribution (though different centers). Note that if your data is not +or comparable scales across keys, this default is likely inappropriate. In that +case, you can choose by which keys quantiles are computed using +\code{climate_args_list(quantile_by_key = ...)}. +} +\examples{ +cases <- cases_deaths_subset +# set as_of to the last day in the data +# "case_rate_7d_av" is on the same scale for all geographies +attr(cases, "metadata")$as_of <- as.Date("2021-12-31") +fcast <- climatological_forecaster(cases, "case_rate_7d_av") +autoplot(fcast) + +# Compute quantiles separately by location, and a backcast +# "cases" is on different scales by geography, due to population size +# so, it is better to compute quantiles separately +backcast <- climatological_forecaster( + cases, "case_rate_7d_av", + climate_args_list( + quantile_by_key = "geo_value", + forecast_date = as.Date("2021-06-01") + ) +) +autoplot(backcast) + +# compute the climate "daily" rather than "weekly" +# use a two week window (on both sides) +# "cases" is on different scales by geography, due to population size +daily_fcast <- climatological_forecaster( + cases, "cases", + climate_args_list( + quantile_by_key = "geo_value", + time_type = "day", + window_size = 14L, + forecast_horizon = 0:30 + ) +) +autoplot(daily_fcast) + + ggplot2::coord_cartesian(xlim = c(as.Date("2021-10-01"), NA)) +} +\seealso{ +\code{\link[=step_climate]{step_climate()}} +} diff --git a/man/figures/lifecycle-archived.svg b/man/figures/lifecycle-archived.svg new file mode 100644 index 000000000..745ab0c78 --- /dev/null +++ b/man/figures/lifecycle-archived.svg @@ -0,0 +1,21 @@ + + lifecycle: archived + + + + + + + + + + + + + + + lifecycle + + archived + + diff --git a/man/figures/lifecycle-defunct.svg b/man/figures/lifecycle-defunct.svg new file mode 100644 index 000000000..d5c9559ed --- /dev/null +++ b/man/figures/lifecycle-defunct.svg @@ -0,0 +1,21 @@ + + lifecycle: defunct + + + + + + + + + + + + + + + lifecycle + + defunct + + diff --git a/man/figures/lifecycle-deprecated.svg b/man/figures/lifecycle-deprecated.svg new file mode 100644 index 000000000..b61c57c3f --- /dev/null +++ b/man/figures/lifecycle-deprecated.svg @@ -0,0 +1,21 @@ + + lifecycle: deprecated + + + + + + + + + + + + + + + lifecycle + + deprecated + + diff --git a/man/figures/lifecycle-experimental.svg b/man/figures/lifecycle-experimental.svg new file mode 100644 index 000000000..5d88fc2c6 --- /dev/null +++ b/man/figures/lifecycle-experimental.svg @@ -0,0 +1,21 @@ + + lifecycle: experimental + + + + + + + + + + + + + + + lifecycle + + experimental + + diff --git a/man/figures/lifecycle-maturing.svg b/man/figures/lifecycle-maturing.svg new file mode 100644 index 000000000..897370ecf --- /dev/null +++ b/man/figures/lifecycle-maturing.svg @@ -0,0 +1,21 @@ + + lifecycle: maturing + + + + + + + + + + + + + + + lifecycle + + maturing + + diff --git a/man/figures/lifecycle-questioning.svg b/man/figures/lifecycle-questioning.svg new file mode 100644 index 000000000..7c1721d05 --- /dev/null +++ b/man/figures/lifecycle-questioning.svg @@ -0,0 +1,21 @@ + + lifecycle: questioning + + + + + + + + + + + + + + + lifecycle + + questioning + + diff --git a/man/figures/lifecycle-soft-deprecated.svg b/man/figures/lifecycle-soft-deprecated.svg new file mode 100644 index 000000000..9c166ff30 --- /dev/null +++ b/man/figures/lifecycle-soft-deprecated.svg @@ -0,0 +1,21 @@ + + lifecycle: soft-deprecated + + + + + + + + + + + + + + + lifecycle + + soft-deprecated + + diff --git a/man/figures/lifecycle-stable.svg b/man/figures/lifecycle-stable.svg new file mode 100644 index 000000000..9bf21e76b --- /dev/null +++ b/man/figures/lifecycle-stable.svg @@ -0,0 +1,29 @@ + + lifecycle: stable + + + + + + + + + + + + + + + + lifecycle + + + + stable + + + diff --git a/man/figures/lifecycle-superseded.svg b/man/figures/lifecycle-superseded.svg new file mode 100644 index 000000000..db8d757f7 --- /dev/null +++ b/man/figures/lifecycle-superseded.svg @@ -0,0 +1,21 @@ + + lifecycle: superseded + + + + + + + + + + + + + + + lifecycle + + superseded + + diff --git a/man/flatline_forecaster.Rd b/man/flatline_forecaster.Rd index f70c05e0f..f78e2f931 100644 --- a/man/flatline_forecaster.Rd +++ b/man/flatline_forecaster.Rd @@ -11,7 +11,7 @@ flatline_forecaster(epi_data, outcome, args_list = flatline_args_list()) \item{outcome}{A scalar character for the column name we wish to predict.} -\item{args_list}{A list of dditional arguments as created by the +\item{args_list}{A list of additional arguments as created by the \code{\link[=flatline_args_list]{flatline_args_list()}} constructor function.} } \value{ diff --git a/man/roll_modular_multivec.Rd b/man/roll_modular_multivec.Rd new file mode 100644 index 000000000..a26cd5884 --- /dev/null +++ b/man/roll_modular_multivec.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/step_climate.R +\name{roll_modular_multivec} +\alias{roll_modular_multivec} +\title{group col by .idx values and sum windows around each .idx value} +\usage{ +roll_modular_multivec(col, .idx, weights, aggr, window_size, modulus) +} +\arguments{ +\item{col}{the list of values indexed by \code{.idx}} + +\item{.idx}{the relevant periodic part of time value, e.g. the week number} + +\item{weights}{how much to weigh each particular datapoint} + +\item{aggr}{the aggregation function, probably Quantile, mean or median} + +\item{window_size}{the number of .idx entries before and after to include in +the aggregation} + +\item{modulus}{the maximum value of \code{.idx}} +} +\description{ +group col by .idx values and sum windows around each .idx value +} diff --git a/man/step_adjust_latency.Rd b/man/step_adjust_latency.Rd index 0078de100..9e1bafbd5 100644 --- a/man/step_adjust_latency.Rd +++ b/man/step_adjust_latency.Rd @@ -114,7 +114,7 @@ there are two issues we will need to address: \item if we want to use \code{b} as an exogenous variable, for \code{"ma"} it is latent by 3 days instead of just 1. } -Regardless of \code{method}, \code{epi_keys_checked="geo_value"} guarantees tha the +Regardless of \code{method}, \code{epi_keys_checked="geo_value"} guarantees that the difference between \code{"ma"} and \code{"ca"} is accounted for by making the latency adjustment at least 2. For some comparison, here's what the various methods will do: @@ -130,7 +130,7 @@ doesn't matter which day we're trying to predict, since it just fills forward to the \code{forecast_date}: \if{html}{\out{
}}\preformatted{toy_recipe <- epi_recipe(toy_df) \%>\% - step_adjust_latency(method="locf") + step_adjust_latency(has_role("raw"), method="locf") toy_recipe \%>\% prep(toy_df) \%>\% @@ -143,7 +143,7 @@ toy_recipe \%>\% #> #> # A tibble: 8 x 4 #> geo_value time_value a b -#> * +#> #> 1 ca 2015-01-11 100 5 #> 2 ca 2015-01-12 103 10 #> 3 ca 2015-01-13 103 10 @@ -163,9 +163,9 @@ a per-column basis; if cases and deaths are reported at different latencies, the lags for each are adjusted separately. In the toy example: \if{html}{\out{
}}\preformatted{toy_recipe <- epi_recipe(toy_df) \%>\% - step_adjust_latency(method="extend_lags") \%>\% - step_epi_lag(a,lag=1) \%>\% - step_epi_lag(b,lag=1) \%>\% + step_adjust_latency(has_role("raw"), method = "extend_lags") \%>\% + step_epi_lag(a, lag=1) \%>\% + step_epi_lag(b, lag=1) \%>\% step_epi_ahead(a, ahead=1) toy_recipe \%>\% @@ -179,7 +179,7 @@ toy_recipe \%>\% #> #> # A tibble: 21 x 7 #> geo_value time_value a b lag_3_a lag_4_b ahead_1_a -#> * +#> #> 1 ca 2015-01-10 NA NA NA NA 100 #> 2 ca 2015-01-11 100 5 NA NA 103 #> 3 ca 2015-01-12 103 10 NA NA NA @@ -212,8 +212,8 @@ different data sources have different latencies; it must use the latency of the most latent data to insure there is data available. In the toy example: \if{html}{\out{
}}\preformatted{toy_recipe <- epi_recipe(toy_df) \%>\% - step_adjust_latency(method="extend_ahead") \%>\% - step_epi_lag(a,lag=0) \%>\% + step_adjust_latency(has_role("raw"), method="extend_ahead") \%>\% + step_epi_lag(a, lag=0) \%>\% step_epi_ahead(a, ahead=1) toy_recipe \%>\% @@ -227,7 +227,7 @@ toy_recipe \%>\% #> #> # A tibble: 10 x 6 #> geo_value time_value a b lag_0_a ahead_3_a -#> * +#> #> 1 ca 2015-01-08 NA NA NA 100 #> 2 ca 2015-01-09 NA NA NA 103 #> 3 ca 2015-01-11 100 5 100 NA @@ -267,8 +267,8 @@ while this will not: \if{html}{\out{
}}\preformatted{toy_recipe <- epi_recipe(toy_df) \%>\% step_epi_lag(a, lag=0) \%>\% step_adjust_latency(a, method = "extend_lags") -#> Warning: If `method` is "extend_lags" or "locf", then the previous `step_epi_lag`s won't -#> work with modified data. +#> Warning: If `method` is "extend_lags" or "locf", then the previous `step_epi_lag`s won't work with +#> modified data. }\if{html}{\out{
}} If you create columns that you then apply lags to (such as @@ -277,22 +277,22 @@ If you create columns that you then apply lags to (such as } \examples{ -jhu <- covid_case_death_rates \%>\% +rates <- covid_case_death_rates \%>\% dplyr::filter(time_value > "2021-11-01", geo_value \%in\% c("ak", "ca", "ny")) # setting the `as_of` to something realistic -attributes(jhu)$metadata$as_of <- max(jhu$time_value) + 3 +attributes(rates)$metadata$as_of <- max(rates$time_value) + 3 -r <- epi_recipe(covid_case_death_rates) \%>\% - step_adjust_latency(method = "extend_ahead") \%>\% +r <- epi_recipe(rates) \%>\% + step_adjust_latency(recipes::has_role("raw"), method = "extend_ahead") \%>\% step_epi_ahead(death_rate, ahead = 7) \%>\% step_epi_lag(death_rate, lag = c(0, 7, 14)) r -jhu_fit <- epi_workflow() \%>\% +rates_fit <- epi_workflow() \%>\% add_epi_recipe(r) \%>\% add_model(linear_reg()) \%>\% - fit(data = jhu) -jhu_fit + fit(data = rates) +rates_fit } \seealso{ diff --git a/man/step_climate.Rd b/man/step_climate.Rd new file mode 100644 index 000000000..9b29fdc42 --- /dev/null +++ b/man/step_climate.Rd @@ -0,0 +1,156 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/step_climate.R +\name{step_climate} +\alias{step_climate} +\title{Calculate a climatological variable based on the history} +\usage{ +step_climate( + recipe, + ..., + forecast_ahead = "detect", + role = "predictor", + time_type = c("detect", "epiweek", "week", "month", "day"), + center_method = c("median", "mean"), + window_size = 3L, + epi_keys = NULL, + prefix = "climate_", + skip = FALSE, + id = rand_id("climate") +) +} +\arguments{ +\item{recipe}{A recipe object. The step will be added to the +sequence of operations for this recipe.} + +\item{...}{One or more selector functions to choose variables +for this step. See \code{\link[recipes:selections]{recipes::selections()}} for more details.} + +\item{forecast_ahead}{The forecast horizon. By default, this step will try to +detect whether a forecast horizon has already been specified with +\code{\link[=step_epi_ahead]{step_epi_ahead()}}. Alternatively, one can specify an explicit +horizon with a scalar integer. Auto-detection is only possible +when the time type of the \code{epi_df} used to create the \code{epi_recipe} is the +same as the aggregation +\code{time_type} specified in this step (say, both daily or both weekly). If, +for example, daily data is used with monthly time aggregation, then +auto-detection is not possible (and may in fact lead to strange behaviour +even if \code{forecast_ahead} is specified with an integer). See details below.} + +\item{role}{What role should be assigned for any variables created by this +step? "predictor" is the most likely choice.} + +\item{time_type}{The duration over which time aggregation should be performed.} + +\item{center_method}{The measure of center to be calculated over the time +window.} + +\item{window_size}{Scalar integer. How many time units on each side should +be included. For example, if \code{window_size = 3} and \code{time_type = "day"}, +then on each day in the data, the center will be calculated using 3 days +before and three days after. So, in this case, it operates like a weekly +rolling average, centered at each day.} + +\item{epi_keys}{Character vector or \code{NULL}. Any columns mentioned will be +grouped before performing any center calculation. So for example, given +state-level data, a national climate would be calculated if \code{NULL}, but +passing \code{epi_keys = "geo_value"} would calculate the climate separately +by state.} + +\item{prefix}{A character string that will be prefixed to the new column.} + +\item{skip}{A logical. Should the step be skipped when the +recipe is baked by \code{\link[=bake]{bake()}}? While all operations are baked +when \code{\link[=prep]{prep()}} is run, some operations may not be able to be +conducted on new data (e.g. processing the outcome variable(s)). +Care should be taken when using \code{skip = TRUE} as it may affect +the computations for subsequent operations.} + +\item{id}{A unique identifier for the step} +} +\value{ +An updated version of \code{recipe} with the new step added to the +sequence of any existing operations. +} +\description{ +\code{step_climate()} creates a \emph{specification} of a recipe step that will +generate one or more new columns of derived data. This step examines all +available seasons in the training data and calculates the a measure of center +for the "typical" season. Think of this like with the weather: to predict the +temperature in January in Pittsburgh, PA, I might look at all previous +January's on record, average their temperatures, and include that in my +model. So it is important to \emph{align} the forecast horizon with the climate. +This step will work best if added after \code{step_epi_ahead()}, but that is not +strictly required. See the details for more information. +} +\details{ +Construction of a climate predictor can be helpful with strongly seasonal +data. But its utility is greatest when the estimated "climate" is aligned +to the forecast horizon. +For example, if today is December 1, and we want +to make a prediction for December 15, we want to know the climate for the +week of December 15 to use in our model. But we also want to align the rest +of our training data with the climate \emph{2 weeks after} those dates. + +To accomplish +this, if we have daily data, we could use \code{time_type = "week"} and +\code{forecast_ahead = 2}. The climate predictor would be created by taking +averages over each week (with a window of a few weeks before and after, as +determined by \code{window_size}), and then aligning these with the appropriate dates +in the training data so that each \code{time_value} will "see" the typical climate 2 +weeks in the future. + +Alternatively, in the same scenario, we could use \code{time_type = "day"} and +\code{forecast_ahead = 14}. The climate predictor would be created by taking +averages over a small window around each \emph{day}, and then aligning these with +the appropriate dates in the training data so that each \code{time_value} will +"see" the climate 14 days in the future. + +The only differences between these options is the type of averaging performed +over the historical data. In the first case, days in the same week will get +the same value of the climate predictor (because we're looking at weekly +windows), while in the second case, every day in the data will have the +average climate for the \emph{day} that happens 14 days in the future. + +Autodetecting the forecast horizon can only be guaranteed to work correctly +when the time types are the same: for example using daily data for training +and daily climate calculations. However, using weekly data, predicting 4 +weeks ahead, and setting \code{time_type = "month"} is perfectly reasonable. It's +just that the climate is calculated over \emph{months} (January, February, March, +etc.) so how to properly align this when producing a forecast for the 5th week +in the year is challenging. For scenarios like these, it may be best to +approximately match the times with \code{forecast_ahead = 1}, for example. +} +\examples{ +# automatically detects the horizon +r <- epi_recipe(covid_case_death_rates) \%>\% + step_epi_ahead(death_rate, ahead = 7) \%>\% + step_climate(death_rate, time_type = "day") +r + +r \%>\% + prep(covid_case_death_rates) \%>\% + bake(new_data = NULL) + +# same idea, but using weekly climate +r <- epi_recipe(covid_case_death_rates) \%>\% + step_epi_ahead(death_rate, ahead = 7) \%>\% + step_climate(death_rate, + forecast_ahead = 1, time_type = "epiweek", + window_size = 1L + ) +r + +r \%>\% + prep(covid_case_death_rates) \%>\% + bake(new_data = NULL) + +# switching the order is possible if you specify `forecast_ahead` +r <- epi_recipe(covid_case_death_rates) \%>\% + step_climate(death_rate, forecast_ahead = 7, time_type = "day") \%>\% + step_epi_ahead(death_rate, ahead = 7) +r + +r \%>\% + prep(covid_case_death_rates) \%>\% + bake(new_data = NULL) +} diff --git a/tests/testthat/_snaps/climatological_forecaster.md b/tests/testthat/_snaps/climatological_forecaster.md new file mode 100644 index 000000000..78043a20b --- /dev/null +++ b/tests/testthat/_snaps/climatological_forecaster.md @@ -0,0 +1,112 @@ +# climate args list validates properly + + Code + climate_args_list(forecast_date = 12345) + Condition + Error in `climate_args_list()`: + ! `forecast_date` must be a date. + +--- + + Code + climate_args_list(forecast_date = as.Date(c("2021-01-10", "2024-01-22"))) + Condition + Error in `climate_args_list()`: + ! `forecast_date` must be a scalar. + +--- + + Code + climate_args_list(forecast_horizon = 1.3) + Condition + Error in `climate_args_list()`: + ! `forecast_horizon` must be a integer. + +--- + + Code + climate_args_list(window_size = -1) + Condition + Error in `climate_args_list()`: + ! `window_size` must be a non-negative integer. + +--- + + Code + climate_args_list(window_size = 2.5) + Condition + Error in `climate_args_list()`: + ! `window_size` must be a non-negative integer. + +--- + + Code + climate_args_list(window_size = 1:3) + Condition + Error in `climate_args_list()`: + ! `window_size` must be a scalar. + +--- + + Code + climate_args_list(quantile_levels = -1) + Condition + Error in `climate_args_list()`: + ! `quantile_levels` must lie in [0, 1]. + +--- + + Code + climate_args_list(quantile_levels = 1.3) + Condition + Error in `climate_args_list()`: + ! `quantile_levels` must lie in [0, 1]. + +--- + + Code + climate_args_list(symmetrize = 2.5) + Condition + Error in `climate_args_list()`: + ! `symmetrize` must be of type . + +--- + + Code + climate_args_list(symmetrize = c(TRUE, TRUE)) + Condition + Error in `climate_args_list()`: + ! `symmetrize` must be a scalar. + +--- + + Code + climate_args_list(nonneg = 2.5) + Condition + Error in `climate_args_list()`: + ! `nonneg` must be of type . + +--- + + Code + climate_args_list(nonneg = c(TRUE, TRUE)) + Condition + Error in `climate_args_list()`: + ! `nonneg` must be a scalar. + +--- + + Code + climate_args_list(quantile_by_key = TRUE) + Condition + Error in `climate_args_list()`: + ! `quantile_by_key` must be of type . + +--- + + Code + climate_args_list(quantile_by_key = 2:3) + Condition + Error in `climate_args_list()`: + ! `quantile_by_key` must be of type . + diff --git a/tests/testthat/_snaps/snapshots.md b/tests/testthat/_snaps/snapshots.md index d1cf2df7c..855cbb457 100644 --- a/tests/testthat/_snaps/snapshots.md +++ b/tests/testthat/_snaps/snapshots.md @@ -1207,7 +1207,6 @@ * 56 unique geographic regions, * At forecast date: 2022-01-03, * For target date: 2022-01-10, - * Lags adjusted per column: case_rate=3, death_rate=3 --- @@ -1231,7 +1230,6 @@ * 56 unique geographic regions, * At forecast date: 2022-01-03, * For target date: 2022-01-10, - * Aheads adjusted for death_rate=3 # arx_classifier snapshots @@ -1286,3 +1284,1108 @@ 19001, 19001, 19001, 19001, 19001), class = "Date")), row.names = c(NA, -51L), class = c("tbl_df", "tbl", "data.frame")) +# climatological_forecaster snapshots + + structure(list(geo_value = c("ca", "fl", "ga", "ny", "pa", "tx", + "ca", "fl", "ga", "ny", "pa", "tx", "ca", "fl", "ga", "ny", "pa", + "tx", "ca", "fl", "ga", "ny", "pa", "tx", "ca", "fl", "ga", "ny", + "pa", "tx"), forecast_date = structure(c(18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992 + ), class = "Date"), target_date = structure(c(18992, 18992, 18992, + 18992, 18992, 18992, 18999, 18999, 18999, 18999, 18999, 18999, + 19006, 19006, 19006, 19006, 19006, 19006, 19013, 19013, 19013, + 19013, 19013, 19013, 19020, 19020, 19020, 19020, 19020, 19020 + ), class = "Date"), .pred = c(81.46212125, 48.9285099, 59.47903055, + 57.44900655, 62.78917715, 53.8558966, 84.3449863, 51.3826096, + 62.0540565, 67.1289331, 62.6712774, 59.47102, 92.3266162, 51.7816021, + 64.1929086, 67.80972325, 58.13744405, 63.10147305, 84.3449863, + 51.8545645, 66.9333338, 65.8523132, 55.9202576, 64.1234883, 59.50597115, + 48.9275239, 64.0481843, 63.45754255, 43.7883142, 65.37832155), + .pred_distn = structure(list(structure(list(values = c(55.01884375, + 61.9936534, 76.8558811, 85.8705552, 95.7238376875, 107.595355333333, + 124.8294820725), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(22.4852324, + 29.46004205, 44.32226975, 53.33694385, 63.1902263375, 75.0617439833333, + 92.2958707225), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(33.03575305, + 40.0105627, 54.8727904, 63.8874645, 73.7407469875, 85.6122646333333, + 102.8463913725), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(31.00572905, + 37.9805387, 52.8427664, 61.8574405, 71.7107229875, 83.5822406333333, + 100.8163673725), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(36.34589965, + 43.3207093, 58.182937, 67.1976111, 77.0508935875, 88.9224112333333, + 106.1565379725), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(27.4126191, + 34.38742875, 49.24965645, 58.26433055, 68.1176130375, 79.9891306833333, + 97.2232574225), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(59.1059257625, + 65.4267824, 80.893949775, 88.512741775, 98.9851218875, 111.446583986667, + 128.951180125), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(26.1435490625, + 32.4644057, 47.931573075, 55.550365075, 66.0227451875, 78.4842072866667, + 95.988803425), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(36.8149959625, + 43.1358526, 58.603019975, 66.221811975, 76.6941920875, 89.1556541866667, + 106.660250325), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(41.8898725625, + 48.2107292, 63.677896575, 71.296688575, 81.7690686875, 94.2305307866667, + 111.735126925), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(37.4322168625, + 43.7530735, 59.220240875, 66.839032875, 77.3114129875, 89.7728750866667, + 107.277471225), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(34.2319594625, + 40.5528161, 56.019983475, 63.638775475, 74.1111555875, 86.5726176866667, + 104.077213825), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(76.597008525, + 83.6285187166667, 89.8466094166667, 96.39787945, 106.5883326375, + 118.488928483333, 139.8972249625), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(36.051994425, 43.0835046166667, 49.3015953166667, + 55.85286535, 66.0433185375, 77.9439143833333, 99.3522108625 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(48.463300925, 55.4948111166667, + 61.7129018166667, 68.26417185, 78.4546250375, 90.3552208833333, + 111.7635173625), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(52.080115575, + 59.1116257666667, 65.3297164666667, 71.8809865, 82.0714396875, + 93.9720355333333, 115.3803320125), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(42.407836375, 49.4393465666667, 55.6574372666667, + 62.2087073, 72.3991604875, 84.2997563333333, 105.7080528125 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(47.371865375, 54.4033755666667, + 60.6214662666667, 67.1727363, 77.3631894875, 89.2637853333333, + 110.6720818125), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(75.151683565, + 78.2257355633333, 82.1485257708333, 87.28053515, 96.1483782208333, + 106.438732546667, 113.7276053175), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(42.661261765, 45.7353137633333, 49.6581039708333, + 54.79011335, 63.6579564208333, 73.9483107466667, 81.2371835175 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(57.740031065, 60.8140830633333, + 64.7368732708333, 69.86888265, 78.7367257208333, 89.0270800466667, + 96.3159528175), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(56.659010465, + 59.7330624633333, 63.6558526708333, 68.78786205, 77.6557051208333, + 87.9460594466667, 95.2349322175), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(46.726954865, 49.8010068633333, 53.7237970708333, + 58.85580645, 67.7236495208333, 78.0140038466667, 85.3028766175 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(54.930185565, 58.0042375633333, + 61.9270277708333, 67.05903715, 75.9268802208333, 86.2172345466667, + 93.5061073175), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(50.3425070425, + 53.1286383166667, 57.7775218541667, 61.6092566, 68.5981147666667, + 77.2595451983333, 81.44671049), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(39.7640597925, 42.5501910666667, 47.1990746041667, + 51.03080935, 58.0196675166667, 66.6810979483333, 70.86826324 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(54.8847201925, + 57.6708514666667, 62.3197350041667, 66.15146975, 73.1403279166667, + 81.8017583483333, 85.98892364), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(54.2940784425, 57.0802097166667, 61.7290932541667, + 65.560828, 72.5496861666667, 81.2111165983333, 85.39828189 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(34.6248500925, + 37.4109813666667, 42.0598649041667, 45.89159965, 52.8804578166667, + 61.5418882483333, 65.72905354), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(56.2148574425, 59.0009887166667, 63.6498722541667, + 67.481607, 74.4704651666667, 83.1318955983333, 87.31906089 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr"))), class = c("distribution", "vctrs_vctr", + "list"))), row.names = c(NA, -30L), class = c("tbl_df", "tbl", + "data.frame")) + +--- + + structure(list(geo_value = c("ca", "fl", "ga", "ny", "pa", "tx", + "ca", "fl", "ga", "ny", "pa", "tx", "ca", "fl", "ga", "ny", "pa", + "tx", "ca", "fl", "ga", "ny", "pa", "tx", "ca", "fl", "ga", "ny", + "pa", "tx"), forecast_date = structure(c(18779, 18779, 18779, + 18779, 18779, 18779, 18779, 18779, 18779, 18779, 18779, 18779, + 18779, 18779, 18779, 18779, 18779, 18779, 18779, 18779, 18779, + 18779, 18779, 18779, 18779, 18779, 18779, 18779, 18779, 18779 + ), class = "Date"), target_date = structure(c(18779, 18779, 18779, + 18779, 18779, 18779, 18786, 18786, 18786, 18786, 18786, 18786, + 18793, 18793, 18793, 18793, 18793, 18793, 18800, 18800, 18800, + 18800, 18800, 18800, 18807, 18807, 18807, 18807, 18807, 18807 + ), class = "Date"), .pred = c(1782, 927.5, 577.5, 935, 635, 1321, + 1791, 934.5, 561, 765.5, 529.5, 1435, 2153.5, 946.5, 607, 673, + 476, 1663.5, 2486.5, 1138, 659.5, 637.5, 446.5, 2002, 3236, 1311, + 879.5, 666.5, 446.5, 2964), .pred_distn = structure(list(structure(list( + values = c(512, 651.333333333334, 1098.45833333333, 1678, + 2429.04166666667, 3110.91666666667, 3621.875), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(0, 0, 365.541666666667, 927.5, 2329.29166666667, + 3263.83333333333, 3892.5), quantile_levels = c(0.05, 0.1, + 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(220.125, 253.166666666667, 342, 540.5, 733.375, + 854.166666666667, 977), quantile_levels = c(0.05, 0.1, 0.25, + 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(435.375, + 506.583333333333, 567.875, 776, 1103.75, 1465.83333333333, 1673.125 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(312.25, 377.833333333333, 453.416666666667, 584.25, + 726.541666666667, 1037.33333333333, 1516.5), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(149.5, 363.666666666667, 814.333333333333, 1149, + 2003.95833333333, 3254.66666666667, 3883.375), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(0, 450.083333333333, 924.75, 1670.5, 2544.375, + 3821.08333333334, 4407.25), quantile_levels = c(0.05, 0.1, + 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(0, 0, 6.41666666666674, 941.5, 2380.375, 4497.16666666667, + 9047.75), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(118.25, + 198.583333333333, 288.916666666667, 495.75, 736.625, 962, 1521.5 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(313.375, 350.166666666667, 409.083333333333, 597, + 860.791666666666, 1210.41666666667, 1353.25), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(206.75, 258.666666666667, 330.166666666667, 478.75, + 598.041666666667, 734.833333333333, 926.25), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(0, 281.083333333333, 790.666666666667, 1242.5, + 2162.125, 3593.5, 4306.625), quantile_levels = c(0.05, 0.1, + 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(0, 121.916666666668, 1184, 2179.25, 3261.875, + 4614.33333333333, 5419.75), quantile_levels = c(0.05, 0.1, + 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(0, 0, 11, 956, 2619, 8508.83333333334, 10103.25 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95 + )), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(0, 176.25, 306.791666666667, + 570, 839.958333333333, 1568.83333333333, 1901.25), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(238.125, 267.583333333333, 344.291666666667, 511.25, + 760.375, 1021.5, 1195), quantile_levels = c(0.05, 0.1, 0.25, + 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(147, + 190.5, 261.458333333333, 414, 545.458333333333, 664.583333333333, + 753.5), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(0, 72.3333333333335, + 931.041666666667, 1487.5, 2731.83333333333, 4390.16666666667, + 5059.5), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(0, 0, 1270.25, 2551, + 4018.70833333333, 5112.83333333333, 6004.375), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(0, 0, 175.541666666667, 1335.5, 4165.625, 8942.58333333333, + 11505.125), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(0, 0, + 321.458333333333, 564.75, 1010.20833333333, 1795, 2183.625), + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95 + )), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(225.125, 257.333333333333, + 342.708333333333, 551.25, 724.875, 924.416666666667, 1071.75), + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95 + )), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(106.125, 152.083333333333, + 221.166666666667, 363, 513.208333333333, 615.166666666667, 668 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(0, 125.166666666667, 943.833333333333, 1830, 3605.66666666667, + 5259.16666666667, 6957), quantile_levels = c(0.05, 0.1, 0.25, + 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(0, 559.25, + 1879.875, 3330.75, 4889, 6122.66666666667, 7629.625), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(0, 0, 158.583333333333, 1687.5, 5516.375, 9507.75, + 12672.375), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(0, 3.41666666666674, + 500.375, 817.000000000001, 1497.16666666667, 2102.08333333333, + 2451.5), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(286.5, 311.333333333333, + 399.166666666667, 629.75, 792.041666666667, 1015, 1111), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(92.125, 139.833333333333, 211.666666666667, 343.75, + 513.208333333333, 626, 714.25), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(0, 579.250000000001, 1838.75, 2963.25, 5057.91666666667, + 6361.33333333333, 7919), quantile_levels = c(0.05, 0.1, 0.25, + 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr"))), class = c("distribution", "vctrs_vctr", + "list"))), row.names = c(NA, -30L), class = c("tbl_df", "tbl", + "data.frame")) + +--- + + structure(list(geo_value = c("ca", "fl", "ga", "ny", "pa", "tx", + "ca", "fl", "ga", "ny", "pa", "tx", "ca", "fl", "ga", "ny", "pa", + "tx", "ca", "fl", "ga", "ny", "pa", "tx", "ca", "fl", "ga", "ny", + "pa", "tx", "ca", "fl", "ga", "ny", "pa", "tx", "ca", "fl", "ga", + "ny", "pa", "tx", "ca", "fl", "ga", "ny", "pa", "tx", "ca", "fl", + "ga", "ny", "pa", "tx", "ca", "fl", "ga", "ny", "pa", "tx", "ca", + "fl", "ga", "ny", "pa", "tx", "ca", "fl", "ga", "ny", "pa", "tx", + "ca", "fl", "ga", "ny", "pa", "tx", "ca", "fl", "ga", "ny", "pa", + "tx", "ca", "fl", "ga", "ny", "pa", "tx", "ca", "fl", "ga", "ny", + "pa", "tx", "ca", "fl", "ga", "ny", "pa", "tx", "ca", "fl", "ga", + "ny", "pa", "tx", "ca", "fl", "ga", "ny", "pa", "tx", "ca", "fl", + "ga", "ny", "pa", "tx", "ca", "fl", "ga", "ny", "pa", "tx", "ca", + "fl", "ga", "ny", "pa", "tx", "ca", "fl", "ga", "ny", "pa", "tx", + "ca", "fl", "ga", "ny", "pa", "tx", "ca", "fl", "ga", "ny", "pa", + "tx", "ca", "fl", "ga", "ny", "pa", "tx", "ca", "fl", "ga", "ny", + "pa", "tx", "ca", "fl", "ga", "ny", "pa", "tx", "ca", "fl", "ga", + "ny", "pa", "tx", "ca", "fl", "ga", "ny", "pa", "tx", "ca", "fl", + "ga", "ny", "pa", "tx"), forecast_date = structure(c(18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, 18992, + 18992, 18992, 18992, 18992), class = "Date"), target_date = structure(c(18992, + 18992, 18992, 18992, 18992, 18992, 18993, 18993, 18993, 18993, + 18993, 18993, 18994, 18994, 18994, 18994, 18994, 18994, 18995, + 18995, 18995, 18995, 18995, 18995, 18996, 18996, 18996, 18996, + 18996, 18996, 18997, 18997, 18997, 18997, 18997, 18997, 18998, + 18998, 18998, 18998, 18998, 18998, 18999, 18999, 18999, 18999, + 18999, 18999, 19000, 19000, 19000, 19000, 19000, 19000, 19001, + 19001, 19001, 19001, 19001, 19001, 19002, 19002, 19002, 19002, + 19002, 19002, 19003, 19003, 19003, 19003, 19003, 19003, 19004, + 19004, 19004, 19004, 19004, 19004, 19005, 19005, 19005, 19005, + 19005, 19005, 19006, 19006, 19006, 19006, 19006, 19006, 19007, + 19007, 19007, 19007, 19007, 19007, 19008, 19008, 19008, 19008, + 19008, 19008, 19009, 19009, 19009, 19009, 19009, 19009, 19010, + 19010, 19010, 19010, 19010, 19010, 19011, 19011, 19011, 19011, + 19011, 19011, 19012, 19012, 19012, 19012, 19012, 19012, 19013, + 19013, 19013, 19013, 19013, 19013, 19014, 19014, 19014, 19014, + 19014, 19014, 19015, 19015, 19015, 19015, 19015, 19015, 19016, + 19016, 19016, 19016, 19016, 19016, 19017, 19017, 19017, 19017, + 19017, 19017, 19018, 19018, 19018, 19018, 19018, 19018, 19019, + 19019, 19019, 19019, 19019, 19019, 19020, 19020, 19020, 19020, + 19020, 19020, 19021, 19021, 19021, 19021, 19021, 19021, 19022, + 19022, 19022, 19022, 19022, 19022), class = "Date"), .pred = c(37365.5, + 13147.5, 8167, 14747.5, 8757, 15877, 37403, 13147, 8596, 14791, + 8734, 15883, 37760.5, 13433.5, 8816, 15621, 8445.5, 16014, 37403, + 13720, 9036, 15393, 8394, 16433, 37760.5, 13795.5, 8816, 15092, + 8445.5, 16289, 38118, 13871, 9036, 14791, 8394, 16145, 37723, + 13795.5, 8816, 14747.5, 8289, 16289, 37328, 13720, 8596, 14704, + 7895, 16433, 37297.5, 13719.5, 8453.5, 14747.5, 7460, 16987, + 37328, 13720, 8596, 14791, 7313, 17694, 37297.5, 13719.5, 8790.5, + 14747.5, 7460, 17951, 37267, 13719, 8596, 14704, 7313, 18208, + 37161.5, 13296, 8564.5, 14445.5, 7106, 20697.5, 36895, 12873, + 8393, 14187, 6757, 19574, 36497.5, 12312, 8283.5, 14183, 6644, + 20962, 35263, 12119, 8150, 13909, 6531, 19574, 31371, 12311, + 8068, 13908, 5863, 19574, 29874, 12119, 8068, 13783, 5817, 19574, + 25888, 12119, 8068, 13783, 5817, 22350, 25816, 12119, 8068, 13783, + 5817, 22580, 24774, 11914, 7686, 13783, 5785, 22350, 24299, 11576, + 7629, 13694, 5662, 19574, 23250, 11543, 7454, 13410, 5632, 19112, + 23168, 11423, 7352, 12951, 5576, 19064, 21159, 11093, 6558, 12892, + 5497, 18191, 20459, 10976, 6384, 12721, 5379, 18191, 19778, 10533, + 6343, 12383, 5379, 18191, 19727, 9816, 6332, 11972, 5111, 17694, + 18581, 9594, 5706, 11492, 5058, 17565, 17672, 9535, 4961, 11209, + 4470, 16433, 17077, 8720, 4957, 11119, 4378, 15274), .pred_distn = structure(list( + structure(list(values = c(13505.6, 16257.7333333333, 26529.25, + 38488.5, 47803.5833333333, 52943, 54849.3), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(1798.7, 2451.95, 10271.125, 14631.5, 19124.5416666667, + 37913.2833333333, 77464.75), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(2147.4, 3752.65, 6336.54166666667, 9070.75, + 11484.9166666667, 14971.85, 24055.4), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(9205.975, 10792.0333333333, 12938.5, 15369.75, + 26851.9166666667, 51192.7333333333, 74599.425), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(4132.625, 5173.11666666667, 7461.91666666667, + 9054.75, 10303.375, 13200.8666666667, 17771.625), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(8787.125, 9949.68333333333, 12840.2916666667, + 15816.5, 21231.125, 25060.15, 28504.575), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(13359, 17130.6666666667, 28892.9166666667, + 38798, 46440.0833333333, 52838, 54064.5), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(1795, 2370, 10126.25, 14555, 18932.0833333333, + 39212.3333333334, 77512.5), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(2529.5, 4030, 7336.5, 9651, 11921.1666666667, + 15999.5, 24553), quantile_levels = c(0.05, 0.1, 0.25, + 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(9224.25, + 10790.3333333333, 12943, 15436.5, 27261.1666666667, 52706.3333333334, + 74960.25), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(4092.25, + 5132.16666666667, 7303.66666666667, 8989.5, 10295.75, 13271.6666666667, + 17869.75), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(9603.5, + 11103.6666666667, 13356.5, 15877, 21436.9166666667, 25184.5, + 28772.25), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(16185.7, + 19338.2, 30417.7916666667, 39255.25, 46966.4166666667, 52746.9333333333, + 54427.7), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(2078.3, + 2575.05, 10845.875, 14696, 19267.7916666667, 40798.3833333333, + 77847.25), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(2702.6, + 4977.35, 7662.25, 9719.75, 12149.25, 16818.15, 24841.6), + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(10029.025, 11575.1333333333, + 13744, 16202.25, 28511.875, 55006.4333333333, 76107.575), + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(3786.375, 4825.71666666667, + 6922.625, 8743.25, 10023.1666666667, 13076.9666666667, 17702.375 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95 + )), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(9716.8, 12099.6166666667, + 13831.75, 16236, 21678.0833333333, 25433.85, 29164.925), + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(15758.4, 18701.4, + 30977.3333333333, 38798, 46155.3333333333, 52291.8, 54173.4 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95 + )), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(2361.6, 2780.1, + 11444.8333333333, 14837, 19625.6666666667, 42384.4333333333, + 78182), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(3490.5, 5374.46666666667, + 7847, 10091, 12379, 17636.8, 25130.2), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(9775.8, 11301.9333333333, 13507, 15910, 27131.6666666667, + 56248.5333333333, 76196.9), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(3717.5, 4756.26666666667, 7224.66666666667, + 8649.5, 9988.66666666667, 13119.2666666667, 17772), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(11078.7, 12872.3333333333, 14339.6666666667, + 16883, 22316.3333333333, 25971.2, 29845.6), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(16326.8, 20830.8333333333, 32634.75, 38883.5, + 46655.2083333333, 52755.95, 54634.1), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(2433.9, 2774.15, 11421.2083333333, 15058, + 19772.5416666667, 43759.4833333333, 78305.75), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(3146.75, 5152.86666666667, 7268.75, 9719.75, + 12133.9166666667, 18015.45, 24978.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(9449.575, 10955.7333333333, 13283, 15523.25, + 24825.1666666666, 57417.6333333333, 76213.225), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(4012.9, 5440.66666666667, 7644.75, 8743.25, + 10057.1666666667, 13264.5666666667, 17944.625), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(7168.225, 12262.5166666667, 14176.6666666667, + 16511, 22391.5833333333, 25945.55, 29963.275), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(17412.3, 22308.8, 34428, 38969, 47155.0833333333, + 53220.1, 55094.8), quantile_levels = c(0.05, 0.1, 0.25, + 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(2506.2, + 4444.2, 11594.6666666667, 15279, 19919.4166666667, 45134.5333333333, + 78429.5), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(3243, + 5371.26666666667, 7776.5, 10091, 12361.1666666667, 18834.1, + 25267.4), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(9123.35, + 10609.5333333333, 12954.5, 15136.5, 20226.4166666667, 58586.7333333334, + 76229.55), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(3906.7, + 5242.66666666667, 7866.58333333333, 8649.5, 10022.6666666667, + 13306.8666666667, 18014.25), quantile_levels = c(0.05, 0.1, + 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(5065.8, 10541.3, 14013.6666666667, 16139, + 21698.9166666667, 24836.8, 30080.95), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(16960.25, 23946.75, 34087.8333333333, 38334.5, + 46928.9166666667, 52931.75, 54803), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(2427.5, 3658.75, 11472.7916666667, 15058, + 19629.7916666667, 46358.5833333334, 78402.25), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(2899.25, 5149.66666666667, 7495.25, 9506.5, + 12163.6666666667, 19212.75, 25116), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(9054.625, 10520.8333333333, 12870.5, 15092.25, + 19622.2916666667, 60013.3333333334, 76503.375), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(3747, 4991.16666666667, 7655.29166666667, + 8529.75, 9937.54166666667, 13295.6666666667, 18030.375 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(5186, 10631.25, + 14214.6666666667, 16511, 21953.0833333333, 25051.5, 30486.625 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95 + )), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(16277.2, 23612.3, + 34219.6666666667, 37700, 46755.6666666667, 52643.4, 54511.2 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95 + )), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(2348.8, 2873.3, + 11338.1666666667, 15017, 19428.8333333333, 47339.3666666666, + 78375), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(2555.5, 4928.06666666667, + 7162, 9117, 11738, 19591.4, 24964.6), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(8985.9, 10432.1333333333, 12980, 15048, 18340.1666666667, + 61439.9333333333, 76777.2), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(3298.3, 4450.66666666667, 7011.66666666667, + 8050, 9489.66666666667, 12995.4666666667, 17757.5), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(5306.2, 10508.4, 14723, 16883, 22316.3333333333, + 25275, 30892.3), quantile_levels = c(0.05, 0.1, 0.25, + 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(21211.45, + 28351.35, 35104.7916666667, 37619.5, 46709.625, 52688.85, + 54583.9), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(2345.1, + 2399.5, 11278.5416666667, 14926.5, 19001.6666666667, 32358.8166666666, + 74049.6499999998), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(2289.25, + 4771.45, 6906.25, 8946.5, 10652.625, 19977.2166666667, 24890.7 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95 + )), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(9004.175, 10411.75, + 12967.25, 15034.25, 17727.1666666667, 62772.8333333333, 77138.025 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95 + )), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(2808.6, 3912.01666666667, + 6327.04166666667, 7521.5, 8971.58333333333, 12715.05, 17443.625 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95 + )), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(5836.4, 10729.7166666667, + 15191.2916666667, 18142.75, 23089.5833333333, 25927.9166666667, + 31707.975), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(23944.6, + 31138.5333333333, 36280.1666666667, 38179, 47104.25, 52733.9, + 54717.6), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(3052.35, + 9589.2, 11699.75, 15017, 19227.6666666667, 34023.7666666667, + 75556.1), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(4574.65, + 4940.86666666667, 7336.5, 9224.5, 11000.25, 20507.3666666667, + 25101.8), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(9577.75, + 10880.7333333333, 13239.8333333333, 15308, 17811.6666666667, + 63744.3333333333, 77498.85), quantile_levels = c(0.05, 0.1, + 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(2606.9, 3747.06666666667, 6793.75, 7468, 8860.83333333333, + 12844.2, 17417.75), quantile_levels = c(0.05, 0.1, 0.25, + 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(6519.6, + 10972.3666666667, 15734.9166666667, 19251.5, 24015.8333333333, + 26772.6666666667, 32676.65), quantile_levels = c(0.05, 0.1, + 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(30143.55, 32933, 36254.9166666667, 38288.5, + 45981.375, 51866.35, 54783.025), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(9504.175, 10087.8, 12112.75, 14926.5, 18563.375, + 35687.7166666666, 77061.5499999999), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(5122.3, 5440.33333333333, 7636.75, 9481, 11397.25, + 21089.5166666666, 25364.9), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(9483.625, 10792.0333333333, 13636.5833333333, + 15178.75, 17645.1666666667, 51192.7333333332, 71279.5 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(2699.2, 3876.11666666667, + 7081.375, 7650.5, 9037.66666666667, 13267.35, 17685.875), + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(6752.8, 10373.6333333333, + 16482.0416666667, 19689.25, 24420.75, 27167.4166666667, 33195.325 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95 + )), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(30054, 32846.3333333333, + 36222.6666666667, 38118, 44345.5, 51942.5, 54863), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(9602, 10479.6666666667, 11966, 14836, 18000.6666666667, + 37351.6666666666, 78566.9999999998), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(4943, 5436, 7407, 9224.5, 10590, 15999.5, + 23867), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(10402, + 11313.3333333333, 13850.6666666667, 15049.5, 17181.3333333333, + 52619.3333333333, 71699.9999999999), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(2497.5, 4747.66666666667, 6887.5, 7468, 8788.33333333333, + 13396.5, 17660), quantile_levels = c(0.05, 0.1, 0.25, + 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(6353, + 7303.33333333333, 16575.6666666667, 20127, 24683, 27562.1666666667, + 33714), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(30609, 33678.5333333333, + 36115.4166666667, 38152.5, 44796.5, 51943.65, 54882.775), + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(8727.5, 10506.25, + 11801.125, 14298.5, 17316.75, 38593.1166666666, 80240.5749999997 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95 + )), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(5286.75, 5818.43333333333, + 7427.5, 9255, 10477.2083333333, 16246.2, 23904.1), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(10572.9, 11566.1333333333, 13513.9166666667, + 14732.25, 16706.1666666667, 38273.0999999999, 71758.825 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(3500.325, 5164.43333333333, + 6782.58333333333, 7167.5, 8370.08333333333, 12298.8833333333, + 17550.65), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(8782.15, + 9745.23333333333, 18901.7916666667, 23672.5, 27843.3333333333, + 30189.4166666667, 38204.6499999997), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(29822, 33388.7333333333, 35722.6666666667, + 37746, 45086.5, 51783.8, 54741.55), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(7853, 10025.5, 11340, 13761, 16558.5833333333, + 25362.8666666667, 81914.1500000001), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(5095.5, 5582.53333333333, 7253, 8914, 10045.1666666667, + 12628.6, 23801.2), quantile_levels = c(0.05, 0.1, 0.25, + 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(10957.1, + 11891.6666666667, 13177.1666666667, 14415, 16394.8333333333, + 19398.1666666667, 71817.65), quantile_levels = c(0.05, 0.1, + 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(3087.65, 4791.53333333333, 6409.83333333333, + 6725, 7740.16666666667, 9516.13333333334, 17299.3), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(7598.3, 8574.13333333334, 17622.3333333333, + 22350, 26059.5, 28098, 39082.3000000001), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(32519.95, 33308.7333333333, 35436.1666666667, + 37488.5, 43019.5, 50277.7666666667, 52591.25), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(6840.5, 9406.75, 10705.25, 13314.5, 14638.9583333333, + 18303.3166666667, 43700.7499999999), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(4966.25, 5408.63333333333, 7129.75, 8776.5, + 9930.33333333333, 11747.7666666667, 14690.275), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(10918.65, 11891.1666666667, 13407.9166666667, + 14469.75, 16427.6666666667, 18348.5166666667, 28410.3749999999 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(2910.975, 4654.63333333333, + 6265.375, 6571.5, 7712.58333333333, 8852.8, 11127.4), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(8925.95, 9914.53333333333, 18804.5833333333, + 23309.5, 27544.8333333333, 29565.5, 42471.4499999999), + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(31164.6, 32021.5333333333, + 34218.6666666667, 36394, 41517.8333333333, 47717.1333333333, + 49796.3), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(6196, + 9156, 10366, 13007, 13878.6666666667, 17648.3, 20612.7), + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(4813, 5210.73333333333, + 6961, 8615, 9759, 10560.0666666667, 11782.5), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(10610.2, 11515.6666666667, 13055.6666666667, + 14137, 16014.3333333333, 16913.2666666667, 18871), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(2734.3, 4517.73333333333, 6168.83333333333, + 6499, 7697.33333333333, 8782.4, 9804.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(7477.6, 8478.93333333333, 17148.3333333333, + 22205, 26049, 27669.7333333333, 29791.2), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(27272.6, 28129.5333333333, 30326.6666666667, + 32502, 36595, 42381.4666666667, 45904.3), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(8994, 9834.56666666667, 10853, 13428, 14255.6666666667, + 18330.8666666667, 20967.1), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(4731, 5128.73333333333, 6879, 8533, 9524.33333333333, + 10012.9333333333, 11700.5), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(10609.2, 11514.6666666667, 13054.6666666667, + 14136, 15769, 16912.2666666667, 18870), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(2066.3, 3849.73333333333, 5500.83333333333, + 6018, 7084.66666666667, 8114.4, 9136.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(7477.6, 8478.93333333333, 17148.3333333333, + 22350, 26049, 27669.7333333333, 29791.2), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(25775.6, 26632.5333333333, 28829.6666666667, + 30725, 33217, 40884.4666666667, 44407.3), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(8802, 9642.56666666667, 10661, 13007, 13878.6666666667, + 17648.3, 18255.6), quantile_levels = c(0.05, 0.1, 0.25, + 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(4731, + 5128.73333333333, 6861, 8533, 9524.33333333333, 10012.9333333333, + 11700.5), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(10484.2, + 11389.6666666667, 12929.6666666667, 13997, 15644, 16787.2666666667, + 18745), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(2020.3, 3803.73333333333, + 5559, 5972, 7038.66666666667, 8068.4, 9090.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(7477.6, 9930.13333333334, 17199.3333333333, + 22350, 26049, 27669.7333333333, 29791.2), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(22459.4, 23246.3333333333, 24843.6666666667, + 26739, 29231, 36898.4666666667, 40421.3), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(9153.2, 9642.56666666667, 10661, 13007, 13878.6666666667, + 17648.3, 18255.6), quantile_levels = c(0.05, 0.1, 0.25, + 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(4848.6, + 5776.73333333333, 6861, 8533, 9524.33333333333, 10012.9333333333, + 11700.5), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(10881.8, + 12145.2, 12929.6666666667, 13997, 15644, 16787.2666666667, + 18745), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(3192.3, 4022.2, + 5559, 5972, 7038.66666666667, 8068.4, 9090.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(10253.6, 12706.1333333333, 19975.3333333333, + 25706, 29214.3333333333, 31033, 38341.6), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(22387.4, 23065, 24717.6666666667, 26667, 29159, + 36826.4666666667, 40349.3), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(9153.2, 9828.53333333333, 10712, 13236, 14046.6666666667, + 17648.3, 18255.6), quantile_levels = c(0.05, 0.1, 0.25, + 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(5472.2, + 6260.8, 6934, 8533, 9524.33333333333, 10012.9333333333, 11700.5 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95 + )), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(11600.6, 12145.2, + 12929.6666666667, 13997, 15644, 16787.2666666667, 18745), + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(3931.2, 4163.66666666667, + 5559, 5972, 7038.66666666667, 8068.4, 9090.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(10483.6, 12936.1333333333, 20205.3333333333, + 26048, 30210.6666666667, 31670.8, 38571.6), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(21345.4, 22418.3333333333, 23729.6666666667, + 25625, 28117, 35784.4666666667, 39307.3), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(8948.2, 9623.53333333333, 10507, 12802, 13841.6666666667, + 17443.3, 18050.6), quantile_levels = c(0.05, 0.1, 0.25, + 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(5090.2, + 5878.8, 6552, 8120, 9142.33333333333, 9630.93333333333, 11318.5 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95 + )), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(11098, 11842.3333333333, + 12929.6666666667, 13997, 15644, 16787.2666666667, 18745), + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(3899.2, 4131.66666666667, + 5500.33333333333, 5753, 7006.66666666667, 8036.4, 9058.8), + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(10253.6, 12706.1333333333, + 19975.3333333333, 25818, 29214.3333333333, 31033, 33266.4 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95 + )), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(20870.4, 21943.3333333333, + 23254.6666666667, 25150, 27642, 35309.4666666667, 38832.3 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95 + )), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(8610.2, 9285.53333333333, + 10169, 11576, 13335.6666666667, 17105.3, 17712.6), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(5033.2, 5821.8, 6850, 8094, 9179.33333333333, + 9573.93333333333, 11261.5), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(11009, 11228.6666666667, 12538.3333333333, + 13863, 15555, 16698.2666666667, 18656), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(3776.2, 4008.66666666667, 5284, 5549, 6725.66666666667, + 7913.4, 8935.8), quantile_levels = c(0.05, 0.1, 0.25, + 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(7477.6, + 9930.13333333334, 17199.3333333333, 22930, 26049, 28257, + 30490.4), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(19821.4, + 20894.3333333333, 22205.6666666667, 23879, 25537.3333333333, + 32287, 35424.1), quantile_levels = c(0.05, 0.1, 0.25, 0.5, + 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(8577.2, + 9252.53333333333, 10136, 11543, 13302.6666666667, 16077.6666666667, + 17451.2), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(4858.2, + 5646.8, 6675, 7919, 9004.33333333333, 9398.93333333333, 11086.5 + ), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95 + )), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(10725, 10944.6666666667, + 12245.6666666667, 13414, 15162.3333333333, 16256.1333333333, + 18372), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(3746.2, 3978.66666666667, + 5254, 5519, 6695.66666666667, 7883.4, 8905.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(7015.6, 9468.13333333334, 16737.3333333333, + 21888, 24995.3333333333, 27790.7333333333, 30028.4), + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(19739.4, 20812.3333333333, + 22123.6666666667, 23797, 25455.3333333333, 29471.8333333333, + 33457.4), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(8457.2, + 9132.53333333333, 10016, 11423, 13064.6666666667, 14882.3333333333, + 16487.6), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(4756.2, + 5544.8, 6573, 7817, 8785, 9005.33333333333, 9658), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(10266, 10485.6666666667, 11786.6666666667, + 12955, 14703.3333333333, 15439.2666666667, 16501.4), + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(3690.2, 3922.66666666667, + 5198, 5463, 6255.33333333333, 7378.46666666667, 8258.6), + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(6967.6, 9420.13333333334, + 16689.3333333333, 21695, 24506.6666666667, 27742.7333333333, + 29980.4), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, + 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(17730.4, + 18803.3333333333, 20114.6666666667, 21531, 23113, 26977, + 28232), quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(8127.2, 8802.53333333333, + 9686, 11042, 12587, 14552.3333333333, 16157.6), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(3962.2, 4750.8, 5779, 6992, 7636.66666666667, + 8200.53333333333, 8292.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(10207, 10426.6666666667, 11727.6666666667, + 12896, 14513, 15178.4666666667, 16052), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(3611.2, 3843.66666666667, 5119, 5384, 6039.33333333333, + 6873.33333333333, 7838.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(6094.6, 8547.13333333334, 15152, 20127, 23361.1666666667, + 26869.7333333333, 29107.4), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(17030.4, 18103.3333333333, 19360.6666666667, + 20459, 22413, 26277, 27532), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(8010.2, 8685.53333333333, 9518, 10925, 12470, + 14435.3333333333, 16040.6), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(3788.2, 4576.8, 5325.33333333333, 6818, 7462.66666666667, + 8026.53333333333, 8118.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(10036, 10255.6666666667, 11556.6666666667, + 12725, 14080.3333333333, 15007.4666666667, 15881), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(3493.2, 3725.66666666667, 4809, 5266, 5921.33333333333, + 6755.33333333333, 7720.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(6094.6, 8547.13333333334, 14977.6666666667, + 20127, 23361.1666666667, 26869.7333333333, 29107.4), + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(16349.4, 17422.3333333333, + 18679.6666666667, 19778, 21732, 25596, 26851), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(7567.2, 8242.53333333333, 9379.66666666667, + 10482, 12027, 13992.3333333333, 15597.6), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(3747.2, 4535.8, 5711.33333333333, 6777, 7421.66666666667, + 7985.53333333333, 8077.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(9698, 9917.66666666667, 11218.6666666667, + 12387, 13742.3333333333, 14669.4666666667, 15543), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(3670.6, 3908, 5001, 5347, 6121.66666666667, + 6755.33333333333, 7720.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(6094.6, 8547.13333333334, 15152, 20127, 23361.1666666667, + 26869.7333333333, 29107.4), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(16298.4, 17371.3333333333, 18628.6666666667, + 19727, 21681, 25545, 26800), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(6850.2, 7525.53333333333, 8662.66666666667, + 9765, 11235, 13275.3333333333, 14880.6), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(3736.2, 4524.8, 5700.33333333333, 6714, 7410.66666666667, + 7974.53333333333, 8066.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(9287, 9506.66666666667, 10599, 11883, 13331.3333333333, + 14258.4666666667, 15132), quantile_levels = c(0.05, 0.1, + 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(3402.6, 3640, 4733, 4998, 5853.66666666667, + 6487.33333333333, 7452.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(5597.6, 8050.13333333334, 14655, 19574, 21943, + 26372.7333333333, 28610.4), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(15152.4, 16225.3333333333, 17482.6666666667, + 18581, 20535, 24399, 25654), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(6628.2, 7303.53333333333, 8440.66666666667, + 9543, 11013, 13053.3333333333, 14658.6), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(3110.2, 3898.8, 5074.33333333333, 6140, 6784.66666666667, + 7348.53333333333, 7440.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(8807, 9026.66666666667, 10119, 11403, 13193.3333333333, + 13778.4666666667, 14652), quantile_levels = c(0.05, 0.1, + 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(3349.6, 3587, 4680, 4945, 5712.66666666667, + 6263.53333333333, 7399.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(5468.6, 7921.13333333334, 14526, 19172, 21297.6666666667, + 26243.7333333333, 28481.4), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(14243.4, 15316.3333333333, 16573.6666666667, + 17672, 19117.3333333333, 21921.5333333333, 24647), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(6569.2, 7244.53333333333, 8381.66666666667, + 9484, 10946.6666666667, 12994.3333333333, 14599.6), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(2365.2, 3153.8, 4329.33333333333, 5343, 6039.66666666667, + 6603.53333333333, 6695.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(8524, 8743.66666666667, 9836, 11120, 12910.3333333333, + 13495.4666666667, 14369), quantile_levels = c(0.05, 0.1, + 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(2761.6, 2999, 4092, 4438, 5124.66666666667, + 5675.53333333333, 6811.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(4336.6, 6789.13333333334, 13394, 17898, 20165.6666666667, + 25111.7333333333, 27349.4), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(13648.4, 14721.3333333333, 15978.6666666667, + 17077, 18266, 19933.0666666667, 22864), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(5754.2, 6429.53333333333, 7566.66666666667, + 8669, 10050.3333333333, 10882.4, 13120.6), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(2361.2, 3149.8, 4325.33333333333, 5270, 5878.66666666667, + 6580.4, 6683.8), quantile_levels = c(0.05, 0.1, 0.25, + 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", "dist_default", + "vctrs_rcrd", "vctrs_vctr")), structure(list(values = c(8434, + 8653.66666666667, 9746, 11030, 12458, 13329.8, 13463.8), + quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, + 0.95)), class = c("dist_quantiles", "dist_default", "vctrs_rcrd", + "vctrs_vctr")), structure(list(values = c(2669.6, 2907, 4000, + 4346, 5032.66666666667, 5583.53333333333, 6719.8), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr")), structure(list( + values = c(3177.6, 5630.13333333334, 12235, 16653, 18812.6666666667, + 23952.7333333333, 26190.4), quantile_levels = c(0.05, + 0.1, 0.25, 0.5, 0.75, 0.9, 0.95)), class = c("dist_quantiles", + "dist_default", "vctrs_rcrd", "vctrs_vctr"))), class = c("distribution", + "vctrs_vctr", "list"))), row.names = c(NA, -186L), class = c("tbl_df", + "tbl", "data.frame")) + diff --git a/tests/testthat/_snaps/step_adjust_latency.md b/tests/testthat/_snaps/step_adjust_latency.md index 70ca51b4f..cffb72703 100644 --- a/tests/testthat/_snaps/step_adjust_latency.md +++ b/tests/testthat/_snaps/step_adjust_latency.md @@ -13,7 +13,7 @@ time_value: 1 -- Operations - 1. extend_lags: case_rate with latency set at train time + 1. Adj. extend_lags: has_role("raw") latency TBD at train time 2. Lagging: death_rate by 0, 6, 11 3. Lagging: case_rate by 1, 5 4. Leading: death_rate by 7 @@ -36,8 +36,8 @@ Training data contained 200 data points and no incomplete rows. -- Operations - 1. extend_lags: case_rate with forecast date 2021-07-24 | Trained - 2. Lagging: death_rate by 0, 6, 11, (lat adj) | Trained + 1. Adj. extend_lags: case_rate death_rate w/ forecast date 2021-07-24 | Trained + 2. Lagging: death_rate by 5, 11, 16, (lat adj) | Trained 3. Lagging: case_rate by 6, 10, (lat adj) | Trained 4. Leading: death_rate by 7 | Trained @@ -57,7 +57,7 @@ -- Operations 1. Lagging: death_rate by 0, 7, 14 - 2. extend_ahead: all future predictors with latency set at train time + 2. Adj. extend_ahead: has_role("raw") latency TBD at train time 3. Leading: death_rate by 7 --- @@ -79,6 +79,6 @@ -- Operations 1. Lagging: death_rate by 0, 7, 14 | Trained - 2. extend_ahead: case_rate, ... with forecast date 2023-03-10 | Trained + 2. Adj. extend_ahead: case_rate, ... w/ forecast date 2023-03-10 | Trained 3. Leading: death_rate by -441, (lat adj) | Trained diff --git a/tests/testthat/test-climatological_forecaster.R b/tests/testthat/test-climatological_forecaster.R new file mode 100644 index 000000000..24f99c26f --- /dev/null +++ b/tests/testthat/test-climatological_forecaster.R @@ -0,0 +1,52 @@ +test_that("climate args list validates properly", { + expect_s3_class(climate_args_list(), c("climate_fcast", "alist")) + expect_s3_class( + climate_args_list(forecast_date = as.Date("2021-01-10")), + c("climate_fcast", "alist") + ) + expect_snapshot(error = TRUE, climate_args_list(forecast_date = 12345)) + expect_snapshot( + error = TRUE, + climate_args_list(forecast_date = as.Date(c("2021-01-10", "2024-01-22"))) + ) + expect_silent(climate_args_list(forecast_horizon = 1L)) + expect_silent(climate_args_list(forecast_horizon = -1:4)) + expect_snapshot(error = TRUE, climate_args_list(forecast_horizon = 1.3)) + expect_snapshot(error = TRUE, climate_args_list(window_size = -1)) + expect_snapshot(error = TRUE, climate_args_list(window_size = 2.5)) + expect_snapshot(error = TRUE, climate_args_list(window_size = 1:3)) + expect_snapshot(error = TRUE, climate_args_list(quantile_levels = -1)) + expect_snapshot(error = TRUE, climate_args_list(quantile_levels = 1.3)) + expect_snapshot(error = TRUE, climate_args_list(symmetrize = 2.5)) + expect_snapshot(error = TRUE, climate_args_list(symmetrize = c(TRUE, TRUE))) + expect_snapshot(error = TRUE, climate_args_list(nonneg = 2.5)) + expect_snapshot(error = TRUE, climate_args_list(nonneg = c(TRUE, TRUE))) + expect_snapshot(error = TRUE, climate_args_list(quantile_by_key = TRUE)) + expect_snapshot(error = TRUE, climate_args_list(quantile_by_key = 2:3)) +}) + +test_that("climatological_forecaster works as expected", { + single_yr <- seq(as.Date("2020-01-01"), as.Date("2020-12-31"), by = "1 day") + x <- tibble( + time_value = rep(single_yr, times = 2L), + geo_value = rep(c("reg1", "reg2"), each = length(single_yr)), + y = rep(c(1:183, 184:2), times = 2L) + ) %>% + as_epi_df(as_of = max(single_yr)) + clim_forecast <- climatological_forecaster(x, "y", args_list = climate_args_list(time_type = "day")) + preds <- clim_forecast$predictions %>% + mutate( + quant_med = median(.pred_distn) + ) + expect_equal(preds$.pred, preds$quant_med) + + expected_res <- tibble( + geo_value = rep(c("reg1", "reg2"), 5), + forecast_date = as.Date("2020-12-31"), + target_date = c( + rep(as.Date("2020-12-31"), 2), rep(as.Date("2021-01-01"), 2), rep(as.Date("2021-01-02"), 2), rep(as.Date("2021-01-03"), 2), rep(as.Date("2021-01-04"), 2) + ), + .pred = c(rep(3, 8), rep(4, 2)) + ) + expect_equal(preds %>% select(geo_value, forecast_date, target_date, .pred), expected_res) +}) diff --git a/tests/testthat/test-layer_add_forecast_date.R b/tests/testthat/test-layer_add_forecast_date.R index 8bf452a81..3beb87dc9 100644 --- a/tests/testthat/test-layer_add_forecast_date.R +++ b/tests/testthat/test-layer_add_forecast_date.R @@ -77,7 +77,7 @@ test_that("`layer_add_forecast_date()` infers correct date when using `adjust_la attributes(jhu_reasonable_date)$metadata$as_of <- as.Date("2022-01-03") r_latent <- epi_recipe(jhu_reasonable_date) %>% step_epi_lag(death_rate, lag = c(0, 7, 14)) %>% - step_adjust_latency(method = "extend_ahead") %>% + step_adjust_latency(death_rate, method = "extend_ahead") %>% step_epi_ahead(death_rate, ahead = 7) %>% step_naomit(all_predictors()) %>% step_naomit(all_outcomes(), skip = TRUE) diff --git a/tests/testthat/test-snapshots.R b/tests/testthat/test-snapshots.R index 8b2ae838c..eb0439c10 100644 --- a/tests/testthat/test-snapshots.R +++ b/tests/testthat/test-snapshots.R @@ -185,3 +185,32 @@ test_that("arx_classifier snapshots", { class = "epipredict__arx_classifier__adjust_latency_unsupported_method" ) }) + +test_that("climatological_forecaster snapshots", { + rates <- cases_deaths_subset + + # set as_of to the last day in the data + attr(rates, "metadata")$as_of <- as.Date("2021-12-31") + fcast <- climatological_forecaster(rates, "case_rate_7d_av") + expect_snapshot_tibble(fcast$predictions) + + # Compute quantiles separately by location, and a backcast + backcast <- climatological_forecaster( + rates, "cases", + climate_args_list( + quantile_by_key = "geo_value", + forecast_date = as.Date("2021-06-01") + ) + ) + expect_snapshot_tibble(backcast$predictions) + # compute the climate "daily" rather than "weekly" + # use a two week window (on both sides) + daily_fcast <- climatological_forecaster( + rates, "cases", + climate_args_list( + quantile_by_key = "geo_value", + time_type = "day", window_size = 14L, forecast_horizon = 0:30 + ) + ) + expect_snapshot_tibble(daily_fcast$predictions) +}) diff --git a/tests/testthat/test-step_adjust_latency.R b/tests/testthat/test-step_adjust_latency.R index 7b1f320e4..1e9127bbe 100644 --- a/tests/testthat/test-step_adjust_latency.R +++ b/tests/testthat/test-step_adjust_latency.R @@ -42,10 +42,10 @@ attributes(x_lagged)$metadata$as_of <- testing_as_of test_that("epi_adjust_latency correctly extends the lags", { expect_warning(epi_recipe(x) %>% step_epi_lag(death_rate, lag = c(0, 6, 11)) %>% - step_adjust_latency(method = "extend_lags")) + step_adjust_latency(death_rate, method = "extend_lags")) r1 <- epi_recipe(x) %>% - step_adjust_latency(method = "extend_lags") %>% + step_adjust_latency(death_rate, case_rate, method = "extend_lags") %>% step_epi_lag(death_rate, lag = c(0, 6, 11)) %>% step_epi_lag(case_rate, lag = c(1, 5)) %>% step_epi_ahead(death_rate, ahead = ahead) @@ -130,7 +130,7 @@ test_that("epi_adjust_latency correctly extends the lags", { test_that("epi_adjust_latency correctly extends the ahead", { r2 <- epi_recipe(x) %>% - step_adjust_latency(method = "extend_ahead") %>% + step_adjust_latency(death_rate, method = "extend_ahead") %>% step_epi_lag(death_rate, lag = c(0, 6, 11)) %>% step_epi_lag(case_rate, lag = c(1, 5)) %>% step_epi_ahead(death_rate, ahead = ahead) @@ -175,7 +175,7 @@ test_that("epi_adjust_latency correctly extends the ahead", { test_that("epi_adjust_latency correctly locfs", { r1 <- epi_recipe(x) %>% - step_adjust_latency(method = "locf") %>% + step_adjust_latency(has_role("raw"), method = "locf") %>% step_epi_lag(death_rate, lag = c(0, 6, 11)) %>% step_epi_lag(case_rate, lag = c(1, 5)) %>% step_epi_ahead(death_rate, ahead = ahead) @@ -228,7 +228,7 @@ test_that("epi_adjust_latency correctly locfs", { test_that("epi_adjust_latency extends multiple aheads", { aheads <- 1:3 r3 <- epi_recipe(x) %>% - step_adjust_latency(method = "extend_ahead") %>% + step_adjust_latency(death_rate, method = "extend_ahead") %>% step_epi_lag(death_rate, lag = c(0, 6, 11)) %>% step_epi_lag(case_rate, lag = c(1, 5)) %>% step_epi_ahead(death_rate, ahead = aheads) @@ -285,7 +285,7 @@ test_that("epi_adjust_latency extends multiple aheads", { test_that("epi_adjust_latency fixed_forecast_date works", { r4 <- epi_recipe(x) %>% - step_adjust_latency(method = "extend_lags", fixed_forecast_date = max_time + 14) %>% + step_adjust_latency(has_role("raw"), method = "extend_lags", fixed_forecast_date = max_time + 14) %>% step_epi_lag(death_rate, lag = c(0, 6, 11)) %>% step_epi_lag(case_rate, lag = c(1, 5)) %>% step_epi_ahead(death_rate, ahead = ahead) @@ -316,7 +316,7 @@ test_that("epi_adjust_latency fixed_forecast_date works", { test_that("epi_adjust_latency fixed_latency works", { r4.1 <- epi_recipe(x) %>% - step_adjust_latency(method = "extend_lags", fixed_latency = 2) %>% + step_adjust_latency(has_role("raw"), method = "extend_lags", fixed_latency = 2) %>% step_epi_lag(death_rate, lag = c(0, 6, 11)) %>% step_epi_lag(case_rate, lag = c(1, 5)) %>% step_epi_ahead(death_rate, ahead = ahead) @@ -357,13 +357,13 @@ test_that("epi_adjust_latency warns there's steps before it", { expect_warning( r5 <- epi_recipe(x) %>% step_epi_lag(death_rate, lag = c(0, 6, 11)) %>% - step_adjust_latency(method = "extend_lags"), + step_adjust_latency(death_rate, method = "extend_lags"), regexp = "extend_lags" ) expect_warning( r5 <- epi_recipe(x) %>% step_epi_ahead(death_rate, ahead = ahead) %>% - step_adjust_latency(method = "extend_ahead"), + step_adjust_latency(death_rate, method = "extend_ahead"), regexp = "extend_ahead" ) }) @@ -375,7 +375,7 @@ test_that("epi_adjust_latency warns there's steps before it", { test_that("epi_adjust_latency correctly extends the lags when there are different delays per-geo", { r5 <- epi_recipe(x_lagged) %>% - step_adjust_latency(method = "extend_lags") %>% + step_adjust_latency(has_role("raw"), method = "extend_lags") %>% step_epi_lag(death_rate, lag = c(0, 6, 11)) %>% step_epi_lag(case_rate, lag = c(1, 5)) %>% step_epi_ahead(death_rate, ahead = ahead) @@ -417,7 +417,7 @@ test_that("epi_adjust_latency correctly extends the lags when there are differen test_that("epi_adjust_latency correctly extends the ahead when there are different delays per-geo", { r5 <- epi_recipe(x_lagged) %>% - step_adjust_latency(method = "extend_ahead") %>% + step_adjust_latency(death_rate, method = "extend_ahead") %>% step_epi_lag(death_rate, lag = c(0, 6, 11)) %>% step_epi_lag(case_rate, lag = c(1, 5)) %>% step_epi_ahead(death_rate, ahead = ahead) @@ -502,7 +502,7 @@ test_that("`step_adjust_latency` only uses the columns specified in the `...`", test_that("printing step_adjust_latency results in expected output", { r5 <- epi_recipe(x) %>% - step_adjust_latency(case_rate, method = "extend_lags") %>% + step_adjust_latency(has_role("raw"), method = "extend_lags") %>% step_epi_lag(death_rate, lag = c(0, 6, 11)) %>% step_epi_lag(case_rate, lag = c(1, 5)) %>% step_epi_ahead(death_rate, ahead = ahead) @@ -510,7 +510,7 @@ test_that("printing step_adjust_latency results in expected output", { expect_snapshot(prep(r5, real_x)) r6 <- epi_recipe(covid_case_death_rates) %>% step_epi_lag(death_rate, lag = c(0, 7, 14)) %>% - step_adjust_latency(method = "extend_ahead") %>% + step_adjust_latency(has_role("raw"), method = "extend_ahead") %>% step_epi_ahead(death_rate, ahead = 7) expect_snapshot(r6) expect_snapshot(prep(r6, covid_case_death_rates)) @@ -519,10 +519,10 @@ test_that("printing step_adjust_latency results in expected output", { test_that("locf works as intended", { expect_warning(epi_recipe(x) %>% step_epi_lag(death_rate, lag = c(0, 6, 11)) %>% - step_adjust_latency(method = "locf")) + step_adjust_latency(death_rate, method = "locf")) r6 <- epi_recipe(x) %>% - step_adjust_latency(method = "locf") %>% + step_adjust_latency(has_role("raw"), method = "locf") %>% step_epi_lag(death_rate, lag = c(0, 6, 11)) %>% step_epi_lag(case_rate, lag = c(1, 5)) %>% step_epi_ahead(death_rate, ahead = ahead) diff --git a/tests/testthat/test-step_climate.R b/tests/testthat/test-step_climate.R new file mode 100644 index 000000000..3dca9ec67 --- /dev/null +++ b/tests/testthat/test-step_climate.R @@ -0,0 +1,249 @@ +test_that("yday_leap works", { + # feburary 29th is assigned a negative value + expect_equal(yday_leap(as.Date("2024-02-29")), 999) + # before that is normal + expect_equal(yday_leap(as.Date("2024-02-28")), 31 + 28) + + # after that is decreased by 1 (so matches non leap years) + expect_equal( + yday_leap(as.Date("2024-05-28")), + lubridate::yday(as.Date("2022-05-28")) + ) + # off leap years have the right value + expect_equal(yday_leap(as.Date("2023-05-28")), 31 + 28 + 31 + 30 + 28) +}) +test_that("roll_modular_multivec works", { + tib <- tibble( + col = c(1, 2, 3, 3.5, 4, 1, -2, 4, 1, 0), + .idx = c(1, 1, 1, 2, 2, 3, 3, 3, 1, 1), + w = rep(1, 10) + ) + modulus <- 3L + + Mean <- function(x, w) weighted.mean(x, w, na.rm = TRUE) + Median <- function(x, w) median(x, na.rm = TRUE) + + # unweighted mean + # window of size 0 + expected_res <- tib |> + mutate(.idx = .idx %% modulus, .idx = .idx + (.idx == 0) * modulus) |> + summarise(climate_pred = weighted.mean(col, w = w), .by = .idx) + expect_equal( + roll_modular_multivec(tib$col, tib$.idx, tib$w, Mean, 0, modulus), + expected_res + ) + # window of size 1, which includes everything + expected_res <- tibble(.idx = as.double(1:3), climate_pred = mean(tib$col)) + expect_equal( + roll_modular_multivec(tib$col, tib$.idx, tib$w, Mean, 1L, modulus), + expected_res + ) + + # weighted mean + # window of size 0 + tib$w <- c(1, 2, 3, 1, 2, 1, 1, 2, 2, 1) + expected_res <- tib |> + mutate(.idx = .idx %% modulus, .idx = .idx + (.idx == 0) * modulus) |> + summarise(climate_pred = weighted.mean(col, w = w), .by = .idx) + expect_equal( + roll_modular_multivec(tib$col, tib$.idx, tib$w, Mean, 0, modulus), + expected_res + ) + # window of size 1 + expected_res <- tibble( + .idx = as.double(1:3), + climate_pred = weighted.mean(tib$col, tib$w) + ) + expect_equal( + roll_modular_multivec(tib$col, tib$.idx, tib$w, Mean, 1L, modulus), + expected_res + ) + # median + expected_res <- tib |> + mutate(.idx = .idx %% modulus, .idx = .idx + (.idx == 0) * modulus) |> + summarise(climate_pred = median(col), .by = .idx) + expect_equal( + roll_modular_multivec(tib$col, tib$.idx, tib$w, Median, 0, modulus), + expected_res + ) + expected_res <- tibble(.idx = as.double(1:3), climate_pred = median(tib$col)) + expect_equal( + roll_modular_multivec(tib$col, tib$.idx, tib$w, Median, 1L, modulus), + expected_res + ) +}) + +test_that("prep/bake steps create the correct training data", { + single_yr <- seq(as.Date("2021-01-01"), as.Date("2021-12-31"), by = "1 day") + x <- tibble( + time_value = rep(single_yr, times = 2L), + geo_value = rep(c("reg1", "reg2"), each = length(single_yr)), + # shift by 2 days to match the epiweeks of 2021 + y = rep(c(1, 1, rep(c(1:26, 26:2), each = 7), 1, 1, 1, 1, 1, 1), times = 2L) + ) %>% + as_epi_df() + # epiweeks 1, 52, and 53 are all 1, note that there are days in wk 52, 2 in wk 53 + r <- epi_recipe(x) %>% step_climate(y, time_type = "epiweek") + p <- prep(r, x) + + expected_res <- tibble(.idx = c(1:52, 999), climate_y = c(2, 2:25, 25, 25, 25:2, 2, 2)) + expect_equal(p$steps[[1]]$climate_table, expected_res) + + b <- bake(p, new_data = NULL) + expected_bake <- x %>% + mutate(.idx = epiweek_leap(time_value)) %>% + left_join(expected_res, by = join_by(.idx)) %>% + select(-.idx) + expect_equal(b, expected_bake) +}) + +test_that("prep/bake steps create the correct training data with an incomplete year", { + single_yr <- seq(as.Date("2021-01-01"), as.Date("2021-10-31"), by = "1 day") + x <- tibble( + time_value = rep(single_yr, times = 2L), + geo_value = rep(c("reg1", "reg2"), each = length(single_yr)), + # shift by 2 days to match the epiweeks of 2021 + y = rep(c(1, 1, rep(c(1:26, 26:2), each = 7), 1, 1, 1, 1, 1, 1)[1:length(single_yr)], times = 2L) + ) %>% + as_epi_df() + # epiweeks 1, 52, and 53 are all 1, note that there are days in wk 52, 2 in wk 53 + r <- epi_recipe(x) %>% step_climate(y, time_type = "epiweek") + p <- prep(r, x) + + expected_res <- tibble(.idx = c(1:44, 999), climate_y = c(2, 3, 3, 4:25, 25, 25, 25:12, 12, 11, 11, 10)) + expect_equal(p$steps[[1]]$climate_table, expected_res) + + b <- bake(p, new_data = NULL) + expected_bake <- x %>% + mutate(.idx = epiweek_leap(time_value)) %>% + left_join(expected_res, by = join_by(.idx)) %>% + select(-.idx) + expect_equal(b, expected_bake) +}) + +test_that("prep/bake steps create the correct training data for non leapweeks", { + single_yr <- seq(as.Date("2023-01-01"), as.Date("2023-12-31"), by = "1 day") + x <- tibble( + time_value = rep(single_yr, times = 2L), + geo_value = rep(c("reg1", "reg2"), each = length(single_yr)), + # shift by 2 days to match the epiweeks of 2021 + y = rep(c(1, 1, rep(c(1:26, 26:2), each = 7), 1, 1, 1, 1, 1, 1), times = 2L) + ) %>% + as_epi_df() + # epiweeks 1, 52, and 53 are all 1, note that there are days in wk 52, 2 in wk 53 + r <- epi_recipe(x) %>% step_climate(y, time_type = "epiweek") + p <- prep(r, x) + + expected_res <- tibble(.idx = 1:52, climate_y = c(2, 2:25, 25, 25, 25:2, 2)) + expect_equal(p$steps[[1]]$climate_table, expected_res) + + b <- bake(p, new_data = NULL) + expected_bake <- x %>% + mutate(.idx = lubridate::epiweek(time_value)) %>% + left_join(expected_res, by = join_by(.idx)) %>% + select(-.idx) + expect_equal(b, expected_bake) +}) + +test_that("prep/bake steps create the correct training data months", { + single_yr <- seq(as.Date("2021-01-01"), as.Date("2023-12-31"), by = "1 day") + x <- tibble( + time_value = rep(single_yr, times = 2L), + geo_value = rep(c("reg1", "reg2"), each = length(single_yr)), + ) %>% + # 1 2 3 4 5 6 6 5 4 3 2 1, assigned based on the month + mutate(y = pmin(13 - month(time_value), month(time_value))) %>% + as_epi_df() + + # epiweeks 1, 52, and 53 are all 1, note that there are days in wk 52, 2 in wk 53 + r <- epi_recipe(x) %>% step_climate(y, time_type = "month", window_size = 1) + p <- prep(r, x) + + expected_res <- tibble(.idx = 1:12, climate_y = c(1:6, 6:1)) + expect_equal(p$steps[[1]]$climate_table, expected_res) + + b <- bake(p, new_data = NULL) + expected_bake <- x %>% + mutate(.idx = month(time_value)) %>% + left_join(expected_res, by = join_by(.idx)) %>% + select(-.idx) + expect_equal(b, expected_bake) +}) + + +test_that("prep/bake steps create the correct training data for daily data", { + single_yr <- seq(as.Date("2020-01-01"), as.Date("2020-12-31"), by = "1 day") + x <- tibble( + time_value = rep(single_yr, times = 2L), + geo_value = rep(c("reg1", "reg2"), each = length(single_yr)), + y = rep(c(1:183, 184:2), times = 2L) + ) %>% + as_epi_df() + # epiweeks 1, 52, and 53 are all 1, note that there are days in wk 52, 2 in wk 53 + r <- epi_recipe(x) %>% step_climate(y, time_type = "day") + p <- prep(r, x) + + expected_res <- tibble( + .idx = c(1:365, 999), + climate_y = c(3, 3, 3:(59 - 4), 56.5:63.5, 65:181, rep(182, 5), 181:3, 3, 59) + ) + expect_equal(p$steps[[1]]$climate_table, expected_res) + + b <- bake(p, new_data = NULL) + expected_bake <- x %>% + mutate(.idx = yday_leap(time_value)) %>% + left_join(expected_res, by = join_by(.idx)) %>% + select(-.idx) + expect_equal(b, expected_bake) +}) + + +test_that("leading the climate predictor works as expected", { + single_yr <- seq(as.Date("2021-01-01"), as.Date("2021-12-31"), by = "1 day") + x <- tibble( + time_value = rep(single_yr, times = 2L), + geo_value = rep(c("reg1", "reg2"), each = length(single_yr)), + # shift by 2 days to match the epiweeks of 2021 + y = rep(c(1, 1, rep(c(1:26, 26:2), each = 7), 1, 1, 1, 1, 1, 1), times = 2L) + ) %>% + as_epi_df() + # epiweeks 1, 52, and 53 are all 1, note that there are days in wk 52, 2 in wk 53 + r <- epi_recipe(x) %>% + step_epi_ahead(y, ahead = 14L) %>% + step_epi_lag(y, lag = c(0, 7L, 14L)) %>% + step_climate(y, forecast_ahead = 2L, time_type = "epiweek") %>% + # matches the response + step_epi_naomit() + p <- prep(r, x) + + expected_res <- tibble(.idx = c(1:52, 999), climate_y = c(2, 2, 3, 4, 4.5, 5.5, 7:25, 25, 25, 25:2, 2, 2)) %>% + mutate( + climate_y = climate_y[c(3:53, 1:2)] + ) %>% + arrange(.idx) + expect_equal(p$steps[[3]]$climate_table, expected_res) + + b <- bake(p, new_data = NULL) + expect_identical(max(b$time_value), as.Date("2021-12-17")) # last date with no NAs + # expected climate predictor should be shifted forward by 2 weeks + expected_climate_pred <- x %>% + mutate( + .idx = lubridate::epiweek(time_value) %% 53, + .idx = dplyr::case_when(.idx == 0 ~ 53, TRUE ~ .idx) + ) %>% + left_join(expected_res, by = join_by(.idx)) %>% + arrange(time_value, geo_value) %>% + filter(time_value %in% unique(b$time_value)) %>% + pull(climate_y) + expect_identical(b$climate_y, expected_climate_pred) + + # Check if our test data has the right values + td <- get_test_data(r, x) + expected_test_x <- td %>% + filter(time_value == "2021-12-31") %>% + mutate( + ahead_14_y = NA_real_, lag_0_y = 1, lag_7_y = 2, lag_14_y = 3, + climate_y = 2 + ) + expect_equal(bake(p, td), expected_test_x) +})