diff --git a/DESCRIPTION b/DESCRIPTION index efa5125391..ff371b1ed3 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -89,6 +89,7 @@ Collate: 'count_occurrences_by_grade.R' 'count_patients_events_in_cols.R' 'count_patients_with_event.R' + 'count_patients_with_flags.R' 'count_values.R' 'cox_regression.R' 'cox_regression_inter.R' diff --git a/NEWS.md b/NEWS.md index ebf9aaa561..8dd2c3a3f5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -16,6 +16,8 @@ * Organization of `.gitignore` and `.Rbuildignore`. * Removed deprecated `footnotes` functions and all related files. * Deprecation cycle of `pairwise` function started. +* Moved `count_patients_with_flags` functions out of `count_patients_with_event.R` and + into `count_patients_with_flags.R`. # tern 0.8.0 diff --git a/R/count_patients_with_event.R b/R/count_patients_with_event.R index 8f459e23ff..b1eedb40b8 100644 --- a/R/count_patients_with_event.R +++ b/R/count_patients_with_event.R @@ -4,6 +4,8 @@ #' #' The primary analysis variable `.var` denotes the unique patient identifier. #' +#' @seealso [count_patients_with_flags] +#' #' @name count_patients_with_event NULL @@ -165,160 +167,3 @@ count_patients_with_event <- function(lyt, table_names = table_names ) } - -#' @describeIn count_patients_with_event Statistics function which counts the number of patients for which -#' a particular flag variable is `TRUE`. -#' -#' @inheritParams argument_convention -#' @param .var (`character`)\cr name of the column that contains the unique identifier. -#' @param flag_variables (`character`)\cr a character vector specifying the names of `logical` -#' variables from analysis dataset used for counting the number of unique identifiers. -#' @inheritParams summarize_variables -#' -#' @return -#' * `s_count_patients_with_flags()` returns the count and the fraction of unique identifiers with each particular -#' flag as a list of statistics `n`, `count`, `count_fraction`, and `n_blq`, with one element per flag. -#' -#' @export -#' -#' @examples -#' # `s_count_patients_with_flags()` -#' -#' # Add labelled flag variables to analysis dataset. -#' adae <- tern_ex_adae %>% -#' mutate( -#' fl1 = TRUE, -#' fl2 = TRTEMFL == "Y", -#' fl3 = TRTEMFL == "Y" & AEOUT == "FATAL", -#' fl4 = TRTEMFL == "Y" & AEOUT == "FATAL" & AEREL == "Y" -#' ) -#' labels <- c( -#' "fl1" = "Total AEs", -#' "fl2" = "Total number of patients with at least one adverse event", -#' "fl3" = "Total number of patients with fatal AEs", -#' "fl4" = "Total number of patients with related fatal AEs" -#' ) -#' formatters::var_labels(adae)[names(labels)] <- labels -#' -#' s_count_patients_with_flags( -#' adae, -#' "SUBJID", -#' flag_variables = c("fl1", "fl2", "fl3", "fl4"), -#' denom = "N_col", -#' .N_col = 1000 -#' ) -s_count_patients_with_flags <- function(df, - .var, - flag_variables, - .N_col, # nolint - .N_row, # nolint - denom = c("n", "N_row", "N_col")) { - if (is.null(names(flag_variables))) flag_variables <- stats::setNames(flag_variables, flag_variables) - flag_names <- unname(flag_variables) - flag_variables <- names(flag_variables) - - checkmate::assert_subset(flag_variables, colnames(df)) - temp <- sapply(flag_variables, function(x) { - tmp <- Map(function(y) which(df[[y]]), x) - position_satisfy_flags <- Reduce(intersect, tmp) - id_satisfy_flags <- as.character(unique(df[position_satisfy_flags, ][[.var]])) - s_count_values( - as.character(unique(df[[.var]])), - id_satisfy_flags, - denom = denom, - .N_col = .N_col, - .N_row = .N_row - ) - }) - colnames(temp) <- flag_names - temp <- data.frame(t(temp)) - result <- temp %>% as.list() - if (length(flag_variables) == 1) { - for (i in 1:3) names(result[[i]]) <- flag_names[1] - } - result -} - -#' @describeIn count_patients_with_event Formatted analysis function which is used as `afun` -#' in `count_patients_with_flags()`. -#' -#' @return -#' * `a_count_patients_with_flags()` returns the corresponding list with formatted [rtables::CellValue()]. -#' -#' @export -#' -#' @examples -#' # We need to ungroup `count_fraction` first so that the `rtables` formatting -#' # function `format_count_fraction()` can be applied correctly. -#' -#' # `a_count_patients_with_flags()` -#' -#' afun <- make_afun(a_count_patients_with_flags, -#' .stats = "count_fraction", -#' .ungroup_stats = "count_fraction" -#' ) -#' afun( -#' adae, -#' .N_col = 10L, # nolint -#' .N_row = 10L, -#' .var = "USUBJID", -#' flag_variables = c("fl1", "fl2", "fl3", "fl4") -#' ) -a_count_patients_with_flags <- make_afun( - s_count_patients_with_flags, - .formats = c("count_fraction" = format_count_fraction_fixed_dp) -) - -#' @describeIn count_patients_with_event Layout-creating function which can take statistics function -#' arguments and additional format arguments. This function is a wrapper for [rtables::analyze()]. -#' -#' @inheritParams argument_convention -#' -#' @return -#' * `count_patients_with_flags()` returns a layout object suitable for passing to further layouting functions, -#' or to [rtables::build_table()]. Adding this function to an `rtable` layout will add formatted rows containing -#' the statistics from `s_count_patients_with_flags()` to the table layout. -#' -#' @export -#' -#' @examples -#' # `count_patients_with_flags()` -#' -#' lyt2 <- basic_table() %>% -#' split_cols_by("ARM") %>% -#' add_colcounts() %>% -#' count_patients_with_flags( -#' "SUBJID", -#' flag_variables = formatters::var_labels(adae[, c("fl1", "fl2", "fl3", "fl4")]), -#' denom = "N_col" -#' ) -#' build_table(lyt2, adae, alt_counts_df = tern_ex_adsl) -count_patients_with_flags <- function(lyt, - var, - var_labels = var, - show_labels = "hidden", - ..., - table_names = paste0("tbl_flags_", var), - .stats = "count_fraction", - .formats = NULL, - .indent_mods = NULL) { - afun <- make_afun( - a_count_patients_with_flags, - .stats = .stats, - .formats = .formats, - .indent_mods = .indent_mods, - .ungroup_stats = .stats - ) - - lyt <- analyze( - lyt = lyt, - vars = var, - var_labels = var_labels, - show_labels = show_labels, - afun = afun, - table_names = table_names, - extra_args = list(...) - ) - - lyt -} diff --git a/R/count_patients_with_flags.R b/R/count_patients_with_flags.R new file mode 100644 index 0000000000..19e7a1bd69 --- /dev/null +++ b/R/count_patients_with_flags.R @@ -0,0 +1,168 @@ +#' Count the Number of Patients with Particular Flags +#' +#' @description `r lifecycle::badge("stable")` +#' +#' The primary analysis variable `.var` denotes the unique patient identifier. +#' +#' @inheritParams argument_convention +#' +#' @seealso [count_patients_with_event] +#' +#' @name count_patients_with_flags +NULL + +#' @describeIn count_patients_with_flags Statistics function which counts the number of patients for which +#' a particular flag variable is `TRUE`. +#' +#' @inheritParams summarize_variables +#' @param .var (`character`)\cr name of the column that contains the unique identifier. +#' @param flag_variables (`character`)\cr a character vector specifying the names of `logical` +#' variables from analysis dataset used for counting the number of unique identifiers. +#' +#' @return +#' * `s_count_patients_with_flags()` returns the count and the fraction of unique identifiers with each particular +#' flag as a list of statistics `n`, `count`, `count_fraction`, and `n_blq`, with one element per flag. +#' +#' @examples +#' library(dplyr) +#' +#' # `s_count_patients_with_flags()` +#' +#' # Add labelled flag variables to analysis dataset. +#' adae <- tern_ex_adae %>% +#' mutate( +#' fl1 = TRUE, +#' fl2 = TRTEMFL == "Y", +#' fl3 = TRTEMFL == "Y" & AEOUT == "FATAL", +#' fl4 = TRTEMFL == "Y" & AEOUT == "FATAL" & AEREL == "Y" +#' ) +#' labels <- c( +#' "fl1" = "Total AEs", +#' "fl2" = "Total number of patients with at least one adverse event", +#' "fl3" = "Total number of patients with fatal AEs", +#' "fl4" = "Total number of patients with related fatal AEs" +#' ) +#' formatters::var_labels(adae)[names(labels)] <- labels +#' +#' s_count_patients_with_flags( +#' adae, +#' "SUBJID", +#' flag_variables = c("fl1", "fl2", "fl3", "fl4"), +#' denom = "N_col", +#' .N_col = 1000 +#' ) +#' +#' @export +s_count_patients_with_flags <- function(df, + .var, + flag_variables, + .N_col, # nolint + .N_row, # nolint + denom = c("n", "N_row", "N_col")) { + if (is.null(names(flag_variables))) flag_variables <- stats::setNames(flag_variables, flag_variables) + flag_names <- unname(flag_variables) + flag_variables <- names(flag_variables) + + checkmate::assert_subset(flag_variables, colnames(df)) + temp <- sapply(flag_variables, function(x) { + tmp <- Map(function(y) which(df[[y]]), x) + position_satisfy_flags <- Reduce(intersect, tmp) + id_satisfy_flags <- as.character(unique(df[position_satisfy_flags, ][[.var]])) + s_count_values( + as.character(unique(df[[.var]])), + id_satisfy_flags, + denom = denom, + .N_col = .N_col, + .N_row = .N_row + ) + }) + colnames(temp) <- flag_names + temp <- data.frame(t(temp)) + result <- temp %>% as.list() + if (length(flag_variables) == 1) { + for (i in 1:3) names(result[[i]]) <- flag_names[1] + } + result +} + +#' @describeIn count_patients_with_flags Formatted analysis function which is used as `afun` +#' in `count_patients_with_flags()`. +#' +#' @return +#' * `a_count_patients_with_flags()` returns the corresponding list with formatted [rtables::CellValue()]. +#' +#' @examples +#' # We need to ungroup `count_fraction` first so that the `rtables` formatting +#' # function `format_count_fraction()` can be applied correctly. +#' +#' # `a_count_patients_with_flags()` +#' +#' afun <- make_afun(a_count_patients_with_flags, +#' .stats = "count_fraction", +#' .ungroup_stats = "count_fraction" +#' ) +#' afun( +#' adae, +#' .N_col = 10L, +#' .N_row = 10L, +#' .var = "USUBJID", +#' flag_variables = c("fl1", "fl2", "fl3", "fl4") +#' ) +#' +#' @export +a_count_patients_with_flags <- make_afun( + s_count_patients_with_flags, + .formats = c("count_fraction" = format_count_fraction_fixed_dp) +) + +#' @describeIn count_patients_with_flags Layout-creating function which can take statistics function +#' arguments and additional format arguments. This function is a wrapper for [rtables::analyze()]. +#' +#' @return +#' * `count_patients_with_flags()` returns a layout object suitable for passing to further layouting functions, +#' or to [rtables::build_table()]. Adding this function to an `rtable` layout will add formatted rows containing +#' the statistics from `s_count_patients_with_flags()` to the table layout. +#' +#' @examples +#' # `count_patients_with_flags()` +#' +#' lyt2 <- basic_table() %>% +#' split_cols_by("ARM") %>% +#' add_colcounts() %>% +#' count_patients_with_flags( +#' "SUBJID", +#' flag_variables = formatters::var_labels(adae[, c("fl1", "fl2", "fl3", "fl4")]), +#' denom = "N_col" +#' ) +#' build_table(lyt2, adae, alt_counts_df = tern_ex_adsl) +#' +#' @export +count_patients_with_flags <- function(lyt, + var, + var_labels = var, + show_labels = "hidden", + ..., + table_names = paste0("tbl_flags_", var), + .stats = "count_fraction", + .formats = NULL, + .indent_mods = NULL) { + afun <- make_afun( + a_count_patients_with_flags, + .stats = .stats, + .formats = .formats, + .indent_mods = .indent_mods, + .ungroup_stats = .stats + ) + + lyt <- analyze( + lyt = lyt, + vars = var, + var_labels = var_labels, + show_labels = show_labels, + afun = afun, + table_names = table_names, + extra_args = list(...) + ) + + lyt +} diff --git a/man/count_patients_with_event.Rd b/man/count_patients_with_event.Rd index d1b8111cb0..9d5d948fa7 100644 --- a/man/count_patients_with_event.Rd +++ b/man/count_patients_with_event.Rd @@ -4,9 +4,6 @@ \alias{count_patients_with_event} \alias{s_count_patients_with_event} \alias{a_count_patients_with_event} -\alias{s_count_patients_with_flags} -\alias{a_count_patients_with_flags} -\alias{count_patients_with_flags} \title{Count the Number of Patients with a Particular Event} \usage{ s_count_patients_with_event( @@ -37,36 +34,6 @@ count_patients_with_event( .labels = NULL, .indent_mods = NULL ) - -s_count_patients_with_flags( - df, - .var, - flag_variables, - .N_col, - .N_row, - denom = c("n", "N_row", "N_col") -) - -a_count_patients_with_flags( - df, - .var, - flag_variables, - .N_col, - .N_row, - denom = c("n", "N_row", "N_col") -) - -count_patients_with_flags( - lyt, - var, - var_labels = var, - show_labels = "hidden", - ..., - table_names = paste0("tbl_flags_", var), - .stats = "count_fraction", - .formats = NULL, - .indent_mods = NULL -) } \arguments{ \item{df}{(\code{data.frame})\cr data set containing all analysis variables.} @@ -107,16 +74,6 @@ to avoid warnings from \code{rtables}.} \item{.labels}{(named \code{character})\cr labels for the statistics (without indent).} \item{.indent_mods}{(named \code{integer})\cr indent modifiers for the labels.} - -\item{flag_variables}{(\code{character})\cr a character vector specifying the names of \code{logical} -variables from analysis dataset used for counting the number of unique identifiers.} - -\item{var}{(\code{string})\cr single variable name that is passed by \code{rtables} when requested -by a statistics function.} - -\item{var_labels}{(\code{character})\cr character for label.} - -\item{show_labels}{(\code{string})\cr label visibility: one of "default", "visible" and "hidden".} } \value{ \itemize{ @@ -132,21 +89,6 @@ by a statistics function.} or to \code{\link[rtables:build_table]{rtables::build_table()}}. Adding this function to an \code{rtable} layout will add formatted rows containing the statistics from \code{s_count_patients_with_event()} to the table layout. } - -\itemize{ -\item \code{s_count_patients_with_flags()} returns the count and the fraction of unique identifiers with each particular -flag as a list of statistics \code{n}, \code{count}, \code{count_fraction}, and \code{n_blq}, with one element per flag. -} - -\itemize{ -\item \code{a_count_patients_with_flags()} returns the corresponding list with formatted \code{\link[rtables:CellValue]{rtables::CellValue()}}. -} - -\itemize{ -\item \code{count_patients_with_flags()} returns a layout object suitable for passing to further layouting functions, -or to \code{\link[rtables:build_table]{rtables::build_table()}}. Adding this function to an \code{rtable} layout will add formatted rows containing -the statistics from \code{s_count_patients_with_flags()} to the table layout. -} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} @@ -164,15 +106,6 @@ in \code{count_patients_with_event()}. \item \code{count_patients_with_event()}: Layout-creating function which can take statistics function arguments and additional format arguments. This function is a wrapper for \code{\link[rtables:analyze]{rtables::analyze()}}. -\item \code{s_count_patients_with_flags()}: Statistics function which counts the number of patients for which -a particular flag variable is \code{TRUE}. - -\item \code{a_count_patients_with_flags()}: Formatted analysis function which is used as \code{afun} -in \code{count_patients_with_flags()}. - -\item \code{count_patients_with_flags()}: Layout-creating function which can take statistics function -arguments and additional format arguments. This function is a wrapper for \code{\link[rtables:analyze]{rtables::analyze()}}. - }} \examples{ library(dplyr) @@ -236,56 +169,7 @@ lyt <- basic_table() \%>\% table_names = "tbl_rel_fatal" ) build_table(lyt, tern_ex_adae, alt_counts_df = tern_ex_adsl) -# `s_count_patients_with_flags()` - -# Add labelled flag variables to analysis dataset. -adae <- tern_ex_adae \%>\% - mutate( - fl1 = TRUE, - fl2 = TRTEMFL == "Y", - fl3 = TRTEMFL == "Y" & AEOUT == "FATAL", - fl4 = TRTEMFL == "Y" & AEOUT == "FATAL" & AEREL == "Y" - ) -labels <- c( - "fl1" = "Total AEs", - "fl2" = "Total number of patients with at least one adverse event", - "fl3" = "Total number of patients with fatal AEs", - "fl4" = "Total number of patients with related fatal AEs" -) -formatters::var_labels(adae)[names(labels)] <- labels - -s_count_patients_with_flags( - adae, - "SUBJID", - flag_variables = c("fl1", "fl2", "fl3", "fl4"), - denom = "N_col", - .N_col = 1000 -) -# We need to ungroup `count_fraction` first so that the `rtables` formatting -# function `format_count_fraction()` can be applied correctly. - -# `a_count_patients_with_flags()` - -afun <- make_afun(a_count_patients_with_flags, - .stats = "count_fraction", - .ungroup_stats = "count_fraction" -) -afun( - adae, - .N_col = 10L, # nolint - .N_row = 10L, - .var = "USUBJID", - flag_variables = c("fl1", "fl2", "fl3", "fl4") -) -# `count_patients_with_flags()` - -lyt2 <- basic_table() \%>\% - split_cols_by("ARM") \%>\% - add_colcounts() \%>\% - count_patients_with_flags( - "SUBJID", - flag_variables = formatters::var_labels(adae[, c("fl1", "fl2", "fl3", "fl4")]), - denom = "N_col" - ) -build_table(lyt2, adae, alt_counts_df = tern_ex_adsl) +} +\seealso{ +\link{count_patients_with_flags} } diff --git a/man/count_patients_with_flags.Rd b/man/count_patients_with_flags.Rd new file mode 100644 index 0000000000..18ad30d0a5 --- /dev/null +++ b/man/count_patients_with_flags.Rd @@ -0,0 +1,173 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/count_patients_with_flags.R +\name{count_patients_with_flags} +\alias{count_patients_with_flags} +\alias{s_count_patients_with_flags} +\alias{a_count_patients_with_flags} +\title{Count the Number of Patients with Particular Flags} +\usage{ +s_count_patients_with_flags( + df, + .var, + flag_variables, + .N_col, + .N_row, + denom = c("n", "N_row", "N_col") +) + +a_count_patients_with_flags( + df, + .var, + flag_variables, + .N_col, + .N_row, + denom = c("n", "N_row", "N_col") +) + +count_patients_with_flags( + lyt, + var, + var_labels = var, + show_labels = "hidden", + ..., + table_names = paste0("tbl_flags_", var), + .stats = "count_fraction", + .formats = NULL, + .indent_mods = NULL +) +} +\arguments{ +\item{df}{(\code{data.frame})\cr data set containing all analysis variables.} + +\item{.var}{(\code{character})\cr name of the column that contains the unique identifier.} + +\item{flag_variables}{(\code{character})\cr a character vector specifying the names of \code{logical} +variables from analysis dataset used for counting the number of unique identifiers.} + +\item{.N_col}{(\code{count})\cr row-wise N (row group count) for the group of observations being analyzed +(i.e. with no column-based subsetting) that is passed by \code{rtables}.} + +\item{.N_row}{(\code{count})\cr column-wise N (column count) for the full column that is passed by \code{rtables}.} + +\item{denom}{(\code{string})\cr choice of denominator for proportion. Options are: +\itemize{ +\item \code{n}: number of values in this row and column intersection. +\item \code{N_row}: total number of values in this row across columns. +\item \code{N_col}: total number of values in this column across rows. +}} + +\item{lyt}{(\code{layout})\cr input layout where analyses will be added to.} + +\item{var}{(\code{string})\cr single variable name that is passed by \code{rtables} when requested +by a statistics function.} + +\item{var_labels}{(\code{character})\cr character for label.} + +\item{show_labels}{(\code{string})\cr label visibility: one of "default", "visible" and "hidden".} + +\item{...}{additional arguments for the lower level functions.} + +\item{table_names}{(\code{character})\cr this can be customized in case that the same \code{vars} are analyzed multiple times, +to avoid warnings from \code{rtables}.} + +\item{.stats}{(\code{character})\cr statistics to select for the table.} + +\item{.formats}{(named \code{character} or \code{list})\cr formats for the statistics.} + +\item{.indent_mods}{(named \code{integer})\cr indent modifiers for the labels.} +} +\value{ +\itemize{ +\item \code{s_count_patients_with_flags()} returns the count and the fraction of unique identifiers with each particular +flag as a list of statistics \code{n}, \code{count}, \code{count_fraction}, and \code{n_blq}, with one element per flag. +} + +\itemize{ +\item \code{a_count_patients_with_flags()} returns the corresponding list with formatted \code{\link[rtables:CellValue]{rtables::CellValue()}}. +} + +\itemize{ +\item \code{count_patients_with_flags()} returns a layout object suitable for passing to further layouting functions, +or to \code{\link[rtables:build_table]{rtables::build_table()}}. Adding this function to an \code{rtable} layout will add formatted rows containing +the statistics from \code{s_count_patients_with_flags()} to the table layout. +} +} +\description{ +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} + +The primary analysis variable \code{.var} denotes the unique patient identifier. +} +\section{Functions}{ +\itemize{ +\item \code{s_count_patients_with_flags()}: Statistics function which counts the number of patients for which +a particular flag variable is \code{TRUE}. + +\item \code{a_count_patients_with_flags()}: Formatted analysis function which is used as \code{afun} +in \code{count_patients_with_flags()}. + +\item \code{count_patients_with_flags()}: Layout-creating function which can take statistics function +arguments and additional format arguments. This function is a wrapper for \code{\link[rtables:analyze]{rtables::analyze()}}. + +}} +\examples{ +library(dplyr) + +# `s_count_patients_with_flags()` + +# Add labelled flag variables to analysis dataset. +adae <- tern_ex_adae \%>\% + mutate( + fl1 = TRUE, + fl2 = TRTEMFL == "Y", + fl3 = TRTEMFL == "Y" & AEOUT == "FATAL", + fl4 = TRTEMFL == "Y" & AEOUT == "FATAL" & AEREL == "Y" + ) +labels <- c( + "fl1" = "Total AEs", + "fl2" = "Total number of patients with at least one adverse event", + "fl3" = "Total number of patients with fatal AEs", + "fl4" = "Total number of patients with related fatal AEs" +) +formatters::var_labels(adae)[names(labels)] <- labels + +s_count_patients_with_flags( + adae, + "SUBJID", + flag_variables = c("fl1", "fl2", "fl3", "fl4"), + denom = "N_col", + .N_col = 1000 +) + +# We need to ungroup `count_fraction` first so that the `rtables` formatting +# function `format_count_fraction()` can be applied correctly. + +# `a_count_patients_with_flags()` + +afun <- make_afun(a_count_patients_with_flags, + .stats = "count_fraction", + .ungroup_stats = "count_fraction" +) +afun( + adae, + .N_col = 10L, + .N_row = 10L, + .var = "USUBJID", + flag_variables = c("fl1", "fl2", "fl3", "fl4") +) + +# `count_patients_with_flags()` + +lyt2 <- basic_table() \%>\% + split_cols_by("ARM") \%>\% + add_colcounts() \%>\% + count_patients_with_flags( + "SUBJID", + flag_variables = formatters::var_labels(adae[, c("fl1", "fl2", "fl3", "fl4")]), + denom = "N_col" + ) +build_table(lyt2, adae, alt_counts_df = tern_ex_adsl) + +} +\seealso{ +\link{count_patients_with_event} +} diff --git a/tests/testthat/_snaps/count_patients_with_event.md b/tests/testthat/_snaps/count_patients_with_event.md index ae92b6e107..36f5d902d4 100644 --- a/tests/testthat/_snaps/count_patients_with_event.md +++ b/tests/testthat/_snaps/count_patients_with_event.md @@ -56,109 +56,6 @@ Total number of patients with at least one adverse event 1 (16.7%) 1 (25.0%) Total number of patients with fatal AEs 0 1 (25.0%) -# s_count_patients_with_flags handles NA - - Code - res - Output - $n - $n$TRTEMFL - [1] 2 - - - $count - $count$TRTEMFL - [1] 2 - - - $count_fraction - $count_fraction$TRTEMFL - [1] 2 1 - - - $n_blq - $n_blq[[1]] - [1] 0 - - - -# s_count_patients_with_flags handles multiple columns - - Code - res - Output - $n - $n$TRTEMFL - [1] 3 - - $n$AEOUTFL - [1] 3 - - - $count - $count$TRTEMFL - [1] 3 - - $count$AEOUTFL - [1] 1 - - - $count_fraction - $count_fraction$TRTEMFL - [1] 3 1 - - $count_fraction$AEOUTFL - [1] 1.0000000 0.3333333 - - - $n_blq - $n_blq$TRTEMFL - [1] 0 - - $n_blq$AEOUTFL - [1] 0 - - - -# count_patients_with_flags works as expected - - Code - res - Output - A B - (N=6) (N=4) - ———————————————————————————————————————————————————————————————————————————————— - Total number of patients with at least one adverse event 1 (16.7%) 1 (25.0%) - Total number of patients with fatal AEs 0 1 (25.0%) - -# count_patients_with_flags works as expected when specifying table_names - - Code - res - Output - A B - (N=6) (N=4) - ———————————————————————————————————————————————————————————————————————————————— - Total number of patients with at least one adverse event 1 (16.7%) 1 (25.0%) - Total number of patients with fatal AEs 0 1 (25.0%) - Total number of patients with at least one adverse event 1 (16.7%) 1 (25.0%) - Total number of patients with fatal AEs 0 1 (25.0%) - -# count_patients_with_flags works with label row specified - - Code - res - Output - A: Drug X B: Placebo C: Combination - (N=69) (N=73) (N=58) - ——————————————————————————————————————————————————————————————————————————————————————————————————— - Total number of patients with at least one adverse event 59 (85.5%) 57 (78.1%) 48 (82.8%) - Total number of patients with at least one - Serious AE 45 (65.2%) 46 (63.0%) 37 (63.8%) - Related AE 49 (71.0%) 48 (65.8%) 40 (69.0%) - Grade 3-5 AE 47 (68.1%) 46 (63.0%) 41 (70.7%) - Grade 4/5 AE 34 (49.3%) 38 (52.1%) 32 (55.2%) - # s_count_patients_with_event works with factor filters Code diff --git a/tests/testthat/_snaps/count_patients_with_flags.md b/tests/testthat/_snaps/count_patients_with_flags.md new file mode 100644 index 0000000000..4d72632aae --- /dev/null +++ b/tests/testthat/_snaps/count_patients_with_flags.md @@ -0,0 +1,103 @@ +# s_count_patients_with_flags handles NA + + Code + res + Output + $n + $n$TRTEMFL + [1] 2 + + + $count + $count$TRTEMFL + [1] 2 + + + $count_fraction + $count_fraction$TRTEMFL + [1] 2 1 + + + $n_blq + $n_blq[[1]] + [1] 0 + + + +# s_count_patients_with_flags handles multiple columns + + Code + res + Output + $n + $n$TRTEMFL + [1] 3 + + $n$AEOUTFL + [1] 3 + + + $count + $count$TRTEMFL + [1] 3 + + $count$AEOUTFL + [1] 1 + + + $count_fraction + $count_fraction$TRTEMFL + [1] 3 1 + + $count_fraction$AEOUTFL + [1] 1.0000000 0.3333333 + + + $n_blq + $n_blq$TRTEMFL + [1] 0 + + $n_blq$AEOUTFL + [1] 0 + + + +# count_patients_with_flags works as expected + + Code + res + Output + A B + (N=6) (N=4) + ———————————————————————————————————————————————————————————————————————————————— + Total number of patients with at least one adverse event 1 (16.7%) 1 (25.0%) + Total number of patients with fatal AEs 0 1 (25.0%) + +# count_patients_with_flags works as expected when specifying table_names + + Code + res + Output + A B + (N=6) (N=4) + ———————————————————————————————————————————————————————————————————————————————— + Total number of patients with at least one adverse event 1 (16.7%) 1 (25.0%) + Total number of patients with fatal AEs 0 1 (25.0%) + Total number of patients with at least one adverse event 1 (16.7%) 1 (25.0%) + Total number of patients with fatal AEs 0 1 (25.0%) + +# count_patients_with_flags works with label row specified + + Code + res + Output + A: Drug X B: Placebo C: Combination + (N=69) (N=73) (N=58) + ——————————————————————————————————————————————————————————————————————————————————————————————————— + Total number of patients with at least one adverse event 59 (85.5%) 57 (78.1%) 48 (82.8%) + Total number of patients with at least one + Serious AE 45 (65.2%) 46 (63.0%) 37 (63.8%) + Related AE 49 (71.0%) 48 (65.8%) 40 (69.0%) + Grade 3-5 AE 47 (68.1%) 46 (63.0%) 41 (70.7%) + Grade 4/5 AE 34 (49.3%) 38 (52.1%) 32 (55.2%) + diff --git a/tests/testthat/test-count_patients_with_event.R b/tests/testthat/test-count_patients_with_event.R index 8733f315ee..56fea1aa1b 100644 --- a/tests/testthat/test-count_patients_with_event.R +++ b/tests/testthat/test-count_patients_with_event.R @@ -101,168 +101,6 @@ testthat::test_that("count_patients_with_event works as expected for different c testthat::expect_snapshot(res) }) -testthat::test_that("s_count_patients_with_flags handles NA", { - test_data <- data.frame( - SUBJID = c("1001", "1001", "1001", "1002", "1002", "1002"), - TRTEMFL = c(TRUE, FALSE, FALSE, NA, FALSE, TRUE), - stringsAsFactors = FALSE - ) - result <- s_count_patients_with_flags( - test_data, - .var = "SUBJID", - flag_variables = "TRTEMFL" - ) - - res <- testthat::expect_silent(result) - testthat::expect_snapshot(res) -}) - -testthat::test_that("s_count_patients_with_flags handles multiple columns", { - test_data <- data.frame( - SUBJID = c("1001", "1001", "1001", "1002", "1002", "1002", "1003", "1003", "1003"), - TRTEMFL = c(TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE), - AEOUTFL = c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE), - stringsAsFactors = FALSE - ) - result <- s_count_patients_with_flags( - test_data, - .var = "SUBJID", - flag_variables = c("TRTEMFL", "AEOUTFL") - ) - - res <- testthat::expect_silent(result) - testthat::expect_snapshot(res) -}) - -testthat::test_that("count_patients_with_flags works as expected", { - test_data <- tibble::tibble( - SUBJID = c("1001", "1001", "1001", "1002", "1002", "1002", "1003", "1003", "1003"), - ARM = factor(c("A", "A", "A", "A", "A", "A", "B", "B", "B"), levels = c("A", "B")), - TRTEMFL = c("Y", "", "", "NA", "", "", "Y", "", ""), - AEOUT = c("", "", "", "", "", "", "FATAL", "", "FATAL") - ) - test_data <- test_data %>% - dplyr::mutate( - flag1 = TRTEMFL == "Y", - flag2 = TRTEMFL == "Y" & AEOUT == "FATAL", - ) - labels <- c( - "A", - "B", - "C", - "D", - "Total number of patients with at least one adverse event", - "Total number of patients with fatal AEs" - ) - formatters::var_labels(test_data) <- labels - - test_adsl_like <- tibble::tibble( - SUBJID = as.character(1001:1010), - ARM = factor(c("A", "A", "B", "B", "A", "A", "A", "B", "B", "A"), levels = c("A", "B")), - stringsAsFactors = FALSE - ) - - lyt <- basic_table() %>% - split_cols_by("ARM") %>% - add_colcounts() %>% - count_patients_with_flags( - "SUBJID", - flag_variables = formatters::var_labels(test_data[, c("flag1", "flag2")]), - denom = "N_col" - ) - result <- build_table(lyt, df = test_data, alt_counts_df = test_adsl_like) - - res <- testthat::expect_silent(result) - testthat::expect_snapshot(res) -}) - -testthat::test_that("count_patients_with_flags works as expected when specifying table_names", { - test_data <- tibble::tibble( - USUBJID = c("1001", "1001", "1001", "1002", "1002", "1002", "1003", "1003", "1003"), - SUBJID = c("1001", "1001", "1001", "1002", "1002", "1002", "1003", "1003", "1003"), - ARM = factor(c("A", "A", "A", "A", "A", "A", "B", "B", "B"), levels = c("A", "B")), - TRTEMFL = c("Y", "", "", "NA", "", "", "Y", "", ""), - AEOUT = c("", "", "", "", "", "", "FATAL", "", "FATAL") - ) - test_data <- test_data %>% - dplyr::mutate( - flag1 = TRTEMFL == "Y", - flag2 = TRTEMFL == "Y" & AEOUT == "FATAL", - ) - columns <- c("flag1", "flag2") - labels <- c( - "Total number of patients with at least one adverse event", - "Total number of patients with fatal AEs" - ) - formatters::var_labels(test_data)[columns] <- labels - - test_adsl_like <- tibble::tibble( - USUBJID = as.character(1001:1010), - SUBJID = as.character(1001:1010), - ARM = factor(c("A", "A", "B", "B", "A", "A", "A", "B", "B", "A"), levels = c("A", "B")), - stringsAsFactors = FALSE - ) - - lyt <- basic_table() %>% - split_cols_by("ARM") %>% - add_colcounts() %>% - count_patients_with_flags( - "SUBJID", - flag_variables = formatters::var_labels(test_data[, c("flag1", "flag2")]), - table_names = "SUBJID", - denom = "N_col" - ) %>% - count_patients_with_flags( - "USUBJID", - flag_variables = formatters::var_labels(test_data[, c("flag1", "flag2")]), - table_names = "USUBJID", - denom = "N_col" - ) - result <- build_table(lyt, df = test_data, alt_counts_df = test_adsl_like) - - res <- testthat::expect_silent(result) - testthat::expect_snapshot(res) -}) - -testthat::test_that("count_patients_with_flags works with label row specified", { - # Create custom flags: - adae_local <- tern_ex_adae %>% - dplyr::mutate( - SER = AESER == "Y", - REL = AEREL == "Y", - CTC35 = AETOXGR %in% c("3", "4", "5"), - CTC45 = AETOXGR %in% c("4", "5") - ) - columns <- c("SER", "REL", "CTC35", "CTC45") - labels <- c("Serious AE", "Related AE", "Grade 3-5 AE", "Grade 4/5 AE") - for (i in seq_along(columns)) { - attr(adae_local[[columns[i]]], "label") <- labels[i] - } - aesi_vars <- c("SER", "REL", "CTC35", "CTC45") - - # Create layout - lyt <- basic_table() %>% - split_cols_by("ACTARM") %>% - add_colcounts() %>% - count_patients_with_event( - vars = "USUBJID", - filters = c("STUDYID" = as.character(unique(adae_local$STUDYID))), - denom = "N_col", - .labels = c(count_fraction = "Total number of patients with at least one adverse event") - ) %>% - count_patients_with_flags( - "USUBJID", - flag_variables = formatters::var_labels(adae_local[, aesi_vars]), - denom = "N_col", - var_labels = "Total number of patients with at least one", - show_labels = "visible" - ) - result <- build_table(lyt, df = adae_local, alt_counts_df = tern_ex_adsl) - - res <- testthat::expect_silent(result) - testthat::expect_snapshot(res) -}) - testthat::test_that("s_count_patients_with_event works with factor filters", { test_data <- data.frame( SUBJID = c("1001", "1001", "1001", "1002", "1002", "1002", "1003", "1003", "1003"), diff --git a/tests/testthat/test-count_patients_with_flags.R b/tests/testthat/test-count_patients_with_flags.R new file mode 100644 index 0000000000..e92bc5522f --- /dev/null +++ b/tests/testthat/test-count_patients_with_flags.R @@ -0,0 +1,161 @@ +testthat::test_that("s_count_patients_with_flags handles NA", { + test_data <- data.frame( + SUBJID = c("1001", "1001", "1001", "1002", "1002", "1002"), + TRTEMFL = c(TRUE, FALSE, FALSE, NA, FALSE, TRUE), + stringsAsFactors = FALSE + ) + result <- s_count_patients_with_flags( + test_data, + .var = "SUBJID", + flag_variables = "TRTEMFL" + ) + + res <- testthat::expect_silent(result) + testthat::expect_snapshot(res) +}) + +testthat::test_that("s_count_patients_with_flags handles multiple columns", { + test_data <- data.frame( + SUBJID = c("1001", "1001", "1001", "1002", "1002", "1002", "1003", "1003", "1003"), + TRTEMFL = c(TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE), + AEOUTFL = c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE), + stringsAsFactors = FALSE + ) + result <- s_count_patients_with_flags( + test_data, + .var = "SUBJID", + flag_variables = c("TRTEMFL", "AEOUTFL") + ) + + res <- testthat::expect_silent(result) + testthat::expect_snapshot(res) +}) + +testthat::test_that("count_patients_with_flags works as expected", { + test_data <- tibble::tibble( + SUBJID = c("1001", "1001", "1001", "1002", "1002", "1002", "1003", "1003", "1003"), + ARM = factor(c("A", "A", "A", "A", "A", "A", "B", "B", "B"), levels = c("A", "B")), + TRTEMFL = c("Y", "", "", "NA", "", "", "Y", "", ""), + AEOUT = c("", "", "", "", "", "", "FATAL", "", "FATAL") + ) + test_data <- test_data %>% + dplyr::mutate( + flag1 = TRTEMFL == "Y", + flag2 = TRTEMFL == "Y" & AEOUT == "FATAL", + ) + labels <- c( + "A", + "B", + "C", + "D", + "Total number of patients with at least one adverse event", + "Total number of patients with fatal AEs" + ) + formatters::var_labels(test_data) <- labels + + test_adsl_like <- tibble::tibble( + SUBJID = as.character(1001:1010), + ARM = factor(c("A", "A", "B", "B", "A", "A", "A", "B", "B", "A"), levels = c("A", "B")), + stringsAsFactors = FALSE + ) + + lyt <- basic_table() %>% + split_cols_by("ARM") %>% + add_colcounts() %>% + count_patients_with_flags( + "SUBJID", + flag_variables = formatters::var_labels(test_data[, c("flag1", "flag2")]), + denom = "N_col" + ) + result <- build_table(lyt, df = test_data, alt_counts_df = test_adsl_like) + + res <- testthat::expect_silent(result) + testthat::expect_snapshot(res) +}) + +testthat::test_that("count_patients_with_flags works as expected when specifying table_names", { + test_data <- tibble::tibble( + USUBJID = c("1001", "1001", "1001", "1002", "1002", "1002", "1003", "1003", "1003"), + SUBJID = c("1001", "1001", "1001", "1002", "1002", "1002", "1003", "1003", "1003"), + ARM = factor(c("A", "A", "A", "A", "A", "A", "B", "B", "B"), levels = c("A", "B")), + TRTEMFL = c("Y", "", "", "NA", "", "", "Y", "", ""), + AEOUT = c("", "", "", "", "", "", "FATAL", "", "FATAL") + ) + test_data <- test_data %>% + dplyr::mutate( + flag1 = TRTEMFL == "Y", + flag2 = TRTEMFL == "Y" & AEOUT == "FATAL", + ) + columns <- c("flag1", "flag2") + labels <- c( + "Total number of patients with at least one adverse event", + "Total number of patients with fatal AEs" + ) + formatters::var_labels(test_data)[columns] <- labels + + test_adsl_like <- tibble::tibble( + USUBJID = as.character(1001:1010), + SUBJID = as.character(1001:1010), + ARM = factor(c("A", "A", "B", "B", "A", "A", "A", "B", "B", "A"), levels = c("A", "B")), + stringsAsFactors = FALSE + ) + + lyt <- basic_table() %>% + split_cols_by("ARM") %>% + add_colcounts() %>% + count_patients_with_flags( + "SUBJID", + flag_variables = formatters::var_labels(test_data[, c("flag1", "flag2")]), + table_names = "SUBJID", + denom = "N_col" + ) %>% + count_patients_with_flags( + "USUBJID", + flag_variables = formatters::var_labels(test_data[, c("flag1", "flag2")]), + table_names = "USUBJID", + denom = "N_col" + ) + result <- build_table(lyt, df = test_data, alt_counts_df = test_adsl_like) + + res <- testthat::expect_silent(result) + testthat::expect_snapshot(res) +}) + +testthat::test_that("count_patients_with_flags works with label row specified", { + # Create custom flags: + adae_local <- tern_ex_adae %>% + dplyr::mutate( + SER = AESER == "Y", + REL = AEREL == "Y", + CTC35 = AETOXGR %in% c("3", "4", "5"), + CTC45 = AETOXGR %in% c("4", "5") + ) + columns <- c("SER", "REL", "CTC35", "CTC45") + labels <- c("Serious AE", "Related AE", "Grade 3-5 AE", "Grade 4/5 AE") + for (i in seq_along(columns)) { + attr(adae_local[[columns[i]]], "label") <- labels[i] + } + aesi_vars <- c("SER", "REL", "CTC35", "CTC45") + + # Create layout + lyt <- basic_table() %>% + split_cols_by("ACTARM") %>% + add_colcounts() %>% + count_patients_with_event( + vars = "USUBJID", + filters = c("STUDYID" = as.character(unique(adae_local$STUDYID))), + denom = "N_col", + .labels = c(count_fraction = "Total number of patients with at least one adverse event") + ) %>% + count_patients_with_flags( + "USUBJID", + flag_variables = formatters::var_labels(adae_local[, aesi_vars]), + denom = "N_col", + var_labels = "Total number of patients with at least one", + show_labels = "visible" + ) + result <- build_table(lyt, df = adae_local, alt_counts_df = tern_ex_adsl) + + res <- testthat::expect_silent(result) + testthat::expect_snapshot(res) +})