From 6b41d95e0507388b04e536c4d86744dea30a3c9c Mon Sep 17 00:00:00 2001 From: Emily de la Rua <59304861+edelarua@users.noreply.github.com> Date: Thu, 5 Sep 2024 10:53:40 -0400 Subject: [PATCH] Add `n_rate` statistic to `estimate_incidence_rate()` (#1295) Fixes #1294 --- NEWS.md | 1 + R/incidence_rate.R | 12 +++++++--- R/utils_default_stats_formats_labels.R | 2 +- man/incidence_rate.Rd | 3 ++- .../_snaps/estimate_incidence_rate.md | 17 +++++++++++++ tests/testthat/test-estimate_incidence_rate.R | 24 +++++++++++++++++++ 6 files changed, 54 insertions(+), 5 deletions(-) diff --git a/NEWS.md b/NEWS.md index abf0852771..f730e23c73 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,6 +5,7 @@ * Added the `.formats` argument to `tabulate_rsp_subgroups` and `tabulate_survival_subgroups` to allow users to specify formats. * Added the `riskdiff` argument to `tabulate_rsp_subgroups` and `tabulate_survival_subgroups` to allow users to add a risk difference table column, and function `control_riskdiff` to specify settings for the risk difference column. * Added warning to `tabulate_rsp_subgroups` when `pval` statistic is selected but `df` has not been correctly generated to add p-values to the output table. +* Added `n_rate` statistic as a non-default option to `estimate_incidence_rate` which returns both number of events observed and estimated incidence rate. ### Bug Fixes * Fixed a bug in `a_surv_time` that threw an error when split only has `"is_event"`. diff --git a/R/incidence_rate.R b/R/incidence_rate.R index 7c86c448e9..2fda506e3b 100644 --- a/R/incidence_rate.R +++ b/R/incidence_rate.R @@ -33,6 +33,7 @@ NULL #' - `n_events`: Total number of events observed. #' - `rate`: Estimated incidence rate. #' - `rate_ci`: Confidence interval for the incidence rate. +#' - `n_rate`: Total number of events observed & estimated incidence rate. #' #' @keywords internal s_incidence_rate <- function(df, @@ -77,7 +78,11 @@ s_incidence_rate <- function(df, person_years = formatters::with_label(person_years, "Total patient-years at risk"), n_events = formatters::with_label(n_events, "Number of adverse events observed"), rate = formatters::with_label(result$rate, paste("AE rate per", num_pt_year, "patient-years")), - rate_ci = formatters::with_label(result$rate_ci, f_conf_level(conf_level)) + rate_ci = formatters::with_label(result$rate_ci, f_conf_level(conf_level)), + n_rate = formatters::with_label( + c(n_events, result$rate), + paste("Number of adverse events observed (AE rate per", num_pt_year, "patient-years)") + ) ) } @@ -94,7 +99,8 @@ a_incidence_rate <- make_afun( "person_years" = "xx.x", "n_events" = "xx", "rate" = "xx.xx", - "rate_ci" = "(xx.xx, xx.xx)" + "rate_ci" = "(xx.xx, xx.xx)", + "n_rate" = "xx (xx.x)" ) ) @@ -142,7 +148,7 @@ estimate_incidence_rate <- function(lyt, ..., show_labels = "hidden", table_names = vars, - .stats = NULL, + .stats = c("person_years", "n_events", "rate", "rate_ci"), .formats = NULL, .labels = NULL, .indent_mods = NULL) { diff --git a/R/utils_default_stats_formats_labels.R b/R/utils_default_stats_formats_labels.R index 824f946061..34cc8937a1 100644 --- a/R/utils_default_stats_formats_labels.R +++ b/R/utils_default_stats_formats_labels.R @@ -382,7 +382,7 @@ tern_default_stats <- list( count_patients_with_flags = c("n", "count", "count_fraction", "count_fraction_fixed_dp", "n_blq"), count_values = c("n", "count", "count_fraction", "count_fraction_fixed_dp", "n_blq"), coxph_pairwise = c("pvalue", "hr", "hr_ci", "n_tot", "n_tot_events"), - estimate_incidence_rate = c("person_years", "n_events", "rate", "rate_ci"), + estimate_incidence_rate = c("person_years", "n_events", "rate", "rate_ci", "n_rate"), estimate_multinomial_response = c("n_prop", "prop_ci"), estimate_odds_ratio = c("or_ci", "n_tot"), estimate_proportion = c("n_prop", "prop_ci"), diff --git a/man/incidence_rate.Rd b/man/incidence_rate.Rd index d0d0c4d337..33f5f7e63e 100644 --- a/man/incidence_rate.Rd +++ b/man/incidence_rate.Rd @@ -17,7 +17,7 @@ estimate_incidence_rate( ..., show_labels = "hidden", table_names = vars, - .stats = NULL, + .stats = c("person_years", "n_events", "rate", "rate_ci"), .formats = NULL, .labels = NULL, .indent_mods = NULL @@ -102,6 +102,7 @@ the statistics from \code{s_incidence_rate()} to the table layout. \item \code{n_events}: Total number of events observed. \item \code{rate}: Estimated incidence rate. \item \code{rate_ci}: Confidence interval for the incidence rate. +\item \code{n_rate}: Total number of events observed & estimated incidence rate. } } diff --git a/tests/testthat/_snaps/estimate_incidence_rate.md b/tests/testthat/_snaps/estimate_incidence_rate.md index ba28293ec4..7133820dea 100644 --- a/tests/testthat/_snaps/estimate_incidence_rate.md +++ b/tests/testthat/_snaps/estimate_incidence_rate.md @@ -101,6 +101,11 @@ attr(,"label") [1] "90% CI" + $n_rate + [1] 4.00000 44.15823 + attr(,"label") + [1] "Number of adverse events observed (AE rate per 100 patient-years)" + # estimate_incidence_rate works as expected with healthy input @@ -115,3 +120,15 @@ AE rate per 100 patient-years 26.20 57.23 90% CI (5.06, 135.73) (22.14, 147.94) +# estimate_incidence_rate `n_rate` statistic works as expected + + Code + res + Output + A B + (N=3) (N=3) + ————————————————————————————————————————————————————————————————————————————————————— + Number of adverse events observed 1 3 + AE rate per 100 patient-years 2.18 4.77 + Number of adverse events observed (AE rate per 100 patient-years) 1 (2.2) 3 (4.8) + diff --git a/tests/testthat/test-estimate_incidence_rate.R b/tests/testthat/test-estimate_incidence_rate.R index f83173e1a2..2befdfa96f 100644 --- a/tests/testthat/test-estimate_incidence_rate.R +++ b/tests/testthat/test-estimate_incidence_rate.R @@ -109,3 +109,27 @@ testthat::test_that("estimate_incidence_rate works as expected with healthy inpu res <- testthat::expect_silent(result) testthat::expect_snapshot(res) }) + +testthat::test_that("estimate_incidence_rate `n_rate` statistic works as expected", { + df <- data.frame( + USUBJID = as.character(seq(6)), + CNSR = c(0, 1, 1, 0, 0, 0), + AVAL = c(10.1, 20.4, 15.3, 20.8, 18.7, 23.4), + ARM = factor(c("A", "A", "A", "B", "B", "B")) + ) %>% + dplyr::mutate(is_event = CNSR == 0) %>% + dplyr::mutate(n_events = as.integer(is_event)) + + result <- basic_table() %>% + split_cols_by("ARM") %>% + add_colcounts() %>% + estimate_incidence_rate( + vars = "AVAL", + n_events = "n_events", + .stats = c("n_events", "rate", "n_rate") + ) %>% + build_table(df) + + res <- testthat::expect_silent(result) + testthat::expect_snapshot(res) +})