From 21d01669d9d71024279046afcb7be9aca4656dbf Mon Sep 17 00:00:00 2001 From: James Azam Date: Wed, 20 Mar 2024 15:22:13 +0000 Subject: [PATCH] Deprecate `adjust_infection_to_report()`, `report_cases()`, and `sample_approx_dist()` (#597) * Deprecate adjust_infection_to_report() * Deprecate sample_approx_dist() * Deprecate report_cases() * Generate .Rd file * Add NEWS item * Fix wrong function name in NEWS * Linting: turn off missing_argument_linter for deprecation warning * Linting: use file.path() to construct paths instead of paste0. * Remove unnecessary nolint tags * Remove trailing comma * Add more details to deprecation warning * Assign details argument explicitly * Add pointers to replacement functions in the deprecation warnings * Revise example in report_cases to show use of simulate_secondary() * Refer to the right function in warning message * Revise examples in adjust_infection_to_reports to demonstrate use of simulate_secondary * Remove trailing whitespace --------- Co-authored-by: Sebastian Funk --- NEWS.md | 1 + R/adjust.R | 96 ++++++++++--------- R/report.R | 45 ++++++--- man/adjust_infection_to_report.Rd | 69 ++++++------- man/report_cases.Rd | 34 ++++--- man/sample_approx_dist.Rd | 2 +- .../test-adjust_infection_to_report.R | 26 ++--- tests/testthat/test-dist.R | 11 +++ tests/testthat/test-report_cases.R | 16 ++++ 9 files changed, 175 insertions(+), 125 deletions(-) diff --git a/NEWS.md b/NEWS.md index 9dd14e34c..f1e347d7d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,6 +10,7 @@ * A new `simulate_infections` function has been added that can be used to simulate from the model from given initial conditions and parameters. By @sbfnk in #557 and reviewed by @jamesmbaazam. * The function `init_cumulative_fit()` has been deprecated. By @jamesmbaazam in #541 and reviewed by @sbfnk. * The interface to generating delay distributions has been completely overhauled. Instead of calling `dist_spec()` users now specify distributions using functions that represent the available distributions, i.e. `LogNormal()`, `Gamma()` and `Fixed()`. Uncertainty is specified using calls of the same nature, to `Normal()`. More information on the underlying design can be found in `inst/dev/design_dist.md` By @sbfnk in #504 and reviewed by @seabbs. +* The functions `sample_approx_dist()`, `report_cases()`, and `adjust_infection_reports()` have been deprecated as the functionality they provide can now be achieved with `simulate_secondary()`. See #597 by @jamesmbaazam and reviewed by @sbfnk. ## Documentation diff --git a/R/adjust.R b/R/adjust.R index 87ded8c27..6f9c1dbe1 100644 --- a/R/adjust.R +++ b/R/adjust.R @@ -1,6 +1,6 @@ #' Adjust from Case Counts by Infection Date to Date of Report #' -#' @description `r lifecycle::badge("stable")` +#' @description `r lifecycle::badge("deprecated")` #' Maps from cases by date of infection to date of report via date of #' onset. #' @param infections `` containing a `date` variable and a numeric @@ -25,63 +25,59 @@ #' @inheritParams sample_approx_dist #' @importFrom data.table setorder data.table data.table #' @importFrom lubridate wday +#' @importFrom lifecycle deprecate_warn #' @examples #' \donttest{ -#' # define example cases -#' cases <- data.table::copy(example_confirmed)[, cases := as.integer(confirm)] +#' # This function is deprecated and its functionality can now be accessed +#' # from [simulate_secondary()]. +#' # Here are some examples of how to use [simulate_secondary()] to replace +#' # adjust_infection_to_report(). #' -#' # define a single report delay distribution +#' # Old (using adjust_infection_to_report()): +#' # Define example case data +#' cases <- data.table::copy(example_confirmed) +#' cases <- cases[, cases := as.integer(confirm)] +#' # Define a simple reporting delay distribution #' delay_def <- lognorm_dist_def( -#' mean = 5, mean_sd = 1, sd = 3, sd_sd = 1, -#' max_value = 30, samples = 1, to_log = TRUE -#' ) -#' -#' # define a single incubation period -#' incubation_def <- lognorm_dist_def( -#' mean = incubation_periods[1, ]$mean, -#' mean_sd = incubation_periods[1, ]$mean_sd, -#' sd = incubation_periods[1, ]$sd, -#' sd_sd = incubation_periods[1, ]$sd_sd, -#' max_value = 30, samples = 1 +#' mean = 5, mean_sd = 1, sd = 3, sd_sd = 1, +#' max_value = 30, samples = 1, to_log = TRUE #' ) -#' -#' # simple mapping #' report <- adjust_infection_to_report( -#' cases, delay_defs = list(incubation_def, delay_def) +#' cases, +#' delay_defs = list(delay_def), +#' reporting_model = function(n) rpois(length(n), n) #' ) #' print(report) #' -#' # mapping with a weekly reporting effect -#' report_weekly <- adjust_infection_to_report( -#' cases, -#' delay_defs = list(incubation_def, delay_def), -#' reporting_effect = c(1.1, rep(1, 4), 0.95, 0.95) +#' # New (using simulate_secondary()): +#' cases <- data.table::copy(example_confirmed) +#' cases <- cases[, primary := as.integer(confirm)] +#' uncertain_delay <- LogNormal( +#' mean = Normal(5, 1), sd = Normal(3, 1), +#' max = 30 #' ) -#' print(report_weekly) -#' -#' # map using a deterministic median shift for both delays -#' report_median <- adjust_infection_to_report(cases, -#' delay_defs = list(incubation_def, delay_def), -#' type = "median" +#' delay <- fix_dist(uncertain_delay, strategy = "sample") +#' report <- simulate_secondary( +#' cases, +#' delays = delay_opts(delay), +#' obs = obs_opts(family = "poisson") #' ) -#' print(report_median) -#' -#' # map with a weekly reporting effect and stochastic reporting model -#' report_stochastic <- adjust_infection_to_report( -#' cases, -#' delay_defs = list(incubation_def, delay_def), -#' reporting_effect = c(1.1, rep(1, 4), 0.95, 0.95), -#' reporting_model = function(n) { -#' out <- suppressWarnings(rnbinom(length(n), as.integer(n), 0.5)) -#' out <- ifelse(is.na(out), 0, out) -#' } -#' ) -#' print(report_stochastic) +#' print(report) #' } adjust_infection_to_report <- function(infections, delay_defs, reporting_model, reporting_effect, type = "sample", truncate_future = TRUE) { + deprecate_warn( + when = "1.5.0", + what = "adjust_infection_to_report()", + with = "simulate_secondary()", + details = c( + "See equivalent examples using `simulate_secondary()`", + "in ?adjust_infection_to_report.", + "This function will be removed completely in version 2.0.0." + ) + ) # Reset DT Defaults on Exit set_dt_single_thread() @@ -100,14 +96,14 @@ adjust_infection_to_report <- function(infections, delay_defs, ## Infection to onset - out <- EpiNow2::sample_approx_dist( + out <- suppressWarnings(EpiNow2::sample_approx_dist( cases = input, dist_fn = sample_delay_fn, max_value = delay_def$max_value, direction = "forwards", type = type, truncate_future = FALSE - ) + )) return(out) } @@ -124,14 +120,14 @@ adjust_infection_to_report <- function(infections, delay_defs, } ## Infection to onset - out <- EpiNow2::sample_approx_dist( + out <- suppressWarnings(EpiNow2::sample_approx_dist( cases = input, dist_fn = sample_delay_fn, max_value = max(delay_def), direction = "forwards", type = type, truncate_future = FALSE - ) + )) return(out) } @@ -186,7 +182,7 @@ adjust_infection_to_report <- function(infections, delay_defs, #' Approximate Sampling a Distribution using Counts #' -#' @description `r lifecycle::badge("soft-deprecated")` +#' @description `r lifecycle::badge("deprecated")` #' Convolves cases by a PMF function. This function will soon be removed or #' replaced with a more robust stan implementation. #' @@ -218,6 +214,7 @@ adjust_infection_to_report <- function(infections, delay_defs, #' @importFrom purrr map_dfc #' @importFrom data.table data.table setorder #' @importFrom lubridate days +#' @importFrom lifecycle deprecate_warn #' @examples #' \donttest{ #' cases <- example_confirmed @@ -279,6 +276,11 @@ sample_approx_dist <- function(cases = NULL, direction = "backwards", type = "sample", truncate_future = TRUE) { + deprecate_warn( + "1.5.0", + "sample_approx_dist()", + details = "The function will be removed completely in version 2.0.0." + ) if (type == "sample") { if (direction == "backwards") { direction_fn <- rev diff --git a/R/report.R b/R/report.R index a055118b1..afc5b34de 100644 --- a/R/report.R +++ b/R/report.R @@ -1,6 +1,6 @@ #' Report case counts by date of report #' -#' @description `r lifecycle::badge("soft-deprecated")` +#' @description `r lifecycle::badge("deprecated")` #' Convolves latent infections to reported cases via an observation model. #' Likely to be removed/replaced in later releases by functionality drawing on #' the `stan` implementation. @@ -27,23 +27,36 @@ #' @inheritParams adjust_infection_to_report #' @importFrom data.table data.table rbindlist #' @importFrom future.apply future_lapply +#' @importFrom lifecycle deprecate_warn #' @examples #' \donttest{ -#' # define example cases +#' # This function is deprecated and its functionality can now be accessed +#' # from [simulate_secondary()]. +#' # Here are some examples of how to use [simulate_secondary()] to replace +#' # report_cases(). +#' # Old (using report_cases()): +#' # Define case data #' cases <- example_confirmed[1:40] -#' -#' # get example delays -#' # Instead of running them model we use example -#' # data for speed in this example. #' cases <- cases[, cases := as.integer(confirm)] #' cases <- cases[, confirm := NULL][, sample := 1] -#' #' reported_cases <- report_cases( -#' case_estimates = cases, -#' delays = delay_opts(example_incubation_period + example_reporting_delay), -#' type = "sample" +#' case_estimates = cases, +#' delays = delay_opts(example_incubation_period + example_reporting_delay), +#' type = "sample" #' ) -#' print(reported_cases) +#' print(reported_cases$samples) +#' +#' # New (using simulate_secondary()): +#' cases <- example_confirmed[1:40] +#' cases <- cases[, primary := as.integer(confirm)] +#' report <- simulate_secondary( +#' cases, +#' delays = delay_opts( +#' fix_dist(example_incubation_period + example_reporting_delay) +#' ), +#' obs = obs_opts(family = "poisson") +#' ) +#' print(report) #' } report_cases <- function(case_estimates, case_forecast = NULL, @@ -51,6 +64,16 @@ report_cases <- function(case_estimates, type = "sample", reporting_effect, CrIs = c(0.2, 0.5, 0.9)) { + deprecate_warn( + when = "1.5.0", + what = "report_cases()", + with = "simulate_secondary()", + details = c( + "See equivalent examples using `simulate_secondary()`", + "in ?report_cases.", + "This function will be removed completely in version 2.0.0." + ) + ) samples <- length(unique(case_estimates$sample)) # add a null reporting effect if missing diff --git a/man/adjust_infection_to_report.Rd b/man/adjust_infection_to_report.Rd index 6501c1dfb..9c952d6de 100644 --- a/man/adjust_infection_to_report.Rd +++ b/man/adjust_infection_to_report.Rd @@ -42,61 +42,46 @@ A \code{data.table} containing a \code{date} variable (date of report) and a \code{reference} which indicates what the date variable refers to. } \description{ -\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Maps from cases by date of infection to date of report via date of onset. } \examples{ \donttest{ -# define example cases -cases <- data.table::copy(example_confirmed)[, cases := as.integer(confirm)] +# This function is deprecated and its functionality can now be accessed +# from [simulate_secondary()]. +# Here are some examples of how to use [simulate_secondary()] to replace +# adjust_infection_to_report(). -# define a single report delay distribution +# Old (using adjust_infection_to_report()): +# Define example case data +cases <- data.table::copy(example_confirmed) +cases <- cases[, cases := as.integer(confirm)] +# Define a simple reporting delay distribution delay_def <- lognorm_dist_def( - mean = 5, mean_sd = 1, sd = 3, sd_sd = 1, - max_value = 30, samples = 1, to_log = TRUE + mean = 5, mean_sd = 1, sd = 3, sd_sd = 1, + max_value = 30, samples = 1, to_log = TRUE ) - -# define a single incubation period -incubation_def <- lognorm_dist_def( - mean = incubation_periods[1, ]$mean, - mean_sd = incubation_periods[1, ]$mean_sd, - sd = incubation_periods[1, ]$sd, - sd_sd = incubation_periods[1, ]$sd_sd, - max_value = 30, samples = 1 -) - -# simple mapping report <- adjust_infection_to_report( - cases, delay_defs = list(incubation_def, delay_def) + cases, + delay_defs = list(delay_def), + reporting_model = function(n) rpois(length(n), n) ) print(report) -# mapping with a weekly reporting effect -report_weekly <- adjust_infection_to_report( - cases, - delay_defs = list(incubation_def, delay_def), - reporting_effect = c(1.1, rep(1, 4), 0.95, 0.95) +# New (using simulate_secondary()): +cases <- data.table::copy(example_confirmed) +cases <- cases[, primary := as.integer(confirm)] +uncertain_delay <- LogNormal( + mean = Normal(5, 1), sd = Normal(3, 1), + max = 30 ) -print(report_weekly) - -# map using a deterministic median shift for both delays -report_median <- adjust_infection_to_report(cases, - delay_defs = list(incubation_def, delay_def), - type = "median" +delay <- fix_dist(uncertain_delay, strategy = "sample") +report <- simulate_secondary( + cases, + delays = delay_opts(delay), + obs = obs_opts(family = "poisson") ) -print(report_median) - -# map with a weekly reporting effect and stochastic reporting model -report_stochastic <- adjust_infection_to_report( - cases, - delay_defs = list(incubation_def, delay_def), - reporting_effect = c(1.1, rep(1, 4), 0.95, 0.95), - reporting_model = function(n) { - out <- suppressWarnings(rnbinom(length(n), as.integer(n), 0.5)) - out <- ifelse(is.na(out), 0, out) - } -) -print(report_stochastic) +print(report) } } diff --git a/man/report_cases.Rd b/man/report_cases.Rd index e7d13a026..64b2b921e 100644 --- a/man/report_cases.Rd +++ b/man/report_cases.Rd @@ -43,27 +43,39 @@ variables \code{sample}, \code{date} and \code{cases} with the second being summ across samples. } \description{ -\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#soft-deprecated}{\figure{lifecycle-soft-deprecated.svg}{options: alt='[Soft-deprecated]'}}}{\strong{[Soft-deprecated]}} +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Convolves latent infections to reported cases via an observation model. Likely to be removed/replaced in later releases by functionality drawing on the \code{stan} implementation. } \examples{ \donttest{ -# define example cases +# This function is deprecated and its functionality can now be accessed +# from [simulate_secondary()]. +# Here are some examples of how to use [simulate_secondary()] to replace +# report_cases(). +# Old (using report_cases()): +# Define case data cases <- example_confirmed[1:40] - -# get example delays -# Instead of running them model we use example -# data for speed in this example. cases <- cases[, cases := as.integer(confirm)] cases <- cases[, confirm := NULL][, sample := 1] - reported_cases <- report_cases( - case_estimates = cases, - delays = delay_opts(example_incubation_period + example_reporting_delay), - type = "sample" + case_estimates = cases, + delays = delay_opts(example_incubation_period + example_reporting_delay), + type = "sample" +) +print(reported_cases$samples) + +# New (using simulate_secondary()): +cases <- example_confirmed[1:40] +cases <- cases[, primary := as.integer(confirm)] +report <- simulate_secondary( + cases, + delays = delay_opts( + fix_dist(example_incubation_period + example_reporting_delay) + ), + obs = obs_opts(family = "poisson") ) -print(reported_cases) +print(report) } } diff --git a/man/sample_approx_dist.Rd b/man/sample_approx_dist.Rd index d21926e1d..b579cf9af 100644 --- a/man/sample_approx_dist.Rd +++ b/man/sample_approx_dist.Rd @@ -42,7 +42,7 @@ after the first date reported in the data. Defaults to \code{TRUE}.} A \verb{} of cases by date of onset } \description{ -\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#soft-deprecated}{\figure{lifecycle-soft-deprecated.svg}{options: alt='[Soft-deprecated]'}}}{\strong{[Soft-deprecated]}} +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Convolves cases by a PMF function. This function will soon be removed or replaced with a more robust stan implementation. } diff --git a/tests/testthat/test-adjust_infection_to_report.R b/tests/testthat/test-adjust_infection_to_report.R index 33e8502f4..078e7c7c1 100644 --- a/tests/testthat/test-adjust_infection_to_report.R +++ b/tests/testthat/test-adjust_infection_to_report.R @@ -8,10 +8,10 @@ delay <- LogNormal( ) test_that("adjust_infection_to_report can correctly handle a simple mapping", { - reports <- adjust_infection_to_report( + reports <- suppressWarnings(adjust_infection_to_report( cases, delay_defs = example_incubation_period + delay - ) + )) expect_true(nrow(reports) > 80) expect_true(all(!is.infinite(reports$cases))) expect_true(all(!is.na(reports$cases))) @@ -19,23 +19,23 @@ test_that("adjust_infection_to_report can correctly handle a simple mapping", { test_that("adjust_infection_to_report can correctly handle a mapping with a day of the week effect", { - reports <- adjust_infection_to_report( + reports <- suppressWarnings(adjust_infection_to_report( cases, delay_defs = example_incubation_period + delay, reporting_effect = c(1.1, rep(1, 4), 0.95, 0.95) - ) + )) expect_true(nrow(reports) > 80) expect_true(all(!is.infinite(reports$cases))) expect_true(all(!is.na(reports$cases))) }) -test_that("passing data tables to adjust_infection_to_report is deprecated", { - suppressWarnings(delay_def <- lognorm_dist_def( - mean = 5, mean_sd = 1, sd = 3, sd_sd = 1, - max_value = 30, samples = 1, to_log = TRUE - )) - expect_deprecated(adjust_infection_to_report( - cases, - delay_defs = list(delay_def) - )) +test_that("deprecated functions are deprecated", { + # define example cases + cases <- data.table::copy(example_confirmed)[, cases := as.integer(confirm)] + expect_deprecated( + adjust_infection_to_report( + cases, + delay_defs = example_incubation_period + delay, + ) + ) }) diff --git a/tests/testthat/test-dist.R b/tests/testthat/test-dist.R index c54f1ec22..084f34859 100644 --- a/tests/testthat/test-dist.R +++ b/tests/testthat/test-dist.R @@ -21,6 +21,17 @@ test_that("distributions are the same in R and stan", { }) test_that("deprecated functions are deprecated", { + delay_fn <- function(n, dist, cum) { + pgamma(n + 0.9999, 2, 1) - pgamma(n - 1e-5, 2, 1) + } + expect_deprecated( + sample_approx_dist( + cases = example_confirmed[1:5], + dist_fn = delay_fn, + direction = "forwards", + type = "median" + ) + ) args <- list(mean = 3, mean_sd = 0, sd = 2, sd_sd = 0, max_value = 15) expect_deprecated( do.call(lognorm_dist_def, (c(args, list(samples = 1))))$params[[1]] diff --git a/tests/testthat/test-report_cases.R b/tests/testthat/test-report_cases.R index e646ce7a9..9518c24fb 100644 --- a/tests/testthat/test-report_cases.R +++ b/tests/testthat/test-report_cases.R @@ -19,3 +19,19 @@ test_that("report_cases can simulate infections forward", { expect_equal(class(reported_cases$summarised$median), "numeric") set.seed(Sys.time()) }) + +test_that("deprecated functions are deprecated", { + cases <- example_confirmed[1:40] + # get example delays + #' # Instead of running them model we use example + #' # data for speed in this example. + cases <- cases[, cases := as.integer(confirm)] + cases <- cases[, confirm := NULL][, sample := 1] + expect_deprecated( + report_cases( + case_estimates = cases, + delays = delay_opts(example_incubation_period + example_reporting_delay), + type = "sample" + ) + ) +})