diff --git a/DESCRIPTION b/DESCRIPTION index 0125f2e58..af0a92d5e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: epipredict Title: Basic epidemiology forecasting methods -Version: 0.0.1 +Version: 0.0.2 Authors@R: c( person("Daniel", "McDonald", , "daniel@stat.ubc.ca", role = c("aut","cre")), person("Jacob", "Bien", role = "aut"), @@ -19,6 +19,7 @@ Description: A forecasting "framework" for creating epidemiological forecasts License: MIT + file LICENSE URL: https://github.com/cmu-delphi/epipredict/, https://cmu-delphi.github.io/epipredict +BugReports: https://github.com/cmu-delphi/epipredict/issues/ Depends: R (>= 3.5.0) Imports: diff --git a/NAMESPACE b/NAMESPACE index 0f803520d..cfafc9a09 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -64,9 +64,7 @@ export(add_frosting) export(add_layer) export(apply_frosting) export(arx_args_list) -export(arx_epi_forecaster) export(arx_forecaster) -export(create_lags_and_leads) export(create_layer) export(default_epi_recipe_blueprint) export(detect_layer) @@ -82,18 +80,13 @@ export(extract_layers) export(extrapolate_quantiles) export(flatline) export(flatline_args_list) -export(flatline_epi_forecaster) +export(flatline_forecaster) export(frosting) -export(get_precision) export(get_test_data) export(grab_names) export(is_epi_recipe) export(is_epi_workflow) export(is_layer) -export(knn_iteraive_ar_args_list) -export(knn_iteraive_ar_forecaster) -export(knnarx_args_list) -export(knnarx_forecaster) export(layer) export(layer_add_forecast_date) export(layer_add_target_date) @@ -108,8 +101,6 @@ export(new_default_epi_recipe_blueprint) export(new_epi_recipe_blueprint) export(remove_frosting) export(slather) -export(smooth_arx_args_list) -export(smooth_arx_forecaster) export(step_epi_ahead) export(step_epi_lag) export(step_epi_naomit) @@ -139,5 +130,4 @@ importFrom(stats,predict) importFrom(stats,qnorm) importFrom(stats,quantile) importFrom(stats,residuals) -importFrom(stats,setNames) importFrom(tibble,tibble) diff --git a/R/arx_forecaster.R b/R/arx_forecaster.R index 0ff4497c1..86c38f934 100644 --- a/R/arx_forecaster.R +++ b/R/arx_forecaster.R @@ -1,68 +1,87 @@ -#' AR forecaster with optional covariates +#' Direct autoregressive forecaster with covariates #' -#' @param x Covariates. Allowed to be missing (resulting in AR on `y`). -#' @param y Response. -#' @param key_vars Factor(s). A prediction will be made for each unique -#' combination. -#' @param time_value the time value associated with each row of measurements. -#' @param args Additional arguments specifying the forecasting task. Created -#' by calling `arx_args_list()`. +#' This is an autoregressive forecasting model for +#' [epiprocess::epi_df] data. It does "direct" forecasting, meaning +#' that it estimates a model for a particular target horizon. #' -#' @return A data frame of point (and optionally interval) forecasts at a single -#' ahead (unique horizon) for each unique combination of `key_vars`. +#' +#' @param epi_data An `epi_df` object +#' @param outcome A character (scalar) specifying the outcome (in the +#' `epi_df`). +#' @param predictors A character vector giving column(s) of predictor +#' variables. +#' @param trainer A `{parsnip}` model describing the type of estimation. +#' For now, we enforce `mode = "regression"`. +#' @param args_list A list of customization arguments to determine +#' the type of forecasting model. See [arx_args_list()]. +#' +#' @return A list with (1) `predictions` an `epi_df` of predicted values +#' and (2) `epi_workflow`, a list that encapsulates the entire estimation +#' workflow #' @export -arx_forecaster <- function(x, y, key_vars, time_value, - args = arx_args_list()) { +#' +#' @examples +#' jhu <- case_death_rate_subset %>% +#' dplyr::filter(time_value >= as.Date("2021-12-01")) +#' +#' out <- arx_forecaster(jhu, "death_rate", +#' c("case_rate", "death_rate")) +arx_forecaster <- function(epi_data, + outcome, + predictors, + trainer = parsnip::linear_reg(), + args_list = arx_args_list()) { - # TODO: function to verify standard forecaster signature inputs + validate_forecaster_inputs(epi_data, outcome, predictors) + if (!is.list(trainer) || trainer$mode != "regression") + cli_stop("{trainer} must be a `parsnip` method of mode 'regression'.") + lags <- arx_lags_validator(predictors, args_list$lags) - assign_arg_list(args) - if (is.null(key_vars)) { # this is annoying/repetitive, seemingly necessary? - keys <- NULL - distinct_keys <- tibble(.dump = NA) - } else { - keys <- tibble::tibble(key_vars) - distinct_keys <- dplyr::distinct(keys) + r <- epi_recipe(epi_data) + for (l in seq_along(lags)) { + p <- predictors[l] + r <- step_epi_lag(r, !!p, lag = lags[[l]]) } + r <- r %>% + step_epi_ahead(dplyr::all_of(!!outcome), ahead = args_list$ahead) %>% + step_epi_naomit() + # should limit the training window here (in an open PR) + # What to do if insufficient training data? Add issue. - # Return NA if insufficient training data - if (length(y) < min_train_window + max_lags + ahead) { - qnames <- probs_to_string(levels) - out <- dplyr::bind_cols(distinct_keys, point = NA) %>% - dplyr::select(!dplyr::any_of(".dump")) - return(enframer(out, qnames)) - } + forecast_date <- args_list$forecast_date %||% max(epi_data$time_value) + target_date <- args_list$target_date %||% forecast_date + args_list$ahead + f <- frosting() %>% + layer_predict() %>% + # layer_naomit(.pred) %>% + layer_residual_quantiles( + probs = args_list$levels, + symmetrize = args_list$symmetrize) %>% + layer_add_forecast_date(forecast_date = forecast_date) %>% + layer_add_target_date(target_date = target_date) + if (args_list$nonneg) f <- layer_threshold(f, dplyr::starts_with(".pred")) - dat <- create_lags_and_leads(x, y, lags, ahead, time_value, keys) - dat$x0 <- 1 + latest <- get_test_data(r, epi_data) - obj <- stats::lm( - y1 ~ . + 0, - data = dat %>% dplyr::select(starts_with(c("x", "y"))) + wf <- epi_workflow(r, trainer, f) %>% generics::fit(epi_data) + list( + predictions = predict(wf, new_data = latest), + epi_workflow = wf ) +} - point <- make_predictions(obj, dat, time_value, keys) - - # Residuals, simplest case, requires - # 1. same quantiles for all keys - # 2. `residuals(obj)` works - r <- residuals(obj) - q <- residual_quantiles(r, point, levels, symmetrize) - # Harder case requires handling failures of 1 and or 2, neither implemented - # 1. different quantiles by key, need to bind the keys, then group_modify - # 2 fails. need to bind the keys, grab, y and yhat, subtract - if (nonneg) { - q <- dplyr::mutate(q, dplyr::across(dplyr::everything(), ~ pmax(.x, 0))) +arx_lags_validator <- function(predictors, lags) { + p <- length(predictors) + if (!is.list(lags)) lags <- list(lags) + if (length(lags) == 1) lags <- rep(lags, p) + else if (length(lags) < p) { + cli_stop( + "You have requested {p} predictors but lags cannot be recycled to match." + ) } - - return( - dplyr::bind_cols(distinct_keys, q) %>% - dplyr::select(!dplyr::any_of(".dump")) - ) + lags } - #' ARX forecaster argument constructor #' #' Constructs a list of arguments for [arx_forecaster()]. diff --git a/R/arx_forecaster_mod.R b/R/arx_forecaster_mod.R deleted file mode 100644 index 60b0294f2..000000000 --- a/R/arx_forecaster_mod.R +++ /dev/null @@ -1,83 +0,0 @@ -#' Direct autoregressive forecaster with covariates -#' -#' This is an autoregressive forecasting model for -#' [epiprocess::epi_df] data. It does "direct" forecasting, meaning -#' that it estimates a model for a particular target horizon. -#' -#' -#' @param epi_data An `epi_df` object -#' @param outcome A character (scalar) specifying the outcome (in the -#' `epi_df`). -#' @param predictors A character vector giving column(s) of predictor -#' variables. -#' @param trainer A `{parsnip}` model describing the type of estimation. -#' For now, we enforce `mode = "regression"`. -#' @param args_list A list of customization arguments to determine -#' the type of forecasting model. See [arx_args_list()]. -#' -#' @return A list with (1) `predictions` an `epi_df` of predicted values -#' and (2) `epi_workflow`, a list that encapsulates the entire estimation -#' workflow -#' @export -#' -#' @examples -#' jhu <- case_death_rate_subset %>% -#' dplyr::filter(time_value >= as.Date("2021-12-01")) -#' -#' out <- arx_epi_forecaster(jhu, "death_rate", -#' c("case_rate", "death_rate")) -arx_epi_forecaster <- function(epi_data, - outcome, - predictors, - trainer = parsnip::linear_reg(), - args_list = arx_args_list()) { - - validate_forecaster_inputs(epi_data, outcome, predictors) - if (!is.list(trainer) || trainer$mode != "regression") - cli_stop("{trainer} must be a `parsnip` method of mode 'regression'.") - lags <- arx_lags_validator(predictors, args_list$lags) - - r <- epi_recipe(epi_data) - for (l in seq_along(lags)) { - p <- predictors[l] - r <- step_epi_lag(r, !!p, lag = lags[[l]]) - } - r <- r %>% - step_epi_ahead(dplyr::all_of(!!outcome), ahead = args_list$ahead) %>% - step_epi_naomit() - # should limit the training window here (in an open PR) - # What to do if insufficient training data? Add issue. - - forecast_date <- args_list$forecast_date %||% max(epi_data$time_value) - target_date <- args_list$target_date %||% forecast_date + args_list$ahead - f <- frosting() %>% - layer_predict() %>% - # layer_naomit(.pred) %>% - layer_residual_quantiles( - probs = args_list$levels, - symmetrize = args_list$symmetrize) %>% - layer_add_forecast_date(forecast_date = forecast_date) %>% - layer_add_target_date(target_date = target_date) - if (args_list$nonneg) f <- layer_threshold(f, dplyr::starts_with(".pred")) - - latest <- get_test_data(r, epi_data) - - wf <- epi_workflow(r, trainer, f) %>% generics::fit(epi_data) - list( - predictions = predict(wf, new_data = latest), - epi_workflow = wf - ) -} - - -arx_lags_validator <- function(predictors, lags) { - p <- length(predictors) - if (!is.list(lags)) lags <- list(lags) - if (length(lags) == 1) lags <- rep(lags, p) - else if (length(lags) < p) { - cli_stop( - "You have requested {p} predictors but lags cannot be recycled to match." - ) - } - lags -} diff --git a/R/blueprint-epi_recipe-default.R b/R/blueprint-epi_recipe-default.R index 83cf631a1..9fecd9f5b 100644 --- a/R/blueprint-epi_recipe-default.R +++ b/R/blueprint-epi_recipe-default.R @@ -9,6 +9,7 @@ #' @details The `bake_dependent_roles` are automatically set to `epi_df` defaults. #' @return A recipe blueprint. #' +#' @keywords internal #' @export new_epi_recipe_blueprint <- function(intercept = FALSE, allow_novel_levels = FALSE, fresh = TRUE, diff --git a/R/df_mat_mul.R b/R/df_mat_mul.R index 907a8ed0d..320659cd5 100644 --- a/R/df_mat_mul.R +++ b/R/df_mat_mul.R @@ -13,6 +13,7 @@ #' @return A data.frame with the new columns at the right. Original #' columns are removed. #' @export +#' @keywords internal #' #' @examples #' df <- data.frame(matrix(1:200, ncol = 10)) diff --git a/R/epi_keys.R b/R/epi_keys.R index aa9976efa..b82f625dd 100644 --- a/R/epi_keys.R +++ b/R/epi_keys.R @@ -3,8 +3,8 @@ #' @param x a data.frame, tibble, or epi_df #' #' @return If an `epi_df`, this returns all "keys". Otherwise `NULL` +#' @keywords internal #' @export -#' epi_keys <- function(x) { UseMethod("epi_keys") } diff --git a/R/epi_recipe.R b/R/epi_recipe.R index c9dd8d4e9..24ea61ee2 100644 --- a/R/epi_recipe.R +++ b/R/epi_recipe.R @@ -215,6 +215,7 @@ epi_form2args <- function(formula, data, ...) { #' @param x An object. #' @return `TRUE` if the object inherits from `epi_recipe`. #' +#' @keywords internal #' @export is_epi_recipe <- function(x) { inherits(x, "epi_recipe") diff --git a/R/epi_shift.R b/R/epi_shift.R index 4fe99601b..c5d1d96d5 100644 --- a/R/epi_shift.R +++ b/R/epi_shift.R @@ -10,6 +10,8 @@ #' @param keys Data frame, vector, or `NULL`. Additional grouping vars. #' @param out_name Chr. The output list will use this as a prefix. #' +#' @keywords internal +#' #' @return a list of tibbles epi_shift <- function(x, shifts, time_value, keys = NULL, out_name = "x") { if (!is.data.frame(x)) x <- data.frame(x) diff --git a/R/epi_workflow.R b/R/epi_workflow.R index 8ae99b2b7..6ba6e6c7b 100644 --- a/R/epi_workflow.R +++ b/R/epi_workflow.R @@ -57,6 +57,7 @@ epi_workflow <- function(preprocessor = NULL, spec = NULL, postprocessor = NULL) #' @param x An object. #' @return `TRUE` if the object inherits from `epi_workflow`. #' +#' @keywords internal #' @export is_epi_workflow <- function(x) { inherits(x, "epi_workflow") diff --git a/R/extract.R b/R/extract.R index 5c012ebac..bbb7c9152 100644 --- a/R/extract.R +++ b/R/extract.R @@ -8,6 +8,8 @@ #' @return An object originally passed as an argument to a layer or step #' @export #' +#' @keywords internal +#' #' @examples #' f <- frosting() %>% #' layer_predict() %>% diff --git a/R/flatline.R b/R/flatline.R index 8732be192..bed71a8cb 100644 --- a/R/flatline.R +++ b/R/flatline.R @@ -10,7 +10,7 @@ #' horizon. The right hand side must contain any keys (locations) for the #' panel data separated by plus. The observed time series must come last. #' For example -#' ``` +#' ```r #' form <- as.formula(lead7_y ~ state + age + y) #' ``` #' Note that this function doesn't DO the shifting, that has to be done @@ -26,6 +26,7 @@ #' predictions for future data (the last observed of the outcome for each #' combination of keys. #' @export +#' @keywords internal #' #' @examples #' tib <- data.frame(y = runif(100), diff --git a/R/flatline_epi_forecaster.R b/R/flatline_forecaster.R similarity index 93% rename from R/flatline_epi_forecaster.R rename to R/flatline_forecaster.R index 7ecefc17e..fb670911b 100644 --- a/R/flatline_epi_forecaster.R +++ b/R/flatline_forecaster.R @@ -26,10 +26,10 @@ #' jhu <- case_death_rate_subset %>% #' dplyr::filter(time_value >= as.Date("2021-12-01")) #' -#' out <- flatline_epi_forecaster(jhu, "death_rate") -flatline_epi_forecaster <- function(epi_data, - outcome, - args_list = flatline_args_list()) { +#' out <- flatline_forecaster(jhu, "death_rate") +flatline_forecaster <- function(epi_data, + outcome, + args_list = flatline_args_list()) { validate_forecaster_inputs(epi_data, outcome, "time_value") keys <- epi_keys(epi_data) @@ -71,7 +71,7 @@ flatline_epi_forecaster <- function(epi_data, #' Flatline forecaster argument constructor #' -#' Constructs a list of arguments for [flatline_epi_forecaster()]. +#' Constructs a list of arguments for [flatline_forecaster()]. #' #' @inheritParams arx_args_list #' diff --git a/R/grab_names.R b/R/grab_names.R index e4a396b1d..7ff3ac77e 100644 --- a/R/grab_names.R +++ b/R/grab_names.R @@ -12,6 +12,7 @@ #' be used to select a range of variables. #' #' @export +#' @keywords internal #' @return a character vector #' @examples #' df <- data.frame(a = 1, b = 2, cc = rep(NA, 3)) diff --git a/R/utils_misc.R b/R/utils_misc.R index ff566fc25..0c5b5ac7f 100644 --- a/R/utils_misc.R +++ b/R/utils_misc.R @@ -8,6 +8,8 @@ #' @param object A layer object passed to [slather()]. #' @param newname A string of variable names if the object doesn't contain a #' $name element +#' +#' @keywords internal check_pname <- function(res, preds, object, newname = NULL) { if (is.null(newname)) newname <- object$name new_preds_names <- colnames(preds) diff --git a/_pkgdown.yml b/_pkgdown.yml index 8f57fe826..cfe327dca 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -2,3 +2,40 @@ url: https://cmu-delphi.github.io/epipredict/ template: bootstrap: 5 + +reference: + - title: Simple forecasters + desc: Complete forecasters that produce reasonable baselines + contents: + - contains("flatline") + - contains("arx") + - title: Custom panel data forecasting workflows + contents: + - epi_recipe + - epi_workflow + - add_epi_recipe + - predict.epi_workflow + - augment.epi_workflow + - title: Epi recipe preprocessing steps + contents: + - starts_with("step_") + - title: Forecast postprocessing + desc: Create a series of postprocessing operations + contents: + - frosting + - ends_with("_frosting") + - get_test_data + - title: Frosting layers + contents: + - contains("layer") + - contains("slather") + - title: Utilities for quantile distribution processing + contents: + - dist_quantiles + - extrapolate_quantiles + - nested_quantiles + - title: Included datasets + contents: + - case_death_rate_subset + + diff --git a/man/arx_epi_forecaster.Rd b/man/arx_epi_forecaster.Rd deleted file mode 100644 index da8d0ad67..000000000 --- a/man/arx_epi_forecaster.Rd +++ /dev/null @@ -1,46 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/arx_forecaster_mod.R -\name{arx_epi_forecaster} -\alias{arx_epi_forecaster} -\title{Direct autoregressive forecaster with covariates} -\usage{ -arx_epi_forecaster( - epi_data, - outcome, - predictors, - trainer = parsnip::linear_reg(), - args_list = arx_args_list() -) -} -\arguments{ -\item{epi_data}{An \code{epi_df} object} - -\item{outcome}{A character (scalar) specifying the outcome (in the -\code{epi_df}).} - -\item{predictors}{A character vector giving column(s) of predictor -variables.} - -\item{trainer}{A \code{{parsnip}} model describing the type of estimation. -For now, we enforce \code{mode = "regression"}.} - -\item{args_list}{A list of customization arguments to determine -the type of forecasting model. See \code{\link[=arx_args_list]{arx_args_list()}}.} -} -\value{ -A list with (1) \code{predictions} an \code{epi_df} of predicted values -and (2) \code{epi_workflow}, a list that encapsulates the entire estimation -workflow -} -\description{ -This is an autoregressive forecasting model for -\link[epiprocess:epi_df]{epiprocess::epi_df} data. It does "direct" forecasting, meaning -that it estimates a model for a particular target horizon. -} -\examples{ -jhu <- case_death_rate_subset \%>\% - dplyr::filter(time_value >= as.Date("2021-12-01")) - -out <- arx_epi_forecaster(jhu, "death_rate", - c("case_rate", "death_rate")) -} diff --git a/man/arx_forecaster.Rd b/man/arx_forecaster.Rd index 70bf583e5..407090f32 100644 --- a/man/arx_forecaster.Rd +++ b/man/arx_forecaster.Rd @@ -2,27 +2,45 @@ % Please edit documentation in R/arx_forecaster.R \name{arx_forecaster} \alias{arx_forecaster} -\title{AR forecaster with optional covariates} +\title{Direct autoregressive forecaster with covariates} \usage{ -arx_forecaster(x, y, key_vars, time_value, args = arx_args_list()) +arx_forecaster( + epi_data, + outcome, + predictors, + trainer = parsnip::linear_reg(), + args_list = arx_args_list() +) } \arguments{ -\item{x}{Covariates. Allowed to be missing (resulting in AR on \code{y}).} +\item{epi_data}{An \code{epi_df} object} -\item{y}{Response.} +\item{outcome}{A character (scalar) specifying the outcome (in the +\code{epi_df}).} -\item{key_vars}{Factor(s). A prediction will be made for each unique -combination.} +\item{predictors}{A character vector giving column(s) of predictor +variables.} -\item{time_value}{the time value associated with each row of measurements.} +\item{trainer}{A \code{{parsnip}} model describing the type of estimation. +For now, we enforce \code{mode = "regression"}.} -\item{args}{Additional arguments specifying the forecasting task. Created -by calling \code{arx_args_list()}.} +\item{args_list}{A list of customization arguments to determine +the type of forecasting model. See \code{\link[=arx_args_list]{arx_args_list()}}.} } \value{ -A data frame of point (and optionally interval) forecasts at a single -ahead (unique horizon) for each unique combination of \code{key_vars}. +A list with (1) \code{predictions} an \code{epi_df} of predicted values +and (2) \code{epi_workflow}, a list that encapsulates the entire estimation +workflow } \description{ -AR forecaster with optional covariates +This is an autoregressive forecasting model for +\link[epiprocess:epi_df]{epiprocess::epi_df} data. It does "direct" forecasting, meaning +that it estimates a model for a particular target horizon. +} +\examples{ +jhu <- case_death_rate_subset \%>\% + dplyr::filter(time_value >= as.Date("2021-12-01")) + +out <- arx_forecaster(jhu, "death_rate", + c("case_rate", "death_rate")) } diff --git a/man/assign_arg_list.Rd b/man/assign_arg_list.Rd deleted file mode 100644 index 6821fce1c..000000000 --- a/man/assign_arg_list.Rd +++ /dev/null @@ -1,31 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/assign_arg_list.R -\name{assign_arg_list} -\alias{assign_arg_list} -\title{Assign argument list to inside an environment} -\usage{ -assign_arg_list(l, env = parent.frame()) -} -\arguments{ -\item{l}{List of named arguments.} - -\item{env}{The environment where the args should be assigned. -The default goes into the calling environment.} -} -\value{ -Nothing is returned. Called for the side effects. -} -\description{ -This function is similar to \code{attach()} but without the -need to detach. Calling it at the beginning of a forecaster -makes all members of the \code{arg_list} available inside the -forecaster with out the ugly \code{args$member} syntax. -} -\examples{ -\dontrun{ - rm(list = ls()) - l <- list(a=1, b=c(12, 10), ff = function() -5) - assign_arg_list(l) - a -} -} diff --git a/man/check_pname.Rd b/man/check_pname.Rd index 161876ccb..d57eab561 100644 --- a/man/check_pname.Rd +++ b/man/check_pname.Rd @@ -21,3 +21,4 @@ $name element} newly created variable names don't overlap with existing names. Throws an warning if check fails, and creates a random string. } +\keyword{internal} diff --git a/man/create_lags_and_leads.Rd b/man/create_lags_and_leads.Rd deleted file mode 100644 index 00aa7975c..000000000 --- a/man/create_lags_and_leads.Rd +++ /dev/null @@ -1,47 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/create_lags_and_leads.R -\name{create_lags_and_leads} -\alias{create_lags_and_leads} -\title{Create lags and leads of predictors and response} -\usage{ -create_lags_and_leads(x, y, xy_lags, y_leads, time_value, key_vars = NULL) -} -\arguments{ -\item{x}{Data frame or matrix. Predictor variables. May be -missing.} - -\item{y}{Response vector. Typical usage will "lead" y by the -number of steps forward for the prediction horizon (ahead).} - -\item{xy_lags}{Vector or list. If a vector, the lags will apply -to each column of \code{x} and to \code{y}. If a list, it must be of length -\code{ncol(x)+1} and each component will apply to the requisite predictor. -A \code{NULL} list element will remove that variable completely from the -result. Negative values will "lead" the variable.} - -\item{y_leads}{Scalar or vector. If a scalar, we "lead" \code{y} by this -amount. A vector will produce multiple columns of \code{y} if this is -useful for your model. Negative values will "lag" the variable.} - -\item{time_value}{Vector of time values at which the data are -observed} - -\item{key_vars}{Factors representing different groups. May be -\code{NULL} (the default).} -} -\value{ -A \code{data.frame}. -} -\description{ -Create lags and leads of predictors and response -} -\examples{ - -x <- 1:20 -y <- -20:-1 -time_value <- c(1:18, 20, 21) -create_lags_and_leads(x, y, c(1, 2), 1, time_value) -create_lags_and_leads(x, y, list(c(1, 2), 1), 1, time_value) -create_lags_and_leads(x, y, list(c(-1, 1), NULL), 1, time_value) -create_lags_and_leads(x, y, c(1, 2), c(0, 1), time_value) -} diff --git a/man/df_mat_mul.Rd b/man/df_mat_mul.Rd index d095cd8e3..57596dd2d 100644 --- a/man/df_mat_mul.Rd +++ b/man/df_mat_mul.Rd @@ -32,3 +32,4 @@ df <- data.frame(matrix(1:200, ncol = 10)) mat <- matrix(1:10, ncol = 2) df_mat_mul(df, mat, "z", dplyr::num_range("X", 2:6)) } +\keyword{internal} diff --git a/man/epi_keys.Rd b/man/epi_keys.Rd index cfa8b20a2..d96666781 100644 --- a/man/epi_keys.Rd +++ b/man/epi_keys.Rd @@ -15,3 +15,4 @@ If an \code{epi_df}, this returns all "keys". Otherwise \code{NULL} \description{ Grab any keys associated to an epi_df } +\keyword{internal} diff --git a/man/epi_shift.Rd b/man/epi_shift.Rd index 058505faa..14316a8db 100644 --- a/man/epi_shift.Rd +++ b/man/epi_shift.Rd @@ -25,3 +25,4 @@ a list of tibbles \description{ This is a lower-level function. As such it performs no error checking. } +\keyword{internal} diff --git a/man/extract_argument.Rd b/man/extract_argument.Rd index 0ee78d38b..3a83c4dd4 100644 --- a/man/extract_argument.Rd +++ b/man/extract_argument.Rd @@ -29,3 +29,4 @@ f <- frosting() \%>\% extract_argument(f, "layer_residual_quantiles", "symmetrize") } +\keyword{internal} diff --git a/man/flatline.Rd b/man/flatline.Rd index d65dcae8a..a396cfeb9 100644 --- a/man/flatline.Rd +++ b/man/flatline.Rd @@ -13,7 +13,7 @@ horizon. The right hand side must contain any keys (locations) for the panel data separated by plus. The observed time series must come last. For example -\if{html}{\out{
}}\preformatted{form <- as.formula(lead7_y ~ state + age + y) +\if{html}{\out{
}}\preformatted{form <- as.formula(lead7_y ~ state + age + y) }\if{html}{\out{
}} Note that this function doesn't DO the shifting, that has to be done @@ -45,3 +45,4 @@ tib <- data.frame(y = runif(100), flat <- flatline(y2 ~ j + k + y, tib) # predictions for 20 locations sum(!is.na(flat$residuals$.resid)) # 100 residuals, but 40 are NA } +\keyword{internal} diff --git a/man/flatline_args_list.Rd b/man/flatline_args_list.Rd index 701b4d7b0..4198538c5 100644 --- a/man/flatline_args_list.Rd +++ b/man/flatline_args_list.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/flatline_epi_forecaster.R +% Please edit documentation in R/flatline_forecaster.R \name{flatline_args_list} \alias{flatline_args_list} \title{Flatline forecaster argument constructor} @@ -48,7 +48,7 @@ before calculating residual quantiles. See the \code{by_key} argument to A list containing updated parameter choices. } \description{ -Constructs a list of arguments for \code{\link[=flatline_epi_forecaster]{flatline_epi_forecaster()}}. +Constructs a list of arguments for \code{\link[=flatline_forecaster]{flatline_forecaster()}}. } \examples{ flatline_args_list() diff --git a/man/flatline_epi_forecaster.Rd b/man/flatline_forecaster.Rd similarity index 83% rename from man/flatline_epi_forecaster.Rd rename to man/flatline_forecaster.Rd index 345d87566..052dd6428 100644 --- a/man/flatline_epi_forecaster.Rd +++ b/man/flatline_forecaster.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/flatline_epi_forecaster.R -\name{flatline_epi_forecaster} -\alias{flatline_epi_forecaster} +% Please edit documentation in R/flatline_forecaster.R +\name{flatline_forecaster} +\alias{flatline_forecaster} \title{Predict the future with today's value} \usage{ -flatline_epi_forecaster(epi_data, outcome, args_list = flatline_args_list()) +flatline_forecaster(epi_data, outcome, args_list = flatline_args_list()) } \arguments{ \item{epi_data}{An \link[epiprocess:epi_df]{epiprocess::epi_df}} @@ -37,5 +37,5 @@ This forecaster is very similar to that used by the jhu <- case_death_rate_subset \%>\% dplyr::filter(time_value >= as.Date("2021-12-01")) -out <- flatline_epi_forecaster(jhu, "death_rate") +out <- flatline_forecaster(jhu, "death_rate") } diff --git a/man/get_precision.Rd b/man/get_precision.Rd deleted file mode 100644 index 80921cbcc..000000000 --- a/man/get_precision.Rd +++ /dev/null @@ -1,23 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/probs_to_string.R -\name{get_precision} -\alias{get_precision} -\title{Determine the precision of a number} -\usage{ -get_precision(x, ...) -} -\arguments{ -\item{x}{A numeric vector} - -\item{...}{Ignore this} -} -\value{ -A vector of integers, with the number of digits (to the last non-zero digit) past the decimal point. -} -\description{ -Determine the precision of a number, as the number of digits past -the decimal point. -} -\details{ -If the number is expressed in scientific notation, we take the number of digits -} diff --git a/man/grab_names.Rd b/man/grab_names.Rd index 8af66c736..cee6b19dc 100644 --- a/man/grab_names.Rd +++ b/man/grab_names.Rd @@ -28,3 +28,4 @@ As this is an internal function, no checks are performed. df <- data.frame(a = 1, b = 2, cc = rep(NA, 3)) grab_names(df, dplyr::starts_with("c")) } +\keyword{internal} diff --git a/man/is_epi_recipe.Rd b/man/is_epi_recipe.Rd index f3b32ffe1..803fa2190 100644 --- a/man/is_epi_recipe.Rd +++ b/man/is_epi_recipe.Rd @@ -15,3 +15,4 @@ is_epi_recipe(x) \description{ Test for \code{epi_recipe} } +\keyword{internal} diff --git a/man/is_epi_workflow.Rd b/man/is_epi_workflow.Rd index 7b1843c39..81b017578 100644 --- a/man/is_epi_workflow.Rd +++ b/man/is_epi_workflow.Rd @@ -15,3 +15,4 @@ is_epi_workflow(x) \description{ Test for an \code{epi_workflow} } +\keyword{internal} diff --git a/man/knn_iteraive_ar_args_list.Rd b/man/knn_iteraive_ar_args_list.Rd deleted file mode 100644 index 5e82f9084..000000000 --- a/man/knn_iteraive_ar_args_list.Rd +++ /dev/null @@ -1,65 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/knn_iterative_ar_forecaster.R -\name{knn_iteraive_ar_args_list} -\alias{knn_iteraive_ar_args_list} -\title{KNN enhanced iterative AR forecaster argument constructor} -\usage{ -knn_iteraive_ar_args_list( - lags = c(0, 7, 14), - query_window_len = 50, - topK = 500, - ahead = 7, - min_train_window = 20, - levels = c(0.05, 0.95), - intercept = TRUE, - symmetrize = TRUE, - nonneg = TRUE, - quantile_by_key = FALSE, - update_model = TRUE -) -} -\arguments{ -\item{lags}{Vector or List. Positive integers enumerating lags to use -in autoregressive-type models.} - -\item{query_window_len}{Integer. Length of the query window -for KNN searching.} - -\item{topK}{Integer. Number of most similar training samples.} - -\item{ahead}{Integer. Number of time steps ahead of the forecast date -for which forecasts should be produced.} - -\item{min_train_window}{Integer. The minimal amount of training -data needed to produce a forecast. If smaller, the forecaster will return -\code{NA} predictions.} - -\item{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{intercept}{Logical. The default \code{TRUE} includes intercept in the -forecaster.} - -\item{symmetrize}{Logical. The default \code{TRUE} calculates -symmetric prediction intervals.} - -\item{nonneg}{Logical. The default \code{TRUE} enforeces nonnegative predictions -by hard-thresholding at 0.} - -\item{quantile_by_key}{Not currently implemented} - -\item{update_model}{Logical. The default \code{TRUE} updates the -one-step ahead model every time for iterative forecasting strategy.} -} -\value{ -A list containing updated parameter choices. -} -\description{ -Constructs a list of arguments for \code{\link[=knn_iteraive_ar_forecaster]{knn_iteraive_ar_forecaster()}}. -} -\examples{ -arx_args_list() -arx_args_list(symmetrize = FALSE) -arx_args_list(levels = c(.1, .3, .7, .9), min_train_window = 120) -} diff --git a/man/knn_iteraive_ar_forecaster.Rd b/man/knn_iteraive_ar_forecaster.Rd deleted file mode 100644 index a25b379ec..000000000 --- a/man/knn_iteraive_ar_forecaster.Rd +++ /dev/null @@ -1,34 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/knn_iterative_ar_forecaster.R -\name{knn_iteraive_ar_forecaster} -\alias{knn_iteraive_ar_forecaster} -\title{KNN enhanced iterative AR forecaster with optional covariates} -\usage{ -knn_iteraive_ar_forecaster( - x, - y, - key_vars, - time_value, - args = knn_iteraive_ar_args_list() -) -} -\arguments{ -\item{x}{Unused covariates. Must to be missing (resulting in AR on \code{y}) .} - -\item{y}{Response.} - -\item{key_vars}{Factor(s). A prediction will be made for each unique -combination.} - -\item{time_value}{the time value associated with each row of measurements.} - -\item{args}{Additional arguments specifying the forecasting task. Created -by calling \code{knn_iteraive_ar_args_list()}.} -} -\value{ -A data frame of point (and optionally interval) forecasts at multiple -aheads (multiple horizons from one to specified \code{ahead}) for each unique combination of \code{key_vars}. -} -\description{ -KNN enhanced iterative AR forecaster with optional covariates -} diff --git a/man/knnarx_args_list.Rd b/man/knnarx_args_list.Rd deleted file mode 100644 index c0b771b5c..000000000 --- a/man/knnarx_args_list.Rd +++ /dev/null @@ -1,61 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/knnarx_forecaster.R -\name{knnarx_args_list} -\alias{knnarx_args_list} -\title{KNN enhanced ARX forecaster argument constructor} -\usage{ -knnarx_args_list( - lags = c(0, 7, 14), - query_window_len = 50, - topK = 500, - ahead = 7, - min_train_window = 20, - levels = c(0.05, 0.95), - intercept = TRUE, - symmetrize = TRUE, - nonneg = TRUE, - quantile_by_key = FALSE -) -} -\arguments{ -\item{lags}{Vector or List. Positive integers enumerating lags to use -in autoregressive-type models.} - -\item{query_window_len}{Integer. Length of the query window -for KNN searching.} - -\item{topK}{Integer. Number of most similar training samples.} - -\item{ahead}{Integer. Number of time steps ahead of the forecast date -for which forecasts should be produced.} - -\item{min_train_window}{Integer. The minimal amount of training -data needed to produce a forecast. If smaller, the forecaster will return -\code{NA} predictions.} - -\item{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{intercept}{Logical. The default \code{TRUE} includes intercept in the -forecaster.} - -\item{symmetrize}{Logical. The default \code{TRUE} calculates -symmetric prediction intervals.} - -\item{nonneg}{Logical. The default \code{TRUE} enforeces nonnegative predictions -by hard-thresholding at 0.} - -\item{quantile_by_key}{Not currently implemented} -} -\value{ -A list containing updated parameter choices. -} -\description{ -Constructs a list of arguments for \code{\link[=knnarx_forecaster]{knnarx_forecaster()}}. -} -\examples{ -knnarx_args_list() -knnarx_args_list(symmetrize = FALSE) -knnarx_args_list(levels = c(.1, .3, .7, .9), min_train_window = 120) -} diff --git a/man/knnarx_forecaster.Rd b/man/knnarx_forecaster.Rd deleted file mode 100644 index d4bce08fe..000000000 --- a/man/knnarx_forecaster.Rd +++ /dev/null @@ -1,28 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/knnarx_forecaster.R -\name{knnarx_forecaster} -\alias{knnarx_forecaster} -\title{KNN enhanced ARX forecaster with optional covariates} -\usage{ -knnarx_forecaster(x, y, key_vars, time_value, args = knnarx_args_list()) -} -\arguments{ -\item{x}{Covariates. Allowed to be missing (resulting in AR on \code{y}).} - -\item{y}{Response.} - -\item{key_vars}{Factor(s). A prediction will be made for each unique -combination.} - -\item{time_value}{the time value associated with each row of measurements.} - -\item{args}{Additional arguments specifying the forecasting task. Created -by calling \code{knnarx_args_list()}.} -} -\value{ -A data frame of point (and optionally interval) forecasts at a single -ahead (unique horizon) for each unique combination of \code{key_vars}. -} -\description{ -KNN enhanced ARX forecaster with optional covariates -} diff --git a/man/new_epi_recipe_blueprint.Rd b/man/new_epi_recipe_blueprint.Rd index 1ae818c4e..db22b5675 100644 --- a/man/new_epi_recipe_blueprint.Rd +++ b/man/new_epi_recipe_blueprint.Rd @@ -89,3 +89,4 @@ Used for simplicity. See \code{\link[hardhat:new-blueprint]{hardhat::new_recipe_ \details{ The \code{bake_dependent_roles} are automatically set to \code{epi_df} defaults. } +\keyword{internal} diff --git a/man/smooth_arx_args_list.Rd b/man/smooth_arx_args_list.Rd deleted file mode 100644 index d2843edb0..000000000 --- a/man/smooth_arx_args_list.Rd +++ /dev/null @@ -1,63 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/smooth_arx_forecaster.R -\name{smooth_arx_args_list} -\alias{smooth_arx_args_list} -\title{Smooth ARX forecaster argument constructor} -\usage{ -smooth_arx_args_list( - lags = c(0, 7, 14), - ahead = 1:28, - degree = 4, - kronecker_version = FALSE, - min_train_window = 20, - levels = c(0.05, 0.95), - intercept = TRUE, - symmetrize = TRUE, - nonneg = TRUE, - quantile_by_key = FALSE -) -} -\arguments{ -\item{lags}{Vector or List. Positive integers enumerating lags to use -in autoregressive-type models.} - -\item{ahead}{Integer. Number of time steps ahead of the forecast date -for which forecasts should be produced.} - -\item{degree}{Integer. Order of the orthodonal polynomials to use for -smoothing. Should be strictly less than \code{length(ahead)}.} - -\item{kronecker_version}{Logical. Do we ensure that we've "seen" the latest -\code{ahead} value. The default \code{FALSE} is computationally simpler but uses -less recent data.} - -\item{min_train_window}{Integer. The minimal amount of training -data needed to produce a forecast. If smaller, the forecaster will return -\code{NA} predictions.} - -\item{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{intercept}{Logical. The default \code{TRUE} includes intercept in the -forecaster.} - -\item{symmetrize}{Logical. The default \code{TRUE} calculates -symmetric prediction intervals.} - -\item{nonneg}{Logical. The default \code{TRUE} enforeces nonnegative predictions -by hard-thresholding at 0.} - -\item{quantile_by_key}{Not currently implemented.} -} -\value{ -A list containing updated parameter choices. -} -\description{ -Constructs a list of arguments for \code{\link[=smooth_arx_forecaster]{smooth_arx_forecaster()}}. -} -\examples{ -smooth_arx_args_list() -smooth_arx_args_list(symmetrize = FALSE) -smooth_arx_args_list(levels = c(.1, .3, .7, .9), min_train_window = 120) -} diff --git a/man/smooth_arx_forecaster.Rd b/man/smooth_arx_forecaster.Rd deleted file mode 100644 index ea6005e71..000000000 --- a/man/smooth_arx_forecaster.Rd +++ /dev/null @@ -1,34 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/smooth_arx_forecaster.R -\name{smooth_arx_forecaster} -\alias{smooth_arx_forecaster} -\title{Smooth AR forecaster with optional covariates} -\usage{ -smooth_arx_forecaster( - x, - y, - key_vars, - time_value, - args = smooth_arx_args_list() -) -} -\arguments{ -\item{x}{Covariates. Allowed to be missing (resulting in AR on \code{y}).} - -\item{y}{Response.} - -\item{key_vars}{Factor(s). A prediction will be made for each unique -combination.} - -\item{time_value}{the time value associated with each row of measurements.} - -\item{args}{Additional arguments specifying the forecasting task. Created -by calling \code{smooth_arx_args_list()}.} -} -\value{ -A data frame of point (and optionally interval) forecasts across -multiple aheads for each unique combination of \code{key_vars}. -} -\description{ -Smooth AR forecaster with optional covariates -} diff --git a/musings/arx_forecaster_old.R b/musings/arx_forecaster_old.R new file mode 100644 index 000000000..5dedfa1db --- /dev/null +++ b/musings/arx_forecaster_old.R @@ -0,0 +1,65 @@ +#' AR forecaster with optional covariates +#' +#' @param x Covariates. Allowed to be missing (resulting in AR on `y`). +#' @param y Response. +#' @param key_vars Factor(s). A prediction will be made for each unique +#' combination. +#' @param time_value the time value associated with each row of measurements. +#' @param args Additional arguments specifying the forecasting task. Created +#' by calling `arx_args_list()`. +#' +#' @return A data frame of point (and optionally interval) forecasts at a single +#' ahead (unique horizon) for each unique combination of `key_vars`. +#' @export +arx_forecaster <- function(x, y, key_vars, time_value, + args = arx_args_list()) { + + # TODO: function to verify standard forecaster signature inputs + + assign_arg_list(args) + if (is.null(key_vars)) { # this is annoying/repetitive, seemingly necessary? + keys <- NULL + distinct_keys <- tibble(.dump = NA) + } else { + keys <- tibble::tibble(key_vars) + distinct_keys <- dplyr::distinct(keys) + } + + # Return NA if insufficient training data + if (length(y) < min_train_window + max_lags + ahead) { + qnames <- probs_to_string(levels) + out <- dplyr::bind_cols(distinct_keys, point = NA) %>% + dplyr::select(!dplyr::any_of(".dump")) + return(enframer(out, qnames)) + } + + dat <- create_lags_and_leads(x, y, lags, ahead, time_value, keys) + dat$x0 <- 1 + + obj <- stats::lm( + y1 ~ . + 0, + data = dat %>% dplyr::select(starts_with(c("x", "y"))) + ) + + point <- make_predictions(obj, dat, time_value, keys) + + # Residuals, simplest case, requires + # 1. same quantiles for all keys + # 2. `residuals(obj)` works + r <- residuals(obj) + q <- residual_quantiles(r, point, levels, symmetrize) + + # Harder case requires handling failures of 1 and or 2, neither implemented + # 1. different quantiles by key, need to bind the keys, then group_modify + # 2 fails. need to bind the keys, grab, y and yhat, subtract + if (nonneg) { + q <- dplyr::mutate(q, dplyr::across(dplyr::everything(), ~ pmax(.x, 0))) + } + + return( + dplyr::bind_cols(distinct_keys, q) %>% + dplyr::select(!dplyr::any_of(".dump")) + ) +} + + diff --git a/R/assign_arg_list.R b/musings/assign_arg_list.R similarity index 100% rename from R/assign_arg_list.R rename to musings/assign_arg_list.R diff --git a/R/create_lags_and_leads.R b/musings/create_lags_and_leads.R similarity index 100% rename from R/create_lags_and_leads.R rename to musings/create_lags_and_leads.R diff --git a/R/knn_iterative_ar_forecaster.R b/musings/knn_iterative_ar_forecaster.R similarity index 100% rename from R/knn_iterative_ar_forecaster.R rename to musings/knn_iterative_ar_forecaster.R diff --git a/R/knnarx_forecaster.R b/musings/knnarx_forecaster.R similarity index 100% rename from R/knnarx_forecaster.R rename to musings/knnarx_forecaster.R diff --git a/R/make_predictions.R b/musings/make_predictions.R similarity index 100% rename from R/make_predictions.R rename to musings/make_predictions.R diff --git a/R/probs_to_string.R b/musings/probs_to_string.R similarity index 100% rename from R/probs_to_string.R rename to musings/probs_to_string.R diff --git a/R/residual_quantiles.R b/musings/residual_quantiles.R similarity index 100% rename from R/residual_quantiles.R rename to musings/residual_quantiles.R diff --git a/R/smooth_and_fit.R b/musings/smooth_and_fit.R similarity index 100% rename from R/smooth_and_fit.R rename to musings/smooth_and_fit.R diff --git a/R/smooth_arx_forecaster.R b/musings/smooth_arx_forecaster.R similarity index 100% rename from R/smooth_arx_forecaster.R rename to musings/smooth_arx_forecaster.R diff --git a/tests/testthat/test-arx.R b/musings/test-arx.R similarity index 61% rename from tests/testthat/test-arx.R rename to musings/test-arx.R index 99db1e8de..42c4a1472 100644 --- a/tests/testthat/test-arx.R +++ b/musings/test-arx.R @@ -1,23 +1,3 @@ -test_that("arx_args checks inputs", { - expect_error(arx_args_list(ahead = c(0, 4))) - expect_error(arx_args_list(min_train_window = c(28, 65))) - - expect_error(arx_args_list(ahead = -1)) - expect_error(arx_args_list(ahead = 1.5)) - expect_error(arx_args_list(min_train_window = -1)) - expect_error(arx_args_list(min_train_window = 1.5)) - expect_error(arx_args_list(lags = c(-1, 0))) - expect_error(arx_args_list(lags = list(c(1:5,6.5), 2:8))) - - expect_error(arx_args_list(symmetrize = 4)) - expect_error(arx_args_list(nonneg = 4)) - - expect_error(arx_args_list(levels = -.1)) - expect_error(arx_args_list(levels = 1.1)) - expect_type(arx_args_list(levels = NULL), "list") -}) - - test_that("arx returns proper empty tibble", { template1 <- tibble::tibble(key_vars = 1:10, point = NA) template1 <- enframer(template1, c("q0.05", "q0.95")) diff --git a/tests/testthat/test-assign_arg_list.R b/musings/test-assign_arg_list.R similarity index 100% rename from tests/testthat/test-assign_arg_list.R rename to musings/test-assign_arg_list.R diff --git a/tests/testthat/test-lags_and_leads.R b/musings/test-lags_and_leads.R similarity index 100% rename from tests/testthat/test-lags_and_leads.R rename to musings/test-lags_and_leads.R diff --git a/tests/testthat/test-make_predictions.R b/musings/test-make_predictions.R similarity index 100% rename from tests/testthat/test-make_predictions.R rename to musings/test-make_predictions.R diff --git a/tests/testthat/test-probs_to_string.R b/musings/test-probs_to_string.R similarity index 100% rename from tests/testthat/test-probs_to_string.R rename to musings/test-probs_to_string.R diff --git a/tests/testthat/test-smooth_and_fit.R b/musings/test-smooth_and_fit.R similarity index 100% rename from tests/testthat/test-smooth_and_fit.R rename to musings/test-smooth_and_fit.R diff --git a/tests/testthat/test-smooth_arx.R b/musings/test-smooth_arx.R similarity index 100% rename from tests/testthat/test-smooth_arx.R rename to musings/test-smooth_arx.R diff --git a/tests/testthat/test-arx_args_list.R b/tests/testthat/test-arx_args_list.R new file mode 100644 index 000000000..616e992fe --- /dev/null +++ b/tests/testthat/test-arx_args_list.R @@ -0,0 +1,19 @@ +test_that("arx_args checks inputs", { + expect_error(arx_args_list(ahead = c(0, 4))) + expect_error(arx_args_list(min_train_window = c(28, 65))) + + expect_error(arx_args_list(ahead = -1)) + expect_error(arx_args_list(ahead = 1.5)) + expect_error(arx_args_list(min_train_window = -1)) + expect_error(arx_args_list(min_train_window = 1.5)) + expect_error(arx_args_list(lags = c(-1, 0))) + expect_error(arx_args_list(lags = list(c(1:5,6.5), 2:8))) + + expect_error(arx_args_list(symmetrize = 4)) + expect_error(arx_args_list(nonneg = 4)) + + expect_error(arx_args_list(levels = -.1)) + expect_error(arx_args_list(levels = 1.1)) + expect_type(arx_args_list(levels = NULL), "list") +}) + diff --git a/vignettes/epipredict.Rmd b/vignettes/epipredict.Rmd index 5799509c0..e08748c49 100644 --- a/vignettes/epipredict.Rmd +++ b/vignettes/epipredict.Rmd @@ -103,7 +103,7 @@ We'll estimate the model jointly across all locations using only the most recent ```{r demo-workflow} jhu <- jhu %>% filter(time_value >= max(time_value) - 30) -out <- arx_epi_forecaster(jhu, outcome = "death_rate", +out <- arx_forecaster(jhu, outcome = "death_rate", predictors = c("case_rate", "death_rate") ) ``` @@ -131,7 +131,7 @@ knitr::opts_chunk$set(warning = FALSE, message = FALSE) ``` ```{r differential-lags} -out2week <- arx_epi_forecaster(jhu, "death_rate", c("case_rate", "death_rate"), +out2week <- arx_forecaster(jhu, "death_rate", c("case_rate", "death_rate"), args_list = arx_args_list( lags = list(c(0,1,2,3,7,14), c(0,7,14)), ahead = 14) @@ -145,7 +145,7 @@ Here, we've used different lags on the `case_rate` and are now predicting 2 week Another property of the basic model is the predictive interval. We describe this in more detail in a different vignette, but it is easy to request multiple quantiles. ```{r differential-levels} -out_q <- arx_epi_forecaster(jhu, "death_rate", c("case_rate", "death_rate"), +out_q <- arx_forecaster(jhu, "death_rate", c("case_rate", "death_rate"), args_list = arx_args_list( levels = c(.01,.025, seq(.05,.95, by=.05), .975,.99)) ) @@ -183,14 +183,14 @@ The `trainer` argument determines the type of model we want. This takes a [`{parsnip}`](https://parsnip.tidymodels.org) model. The default is linear regression, but we could instead use a random forest with the `{ranger}` package: ```{r ranger, warning = FALSE} -out_rf <- arx_epi_forecaster(jhu, "death_rate", c("case_rate", "death_rate"), +out_rf <- arx_forecaster(jhu, "death_rate", c("case_rate", "death_rate"), rand_forest(mode = "regression")) ``` Or boosted regression trees with `{xgboost}`: ```{r xgboost, warning = FALSE} -out_gb <- arx_epi_forecaster(jhu, "death_rate", c("case_rate", "death_rate"), +out_gb <- arx_forecaster(jhu, "death_rate", c("case_rate", "death_rate"), boost_tree(mode = "regression", trees = 20)) ``` @@ -290,7 +290,7 @@ To stretch the metaphor of preparing a cake to its natural limits, we have created postprocessing functionality called "frosting". Much like the recipe, each postprocessing operation is a "layer" and we "slather" these onto our baked cake. To fix ideas, below is the postprocessing `frosting` for -`arx_epi_forecaster()` +`arx_forecaster()` ```{r} extract_frosting(out_q$epi_workflow) @@ -328,7 +328,7 @@ But ideally, a user could create their own forecasters by building up the components we provide. In other vignettes, we try to walk through some of these customizations. -To illustrate everything above, here is (roughly) the code for the `flatline_epi_forecaster()` applied to the `case_rate`. +To illustrate everything above, here is (roughly) the code for the `flatline_forecaster()` applied to the `case_rate`. ```{r} r <- epi_recipe(jhu) %>%