diff --git a/DESCRIPTION b/DESCRIPTION index d11ce3f552..a619323ceb 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -38,8 +38,9 @@ LazyData: true Roxygen: list(markdown = TRUE) RoxygenNote: 7.2.3 Depends: R (>= 4.0) +Remotes: pharmaverse/admiraldev Imports: - admiraldev (>= 0.4.0), + admiraldev (>= 0.5.0.9000), dplyr (>= 0.8.4), hms (>= 0.5.3), lifecycle (>= 0.1.0), diff --git a/NEWS.md b/NEWS.md index aa9fb1f807..63e964f32b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -17,6 +17,10 @@ character vector (`'--DTC'`), was imputed. (#2146) were enhanced such that more than one summary variable can be derived, e.g., `AVAL` as the sum and `ADT` as the maximum of the contributing records. (#1792) +- `derive_summary_records()` was enhanced with the following optional arguments: `dataset_add`, `dataset_ref`, `missing_values`. These arguments respectively, generate summary variables from additional datasets, retain/add specific records from a reference dataset, and impute user-defined missing values. `derive_param_exposure()` was enhanced with `dataset_add` as well. (#2142) + +- The argument `dataset` is now optional for `derive_summary_records()` and `derive_param_exposure()`. (#2142) + - The "joined" functions (`derive_vars_joined()`, `derive_var_joined_exist_flag()`, `filter_joined()`, and `event_joined()`) were unified: (#2126) - The `dataset_add` and `filter_add` arguments were added to @@ -37,6 +41,7 @@ were enhanced such that more than one summary variable can be derived, e.g., allow more control of the selection of records. It creates a temporary variable for the event number, which can be used in `order`. (#2140) + ## Breaking Changes - `derive_extreme_records()` the `dataset_add` argument is now mandatory. (#2139) @@ -45,6 +50,8 @@ for the event number, which can be used in `order`. (#2140) `analysis_var` and `summary_fun` were deprecated in favor of `set_values_to`. (#1792) +- In `derive_summary_records()` and `derive_param_exposure()` the argument `filter` was renamed to `filter_add` (#2142) + - In `derive_var_merged_summary()` the arguments `new_var`, `analysis_var`, and `summary_fun` were deprecated in favor of `new_vars`. (#1792) diff --git a/R/derive_param_exposure.R b/R/derive_param_exposure.R index 3c0e81c6b3..8430aa7d89 100644 --- a/R/derive_param_exposure.R +++ b/R/derive_param_exposure.R @@ -4,17 +4,43 @@ #' start (`ASTDT(M)`)and end date (`AENDT(M)`) as the minimum and maximum date by `by_vars`. #' #' @param dataset -#' `r roxygen_param_dataset(expected_vars = c("by_vars", "analysis_var"))` -#' `PARAMCD` is expected as well, -#' + Either `ASTDTM` and `AENDTM` or `ASTDT` and `AENDT` are also expected. +#' `r roxygen_param_dataset(expected_vars = c("by_vars"))` #' -#' @param filter Filter condition +#' @param dataset_add Additional dataset #' -#' The specified condition is applied to the input dataset before deriving the -#' new parameter, i.e., only observations fulfilling the condition are taken -#' into account. +#' The variables specified for `by_vars`, `analysis_var`, `PARAMCD`, +#' alongside either `ASTDTM` and `AENDTM` or `ASTDT` and `AENDT` are also expected. +#' Observations from the specified dataset are going to be used to calculate and added +#' as new records to the input dataset (`dataset`). #' -#' *Permitted Values:* a condition +#' +#' @param filter +#' +#' `r lifecycle::badge("deprecated")` Please use `filter_add` instead. +#' +#' Filter condition as logical expression to apply during +#' summary calculation. By default, filtering expressions are computed within +#' `by_vars` as this will help when an aggregating, lagging, or ranking +#' function is involved. +#' +#' For example, +#' +#' + `filter = (AVAL > mean(AVAL, na.rm = TRUE))` will filter all `AVAL` +#' values greater than mean of `AVAL` with in `by_vars`. +#' + `filter = (dplyr::n() > 2)` will filter n count of `by_vars` greater +#' than 2. +#' +#' @param filter_add Filter condition as logical expression to apply during +#' summary calculation. By default, filtering expressions are computed within +#' `by_vars` as this will help when an aggregating, lagging, or ranking +#' function is involved. +#' +#' For example, +#' +#' + `filter_add = (AVAL > mean(AVAL, na.rm = TRUE))` will filter all `AVAL` +#' values greater than mean of `AVAL` with in `by_vars`. +#' + `filter_add = (dplyr::n() > 2)` will filter n count of `by_vars` greater +#' than 2. #' #' @param input_code Required parameter code #' @@ -95,6 +121,7 @@ #' # Cumulative dose #' adex %>% #' derive_param_exposure( +#' dataset_add = adex, #' by_vars = exprs(USUBJID), #' set_values_to = exprs(PARAMCD = "TDOSE", PARCAT1 = "OVERALL"), #' input_code = "DOSE", @@ -106,6 +133,7 @@ #' # average dose in w2-24 #' adex %>% #' derive_param_exposure( +#' dataset_add = adex, #' by_vars = exprs(USUBJID), #' filter = VISIT %in% c("WEEK 2", "WEEK 24"), #' set_values_to = exprs(PARAMCD = "AVDW224", PARCAT1 = "WEEK2-24"), @@ -118,6 +146,7 @@ #' # Any dose adjustment? #' adex %>% #' derive_param_exposure( +#' dataset_add = adex, #' by_vars = exprs(USUBJID), #' set_values_to = exprs(PARAMCD = "TADJ", PARCAT1 = "OVERALL"), #' input_code = "ADJ", @@ -125,12 +154,14 @@ #' summary_fun = function(x) if_else(sum(!is.na(x)) > 0, "Y", NA_character_) #' ) %>% #' select(-ASTDTM, -AENDTM) -derive_param_exposure <- function(dataset, +derive_param_exposure <- function(dataset = NULL, + dataset_add, by_vars, input_code, analysis_var, summary_fun, filter = NULL, + filter_add = NULL, set_values_to = NULL) { by_vars <- assert_vars(by_vars) analysis_var <- assert_symbol(enexpr(analysis_var)) @@ -155,10 +186,20 @@ derive_param_exposure <- function(dataset, ) } - assert_data_frame(dataset, + assert_data_frame(dataset, required_vars = by_vars, optional = TRUE) + assert_data_frame(dataset_add, required_vars = expr_c(by_vars, analysis_var, exprs(PARAMCD), dates) ) - filter <- assert_filter_cond(enexpr(filter), optional = TRUE) + + if (!missing(filter)) { + deprecate_warn( + "1.0.0", + I("derive_param_exposure(filter = )"), + "derive_param_exposure(filter_add = )" + ) + filter_add <- assert_filter_cond(enexpr(filter), optional = TRUE) + } + filter_add <- assert_filter_cond(enexpr(filter_add), optional = TRUE) assert_varval_list(set_values_to, required_elements = "PARAMCD") assert_param_does_not_exist(dataset, set_values_to$PARAMCD) assert_character_scalar(input_code) @@ -166,14 +207,15 @@ derive_param_exposure <- function(dataset, assert_character_vector(input_code, values = params_available) assert_s3_class(summary_fun, "function") - if (is.null(filter)) { - filter <- TRUE + if (is.null(filter_add)) { + filter_add <- TRUE } derive_summary_records( dataset, + dataset_add, by_vars = by_vars, - filter = PARAMCD == !!input_code & !!filter, + filter_add = PARAMCD == !!input_code & !!filter_add, set_values_to = exprs( !!analysis_var := {{ summary_fun }}(!!analysis_var), !!!set_dtm, diff --git a/R/derive_summary_records.R b/R/derive_summary_records.R index ced3a0093e..77e8a7d8a9 100644 --- a/R/derive_summary_records.R +++ b/R/derive_summary_records.R @@ -11,13 +11,29 @@ #' retain those common values in the newly derived records. Otherwise new value #' will be set to `NA`. #' -#' @param dataset `r roxygen_param_dataset(expected_vars = c("by_vars", "analysis_var"))` +#' @param dataset `r roxygen_param_dataset(expected_vars = c("by_vars"))` +#' +#' @param dataset_add Additional dataset +#' +#' The variables specified for `by_vars` are expected. +#' Observations from the specified dataset are going to be used to calculate and added +#' as new records to the input dataset (`dataset`). +#' +#' @param dataset_ref Reference dataset +#' +#' The variables specified for `by_vars` are expected. For each +#' observation of the specified dataset a new observation is added to the +#' input dataset. #' #' @param by_vars Variables to consider for generation of groupwise summary #' records. Providing the names of variables in [exprs()] will create a #' groupwise summary and generate summary records for the specified groups. #' -#' @param filter Filter condition as logical expression to apply during +#' @param filter +#' +#' `r lifecycle::badge("deprecated")` Please use `filter_add` instead. +#' +#' Filter condition as logical expression to apply during #' summary calculation. By default, filtering expressions are computed within #' `by_vars` as this will help when an aggregating, lagging, or ranking #' function is involved. @@ -29,6 +45,46 @@ #' + `filter = (dplyr::n() > 2)` will filter n count of `by_vars` greater #' than 2. #' +#' @param filter_add Filter condition as logical expression to apply during +#' summary calculation. By default, filtering expressions are computed within +#' `by_vars` as this will help when an aggregating, lagging, or ranking +#' function is involved. +#' +#' For example, +#' +#' + `filter_add = (AVAL > mean(AVAL, na.rm = TRUE))` will filter all `AVAL` +#' values greater than mean of `AVAL` with in `by_vars`. +#' + `filter_add = (dplyr::n() > 2)` will filter n count of `by_vars` greater +#' than 2. +#' +#' @param set_values_to Variables to be set +#' +#' The specified variables are set to the specified values for the new +#' observations. +#' +#' Set a list of variables to some specified value for the new records +#' + LHS refer to a variable. +#' + RHS refers to the values to set to the variable. This can be a string, a +#' symbol, a numeric value, an expression or NA. If summary functions are +#' used, the values are summarized by the variables specified for `by_vars`. +#' +#' For example: +#' ``` +#' set_values_to = exprs( +#' AVAL = sum(AVAL), +#' DTYPE = "AVERAGE", +#' ) +#' ``` +#' +#' @param missing_values Values for missing summary values +#' +#' For observations of the reference dataset (`dataset_ref`) which do not have a +#' complete mapping defined by the summarization defined in `set_values_to`. Only variables +#' specified for `set_values_to` can be specified for `missing_values`. +#' +#' *Permitted Values*: named list of expressions, e.g., +#' `exprs(AVAL = -9999)` +#' #' @inheritParams get_summary_records #' #' @return A data frame with derived records appended to original dataset. @@ -72,6 +128,7 @@ #' # Summarize the average of the triplicate ECG interval values (AVAL) #' derive_summary_records( #' adeg, +#' dataset_add = adeg, #' by_vars = exprs(USUBJID, PARAM, AVISIT), #' set_values_to = exprs( #' AVAL = mean(AVAL, na.rm = TRUE), @@ -83,6 +140,7 @@ #' # Derive more than one summary variable #' derive_summary_records( #' adeg, +#' dataset_add = adeg, #' by_vars = exprs(USUBJID, PARAM, AVISIT), #' set_values_to = exprs( #' AVAL = mean(AVAL), @@ -116,27 +174,36 @@ #' # by group #' derive_summary_records( #' adeg, +#' dataset_add = adeg, #' by_vars = exprs(USUBJID, PARAM, AVISIT), -#' filter = n() > 2, +#' filter_add = n() > 2, #' set_values_to = exprs( #' AVAL = mean(AVAL, na.rm = TRUE), #' DTYPE = "AVERAGE" #' ) #' ) %>% #' arrange(USUBJID, AVISIT) -derive_summary_records <- function(dataset, +derive_summary_records <- function(dataset = NULL, + dataset_add, + dataset_ref = NULL, by_vars, filter = NULL, + filter_add = NULL, analysis_var, summary_fun, - set_values_to) { + set_values_to, + missing_values = NULL) { assert_vars(by_vars) - filter <- assert_filter_cond(enexpr(filter), optional = TRUE) + assert_data_frame(dataset, required_vars = by_vars, optional = TRUE) + assert_data_frame(dataset_add, required_vars = by_vars) assert_data_frame( - dataset, - required_vars = by_vars + dataset_ref, + required_vars = by_vars, + optional = TRUE ) + assert_varval_list(set_values_to) + assert_expr_list(missing_values, named = TRUE, optional = TRUE) if (!missing(analysis_var) || !missing(summary_fun)) { deprecate_warn( @@ -149,14 +216,47 @@ derive_summary_records <- function(dataset, set_values_to <- exprs(!!analysis_var := {{ summary_fun }}(!!analysis_var), !!!set_values_to) } - # Summarise the analysis value and bind to the original dataset - bind_rows( - dataset, - get_summary_records( - dataset, - by_vars = by_vars, - filter = !!filter, - set_values_to = set_values_to + if (!missing(filter)) { + deprecate_warn( + "1.0.0", + I("derive_summary_records(filter = )"), + "derive_summary_records(filter_add = )" ) + filter_add <- assert_filter_cond(enexpr(filter), optional = TRUE) + } + filter_add <- assert_filter_cond(enexpr(filter_add), optional = TRUE) + + summary_records <- dataset_add %>% + group_by(!!!by_vars) %>% + filter_if(filter_add) %>% + summarise(!!!set_values_to) %>% + ungroup() + + df_return <- bind_rows( + dataset, + summary_records ) + + if (!is.null(dataset_ref)) { + add_vars <- colnames(dataset_add) + ref_vars <- colnames(dataset_ref) + + new_ref_obs <- anti_join( + select(dataset_ref, intersect(add_vars, ref_vars)), + select(summary_records, !!!by_vars), + by = map_chr(by_vars, as_name) + ) + + if (!is.null(missing_values)) { + new_ref_obs <- new_ref_obs %>% + mutate(!!!missing_values) + } + + df_return <- bind_rows( + df_return, + new_ref_obs + ) + } + + df_return } diff --git a/R/get_summary_records.R b/R/get_summary_records.R index c911a4afe7..e859be443b 100644 --- a/R/get_summary_records.R +++ b/R/get_summary_records.R @@ -1,6 +1,12 @@ #' Create Summary Records #' #' @description +#' +#' `r lifecycle::badge("superseded")` +#' +#' Development on `get_summary_records()` is complete, and for new code we recommend +#' switching to using the `dataset_add` argument in `derive_summary_records()`. +#' #' It is not uncommon to have an analysis need whereby one needs to derive an #' analysis value (`AVAL`) from multiple records. The ADaM basic dataset #' structure variable `DTYPE` is available to indicate when a new derived @@ -64,9 +70,9 @@ #' #' @return A data frame of derived records. #' -#' @family der_gen +#' @family superseded #' -#' @keywords der_gen +#' @keywords superseded #' #' @seealso [derive_summary_records()], [derive_var_merged_summary()] #' @@ -154,7 +160,7 @@ get_summary_records <- function(dataset, filter = NULL, analysis_var, summary_fun, - set_values_to) { + set_values_to = NULL) { assert_vars(by_vars) filter <- assert_filter_cond(enexpr(filter), optional = TRUE) assert_data_frame( diff --git a/inst/templates/ad_adeg.R b/inst/templates/ad_adeg.R index 7df467df42..46abfac143 100644 --- a/inst/templates/ad_adeg.R +++ b/inst/templates/ad_adeg.R @@ -197,8 +197,9 @@ adeg <- adeg %>% # (if least 2 records available) for all parameter except EGINTP adeg <- adeg %>% derive_summary_records( + dataset_add = adeg, by_vars = exprs(STUDYID, USUBJID, !!!adsl_vars, PARAMCD, AVISITN, AVISIT, ADT), - filter = dplyr::n() >= 2 & PARAMCD != "EGINTP", + filter_add = dplyr::n() >= 2 & PARAMCD != "EGINTP", set_values_to = exprs( AVAL = mean(AVAL, na.rm = TRUE), DTYPE = "AVERAGE" diff --git a/inst/templates/ad_adex.R b/inst/templates/ad_adex.R index d64e0df635..a9b84b6e5b 100644 --- a/inst/templates/ad_adex.R +++ b/inst/templates/ad_adex.R @@ -148,6 +148,7 @@ adex <- adex %>% summary_fun = function(x) if_else(sum(!is.na(x)) > 0, "Y", NA_character_) ) ), + dataset_add = adex, by_vars = exprs(STUDYID, USUBJID, !!!adsl_vars) ) %>% # W2-W24 exposure @@ -185,7 +186,8 @@ adex <- adex %>% summary_fun = function(x) if_else(sum(!is.na(x)) > 0, "Y", NA_character_) ) ), - filter = VISIT %in% c("WEEK 2", "WEEK 24"), + dataset_add = adex, + filter_add = VISIT %in% c("WEEK 2", "WEEK 24"), by_vars = exprs(STUDYID, USUBJID, !!!adsl_vars) ) %>% # Overall Dose intensity and W2-24 dose intensity diff --git a/inst/templates/ad_advs.R b/inst/templates/ad_advs.R index af0b41b3c2..8cb14d7470 100644 --- a/inst/templates/ad_advs.R +++ b/inst/templates/ad_advs.R @@ -156,8 +156,9 @@ advs <- advs %>% ## Derive a new record as a summary record (e.g. mean of the triplicates at each time point) ---- advs <- advs %>% derive_summary_records( + dataset_add = advs, by_vars = exprs(STUDYID, USUBJID, !!!adsl_vars, PARAMCD, AVISITN, AVISIT, ADT, ADY), - filter = !is.na(AVAL), + filter_add = !is.na(AVAL), set_values_to = exprs( AVAL = mean(AVAL), DTYPE = "AVERAGE" diff --git a/man/derive_extreme_event.Rd b/man/derive_extreme_event.Rd index 17204edfad..e211c06d28 100644 --- a/man/derive_extreme_event.Rd +++ b/man/derive_extreme_event.Rd @@ -114,8 +114,7 @@ For example: \if{html}{\out{
}}\preformatted{ set_values_to = exprs( AVAL = sum(AVAL), - PARAMCD = "TDOSE", - PARCAT1 = "OVERALL" + DTYPE = "AVERAGE", ) }\if{html}{\out{
}}} diff --git a/man/derive_extreme_records.Rd b/man/derive_extreme_records.Rd index 69aa892b3f..036797a98f 100644 --- a/man/derive_extreme_records.Rd +++ b/man/derive_extreme_records.Rd @@ -119,8 +119,7 @@ For example: \if{html}{\out{
}}\preformatted{ set_values_to = exprs( AVAL = sum(AVAL), - PARAMCD = "TDOSE", - PARCAT1 = "OVERALL" + DTYPE = "AVERAGE", ) }\if{html}{\out{
}}} } diff --git a/man/derive_param_exposure.Rd b/man/derive_param_exposure.Rd index e54fd5704d..cea65120e1 100644 --- a/man/derive_param_exposure.Rd +++ b/man/derive_param_exposure.Rd @@ -5,23 +5,28 @@ \title{Add an Aggregated Parameter and Derive the Associated Start and End Dates} \usage{ derive_param_exposure( - dataset, + dataset = NULL, + dataset_add, by_vars, input_code, analysis_var, summary_fun, filter = NULL, + filter_add = NULL, set_values_to = NULL ) } \arguments{ \item{dataset}{Input dataset -The variables specified by the \code{by_vars} and \code{analysis_var} argument(s) to be expected. -\code{PARAMCD} is expected as well, -\itemize{ -\item Either \code{ASTDTM} and \code{AENDTM} or \code{ASTDT} and \code{AENDT} are also expected. -}} +The variables specified by the \code{by_vars} argument(s) to be expected.} + +\item{dataset_add}{Additional dataset + +The variables specified for \code{by_vars}, \code{analysis_var}, \code{PARAMCD}, +alongside either \code{ASTDTM} and \code{AENDTM} or \code{ASTDT} and \code{AENDT} are also expected. +Observations from the specified dataset are going to be used to calculate and added +as new records to the input dataset (\code{dataset}).} \item{by_vars}{Grouping variables @@ -45,13 +50,33 @@ performs the calculation. This can include built-in functions as well as user defined functions, for example \code{mean} or \code{function(x) mean(x, na.rm = TRUE)}.} -\item{filter}{Filter condition +\item{filter}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Please use \code{filter_add} instead. + +Filter condition as logical expression to apply during +summary calculation. By default, filtering expressions are computed within +\code{by_vars} as this will help when an aggregating, lagging, or ranking +function is involved. -The specified condition is applied to the input dataset before deriving the -new parameter, i.e., only observations fulfilling the condition are taken -into account. +For example, +\itemize{ +\item \code{filter = (AVAL > mean(AVAL, na.rm = TRUE))} will filter all \code{AVAL} +values greater than mean of \code{AVAL} with in \code{by_vars}. +\item \code{filter = (dplyr::n() > 2)} will filter n count of \code{by_vars} greater +than 2. +}} + +\item{filter_add}{Filter condition as logical expression to apply during +summary calculation. By default, filtering expressions are computed within +\code{by_vars} as this will help when an aggregating, lagging, or ranking +function is involved. -\emph{Permitted Values:} a condition} +For example, +\itemize{ +\item \code{filter_add = (AVAL > mean(AVAL, na.rm = TRUE))} will filter all \code{AVAL} +values greater than mean of \code{AVAL} with in \code{by_vars}. +\item \code{filter_add = (dplyr::n() > 2)} will filter n count of \code{by_vars} greater +than 2. +}} \item{set_values_to}{Variable-value pairs @@ -117,6 +142,7 @@ adex <- tribble( # Cumulative dose adex \%>\% derive_param_exposure( + dataset_add = adex, by_vars = exprs(USUBJID), set_values_to = exprs(PARAMCD = "TDOSE", PARCAT1 = "OVERALL"), input_code = "DOSE", @@ -128,6 +154,7 @@ adex \%>\% # average dose in w2-24 adex \%>\% derive_param_exposure( + dataset_add = adex, by_vars = exprs(USUBJID), filter = VISIT \%in\% c("WEEK 2", "WEEK 24"), set_values_to = exprs(PARAMCD = "AVDW224", PARCAT1 = "WEEK2-24"), @@ -140,6 +167,7 @@ adex \%>\% # Any dose adjustment? adex \%>\% derive_param_exposure( + dataset_add = adex, by_vars = exprs(USUBJID), set_values_to = exprs(PARAMCD = "TADJ", PARCAT1 = "OVERALL"), input_code = "ADJ", diff --git a/man/derive_param_extreme_record.Rd b/man/derive_param_extreme_record.Rd index 3b68ae01d2..35739e25cf 100644 --- a/man/derive_param_extreme_record.Rd +++ b/man/derive_param_extreme_record.Rd @@ -141,5 +141,9 @@ derive_param_extreme_record( ) ) } +\seealso{ +Other superseded: +\code{\link{get_summary_records}()} +} \concept{superseded} \keyword{superseded} diff --git a/man/derive_summary_records.Rd b/man/derive_summary_records.Rd index d706207c86..793a2a2c5b 100644 --- a/man/derive_summary_records.Rd +++ b/man/derive_summary_records.Rd @@ -5,24 +5,42 @@ \title{Add New Records Within By Groups Using Aggregation Functions} \usage{ derive_summary_records( - dataset, + dataset = NULL, + dataset_add, + dataset_ref = NULL, by_vars, filter = NULL, + filter_add = NULL, analysis_var, summary_fun, - set_values_to + set_values_to, + missing_values = NULL ) } \arguments{ \item{dataset}{Input dataset -The variables specified by the \code{by_vars} and \code{analysis_var} argument(s) to be expected.} +The variables specified by the \code{by_vars} argument(s) to be expected.} + +\item{dataset_add}{Additional dataset + +The variables specified for \code{by_vars} are expected. +Observations from the specified dataset are going to be used to calculate and added +as new records to the input dataset (\code{dataset}).} + +\item{dataset_ref}{Reference dataset + +The variables specified for \code{by_vars} are expected. For each +observation of the specified dataset a new observation is added to the +input dataset.} \item{by_vars}{Variables to consider for generation of groupwise summary records. Providing the names of variables in \code{\link[=exprs]{exprs()}} will create a groupwise summary and generate summary records for the specified groups.} -\item{filter}{Filter condition as logical expression to apply during +\item{filter}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Please use \code{filter_add} instead. + +Filter condition as logical expression to apply during summary calculation. By default, filtering expressions are computed within \code{by_vars} as this will help when an aggregating, lagging, or ranking function is involved. @@ -35,6 +53,19 @@ values greater than mean of \code{AVAL} with in \code{by_vars}. than 2. }} +\item{filter_add}{Filter condition as logical expression to apply during +summary calculation. By default, filtering expressions are computed within +\code{by_vars} as this will help when an aggregating, lagging, or ranking +function is involved. + +For example, +\itemize{ +\item \code{filter_add = (AVAL > mean(AVAL, na.rm = TRUE))} will filter all \code{AVAL} +values greater than mean of \code{AVAL} with in \code{by_vars}. +\item \code{filter_add = (dplyr::n() > 2)} will filter n count of \code{by_vars} greater +than 2. +}} + \item{analysis_var}{Analysis variable. \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Please use \code{set_values_to} instead.} @@ -64,10 +95,18 @@ For example: \if{html}{\out{
}}\preformatted{ set_values_to = exprs( AVAL = sum(AVAL), - PARAMCD = "TDOSE", - PARCAT1 = "OVERALL" + DTYPE = "AVERAGE", ) }\if{html}{\out{
}}} + +\item{missing_values}{Values for missing summary values + +For observations of the reference dataset (\code{dataset_ref}) which do not have a +complete mapping defined by the summarization defined in \code{set_values_to}. Only variables +specified for \code{set_values_to} can be specified for \code{missing_values}. + +\emph{Permitted Values}: named list of expressions, e.g., +\code{exprs(AVAL = -9999)}} } \value{ A data frame with derived records appended to original dataset. @@ -115,6 +154,7 @@ adeg <- tribble( # Summarize the average of the triplicate ECG interval values (AVAL) derive_summary_records( adeg, + dataset_add = adeg, by_vars = exprs(USUBJID, PARAM, AVISIT), set_values_to = exprs( AVAL = mean(AVAL, na.rm = TRUE), @@ -126,6 +166,7 @@ derive_summary_records( # Derive more than one summary variable derive_summary_records( adeg, + dataset_add = adeg, by_vars = exprs(USUBJID, PARAM, AVISIT), set_values_to = exprs( AVAL = mean(AVAL), @@ -159,8 +200,9 @@ adeg <- tribble( # by group derive_summary_records( adeg, + dataset_add = adeg, by_vars = exprs(USUBJID, PARAM, AVISIT), - filter = n() > 2, + filter_add = n() > 2, set_values_to = exprs( AVAL = mean(AVAL, na.rm = TRUE), DTYPE = "AVERAGE" diff --git a/man/derive_var_extreme_flag.Rd b/man/derive_var_extreme_flag.Rd index 0375ef0309..05ea1d8359 100644 --- a/man/derive_var_extreme_flag.Rd +++ b/man/derive_var_extreme_flag.Rd @@ -267,8 +267,7 @@ General Derivation Functions for all ADaMs that returns variable appended to dat \code{\link{derive_vars_joined}()}, \code{\link{derive_vars_merged_lookup}()}, \code{\link{derive_vars_merged}()}, -\code{\link{derive_vars_transposed}()}, -\code{\link{get_summary_records}()} +\code{\link{derive_vars_transposed}()} } \concept{der_gen} \keyword{der_gen} diff --git a/man/derive_var_joined_exist_flag.Rd b/man/derive_var_joined_exist_flag.Rd index acd6905c0f..d859e790e3 100644 --- a/man/derive_var_joined_exist_flag.Rd +++ b/man/derive_var_joined_exist_flag.Rd @@ -488,8 +488,7 @@ General Derivation Functions for all ADaMs that returns variable appended to dat \code{\link{derive_vars_joined}()}, \code{\link{derive_vars_merged_lookup}()}, \code{\link{derive_vars_merged}()}, -\code{\link{derive_vars_transposed}()}, -\code{\link{get_summary_records}()} +\code{\link{derive_vars_transposed}()} } \concept{der_gen} \keyword{der_gen} diff --git a/man/derive_var_merged_exist_flag.Rd b/man/derive_var_merged_exist_flag.Rd index ae0728a4bd..76c08d7083 100644 --- a/man/derive_var_merged_exist_flag.Rd +++ b/man/derive_var_merged_exist_flag.Rd @@ -159,8 +159,7 @@ General Derivation Functions for all ADaMs that returns variable appended to dat \code{\link{derive_vars_joined}()}, \code{\link{derive_vars_merged_lookup}()}, \code{\link{derive_vars_merged}()}, -\code{\link{derive_vars_transposed}()}, -\code{\link{get_summary_records}()} +\code{\link{derive_vars_transposed}()} } \concept{der_gen} \keyword{der_gen} diff --git a/man/derive_var_merged_summary.Rd b/man/derive_var_merged_summary.Rd index 08220316cb..057bdf569c 100644 --- a/man/derive_var_merged_summary.Rd +++ b/man/derive_var_merged_summary.Rd @@ -175,8 +175,7 @@ General Derivation Functions for all ADaMs that returns variable appended to dat \code{\link{derive_vars_joined}()}, \code{\link{derive_vars_merged_lookup}()}, \code{\link{derive_vars_merged}()}, -\code{\link{derive_vars_transposed}()}, -\code{\link{get_summary_records}()} +\code{\link{derive_vars_transposed}()} } \concept{der_gen} \keyword{der_gen} diff --git a/man/derive_var_obs_number.Rd b/man/derive_var_obs_number.Rd index d4c54e6881..ebdd3375f1 100644 --- a/man/derive_var_obs_number.Rd +++ b/man/derive_var_obs_number.Rd @@ -102,8 +102,7 @@ General Derivation Functions for all ADaMs that returns variable appended to dat \code{\link{derive_vars_joined}()}, \code{\link{derive_vars_merged_lookup}()}, \code{\link{derive_vars_merged}()}, -\code{\link{derive_vars_transposed}()}, -\code{\link{get_summary_records}()} +\code{\link{derive_vars_transposed}()} } \concept{der_gen} \keyword{der_gen} diff --git a/man/derive_var_relative_flag.Rd b/man/derive_var_relative_flag.Rd index ac017c896d..679df63d95 100644 --- a/man/derive_var_relative_flag.Rd +++ b/man/derive_var_relative_flag.Rd @@ -178,8 +178,7 @@ General Derivation Functions for all ADaMs that returns variable appended to dat \code{\link{derive_vars_joined}()}, \code{\link{derive_vars_merged_lookup}()}, \code{\link{derive_vars_merged}()}, -\code{\link{derive_vars_transposed}()}, -\code{\link{get_summary_records}()} +\code{\link{derive_vars_transposed}()} } \concept{der_gen} \keyword{der_gen} diff --git a/man/derive_vars_joined.Rd b/man/derive_vars_joined.Rd index 63ccc0a4d7..ff01b996a9 100644 --- a/man/derive_vars_joined.Rd +++ b/man/derive_vars_joined.Rd @@ -500,8 +500,7 @@ General Derivation Functions for all ADaMs that returns variable appended to dat \code{\link{derive_var_relative_flag}()}, \code{\link{derive_vars_merged_lookup}()}, \code{\link{derive_vars_merged}()}, -\code{\link{derive_vars_transposed}()}, -\code{\link{get_summary_records}()} +\code{\link{derive_vars_transposed}()} } \concept{der_gen} \keyword{der_gen} diff --git a/man/derive_vars_merged.Rd b/man/derive_vars_merged.Rd index dca45a6222..d021aba1fd 100644 --- a/man/derive_vars_merged.Rd +++ b/man/derive_vars_merged.Rd @@ -326,8 +326,7 @@ General Derivation Functions for all ADaMs that returns variable appended to dat \code{\link{derive_var_relative_flag}()}, \code{\link{derive_vars_joined}()}, \code{\link{derive_vars_merged_lookup}()}, -\code{\link{derive_vars_transposed}()}, -\code{\link{get_summary_records}()} +\code{\link{derive_vars_transposed}()} } \concept{der_gen} \keyword{der_gen} diff --git a/man/derive_vars_merged_lookup.Rd b/man/derive_vars_merged_lookup.Rd index 3024d10083..3016da5a55 100644 --- a/man/derive_vars_merged_lookup.Rd +++ b/man/derive_vars_merged_lookup.Rd @@ -182,8 +182,7 @@ General Derivation Functions for all ADaMs that returns variable appended to dat \code{\link{derive_var_relative_flag}()}, \code{\link{derive_vars_joined}()}, \code{\link{derive_vars_merged}()}, -\code{\link{derive_vars_transposed}()}, -\code{\link{get_summary_records}()} +\code{\link{derive_vars_transposed}()} } \concept{der_gen} \keyword{der_gen} diff --git a/man/derive_vars_transposed.Rd b/man/derive_vars_transposed.Rd index 8195dd1166..9e7e753d5d 100644 --- a/man/derive_vars_transposed.Rd +++ b/man/derive_vars_transposed.Rd @@ -97,8 +97,7 @@ General Derivation Functions for all ADaMs that returns variable appended to dat \code{\link{derive_var_relative_flag}()}, \code{\link{derive_vars_joined}()}, \code{\link{derive_vars_merged_lookup}()}, -\code{\link{derive_vars_merged}()}, -\code{\link{get_summary_records}()} +\code{\link{derive_vars_merged}()} } \concept{der_gen} \keyword{der_gen} diff --git a/man/get_summary_records.Rd b/man/get_summary_records.Rd index e63f9d477e..c8f0473c03 100644 --- a/man/get_summary_records.Rd +++ b/man/get_summary_records.Rd @@ -10,7 +10,7 @@ get_summary_records( filter = NULL, analysis_var, summary_fun, - set_values_to + set_values_to = NULL ) } \arguments{ @@ -73,6 +73,11 @@ For example: A data frame of derived records. } \description{ +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} + +Development on \code{get_summary_records()} is complete, and for new code we recommend +switching to using the \code{dataset_add} argument in \code{derive_summary_records()}. + It is not uncommon to have an analysis need whereby one needs to derive an analysis value (\code{AVAL}) from multiple records. The ADaM basic dataset structure variable \code{DTYPE} is available to indicate when a new derived @@ -164,17 +169,8 @@ get_summary_records( \seealso{ \code{\link[=derive_summary_records]{derive_summary_records()}}, \code{\link[=derive_var_merged_summary]{derive_var_merged_summary()}} -General Derivation Functions for all ADaMs that returns variable appended to dataset: -\code{\link{derive_var_extreme_flag}()}, -\code{\link{derive_var_joined_exist_flag}()}, -\code{\link{derive_var_merged_exist_flag}()}, -\code{\link{derive_var_merged_summary}()}, -\code{\link{derive_var_obs_number}()}, -\code{\link{derive_var_relative_flag}()}, -\code{\link{derive_vars_joined}()}, -\code{\link{derive_vars_merged_lookup}()}, -\code{\link{derive_vars_merged}()}, -\code{\link{derive_vars_transposed}()} +Other superseded: +\code{\link{derive_param_extreme_record}()} } -\concept{der_gen} -\keyword{der_gen} +\concept{superseded} +\keyword{superseded} diff --git a/tests/testthat/test-call_derivation.R b/tests/testthat/test-call_derivation.R index c5e9e10abc..667a960b52 100644 --- a/tests/testthat/test-call_derivation.R +++ b/tests/testthat/test-call_derivation.R @@ -5,32 +5,36 @@ test_that("call_derivation Test 1: Test that call_derivation generates expected expected_output <- input %>% derive_summary_records( + dataset_add = input, by_vars = exprs(USUBJID, VSTESTCD), set_values_to = exprs( VSSTRESN = mean(VSSTRESN, na.rm = TRUE), DTYPE = "AVERAGE" ), - filter = dplyr::n() >= 2L + filter_add = dplyr::n() >= 2L ) %>% derive_summary_records( + dataset_add = input, by_vars = exprs(USUBJID, VSTESTCD), set_values_to = exprs( VSSTRESN = max(VSSTRESN, na.rm = TRUE), DTYPE = "MAXIMUM" ), - filter = dplyr::n() >= 2L + filter_add = dplyr::n() >= 2L ) %>% derive_summary_records( + dataset_add = input, by_vars = exprs(USUBJID, VSTESTCD), set_values_to = exprs( VSSTRESN = min(VSSTRESN, na.rm = TRUE), DTYPE = "MINIMUM" ), - filter = dplyr::n() >= 2L + filter_add = dplyr::n() >= 2L ) actual_output <- call_derivation( dataset = input, + dataset_add = input, derivation = derive_summary_records, variable_params = list( params( @@ -53,7 +57,7 @@ test_that("call_derivation Test 1: Test that call_derivation generates expected ) ), by_vars = exprs(USUBJID, VSTESTCD), - filter = dplyr::n() >= 2L + filter_add = dplyr::n() >= 2L ) expect_dfs_equal( diff --git a/tests/testthat/test-compute_scale.R b/tests/testthat/test-compute_scale.R index afb20f819f..0db6250394 100644 --- a/tests/testthat/test-compute_scale.R +++ b/tests/testthat/test-compute_scale.R @@ -95,8 +95,9 @@ test_that("compute_scale Test 5: compute_scale() works as expected within expect_equal( derive_summary_records( input, + dataset_add = input, by_vars = exprs(STUDYID, USUBJID, AVISIT, AVISITN), - filter = (PARAMCD %in% c("ITEM1", "ITEM2", "ITEM3")), + filter_add = (PARAMCD %in% c("ITEM1", "ITEM2", "ITEM3")), set_values_to = exprs( AVAL = compute_scale(AVAL, c(1, 5), c(0, 100), flip_direction = TRUE, min_n = 3), PARAMCD = "ITEMAVG" diff --git a/tests/testthat/test-derive_param_exposure.R b/tests/testthat/test-derive_param_exposure.R index dd3582f406..ca80f75a60 100644 --- a/tests/testthat/test-derive_param_exposure.R +++ b/tests/testthat/test-derive_param_exposure.R @@ -61,6 +61,7 @@ test_that("derive_param_exposure Test 1: works with DTM variables", { actual_output <- input %>% derive_param_exposure( + dataset_add = input, by_vars = exprs(USUBJID), input_code = "DOSE", analysis_var = AVAL, @@ -68,6 +69,7 @@ test_that("derive_param_exposure Test 1: works with DTM variables", { set_values_to = exprs(PARAMCD = "TDOSE", PARCAT1 = "OVERALL") ) %>% derive_param_exposure( + dataset_add = input, by_vars = exprs(USUBJID), input_code = "DOSE", analysis_var = AVAL, @@ -75,6 +77,7 @@ test_that("derive_param_exposure Test 1: works with DTM variables", { set_values_to = exprs(PARAMCD = "AVDOSE", PARCAT1 = "OVERALL") ) %>% derive_param_exposure( + dataset_add = input, by_vars = exprs(USUBJID), input_code = "ADJ", analysis_var = AVALC, @@ -125,6 +128,7 @@ test_that("derive_param_exposure Test 2: works with DT variables", { actual_output <- input_no_dtm %>% derive_param_exposure( + dataset_add = input_no_dtm, by_vars = exprs(USUBJID), input_code = "DOSE", analysis_var = AVAL, @@ -132,6 +136,7 @@ test_that("derive_param_exposure Test 2: works with DT variables", { set_values_to = exprs(PARAMCD = "TDOSE", PARCAT1 = "OVERALL") ) %>% derive_param_exposure( + dataset_add = input_no_dtm, by_vars = exprs(USUBJID), input_code = "DOSE", analysis_var = AVAL, @@ -139,6 +144,7 @@ test_that("derive_param_exposure Test 2: works with DT variables", { set_values_to = exprs(PARAMCD = "AVDOSE", PARCAT1 = "OVERALL") ) %>% derive_param_exposure( + dataset_add = input_no_dtm, by_vars = exprs(USUBJID), input_code = "ADJ", analysis_var = AVALC, @@ -159,6 +165,7 @@ test_that("derive_param_exposure Test 3: Errors", { expect_error( input <- input %>% derive_param_exposure( + dataset_add = input, by_vars = exprs(USUBJID), input_code = "DOSE", analysis_var = AVAL, @@ -171,6 +178,7 @@ test_that("derive_param_exposure Test 3: Errors", { expect_error( input <- input %>% derive_param_exposure( + dataset_add = input, by_vars = exprs(USUBJID), input_code = "DOSED", analysis_var = AVAL, @@ -188,6 +196,8 @@ test_that("derive_param_exposure Test 3: Errors", { input <- input %>% select(-starts_with("AST"), -starts_with("AEN")) %>% derive_param_exposure( + dataset = ., + dataset_add = ., by_vars = exprs(USUBJID), input_code = "DOSE", analysis_var = AVAL, diff --git a/tests/testthat/test-derive_summary_records.R b/tests/testthat/test-derive_summary_records.R index c7b26c927e..4300d05938 100644 --- a/tests/testthat/test-derive_summary_records.R +++ b/tests/testthat/test-derive_summary_records.R @@ -11,6 +11,7 @@ test_that("derive_summary_records Test 1: creates new record per group and group actual_output <- input %>% derive_summary_records( + dataset_add = input, by_vars = exprs(subj, visit), set_values_to = exprs( val = mean(val), @@ -50,8 +51,9 @@ test_that("derive_summary_records Test 2: Filter record within `by_vars`", { actual_output <- input %>% derive_summary_records( + dataset_add = input, by_vars = exprs(subj, visit), - filter = n() > 2, + filter_add = n() > 2, set_values_to = exprs( val = mean(val), seq = max(seq), @@ -129,6 +131,7 @@ test_that("derive_summary_records Test 4: deprecation warning for analysis_var a expect_warning( actual_output <- input %>% derive_summary_records( + dataset_add = input, by_vars = exprs(subj, visit), analysis_var = val, summary_fun = mean, @@ -143,3 +146,91 @@ test_that("derive_summary_records Test 4: deprecation warning for analysis_var a keys = c("subj", "visit", "seq", "type") ) }) + +## Test 5: make sure dataset_add works ---- +test_that("derive_summary_records Test 5: make sure dataset_add works", { + input <- tibble::tribble( + ~subj, ~visit, ~val, ~seq, + "1", 1, 10, 1, + "1", 1, 14, 2, + "1", 1, 9, 3, + "1", 2, 11, 4, + "2", 2, NA_real_, 1 + ) + input_add <- tibble::tribble( + ~subj, ~visit, ~add_val, ~seq, + "1", 1, 100, 1, + "1", 1, 140, 2, + "1", 1, 90, 3 + ) + expected_output <- bind_rows( + input, + tibble::tribble( + ~subj, ~visit, ~val, ~type, + "1", 1, 110, "AVERAGE" + ) + ) + actual_output <- input %>% + derive_summary_records( + dataset_add = input_add, + by_vars = exprs(subj, visit), + set_values_to = exprs( + val = mean(add_val, na.rm = TRUE), + type = "AVERAGE" + ) + ) + expect_dfs_equal( + base = expected_output, + compare = actual_output, + keys = c("subj", "visit", "seq", "type") + ) +}) + +## Test 6: test missing values ---- +test_that("derive_summary_records Test 6: test missing values with dataset_ref", { + input <- tibble::tribble( + ~subj, ~visit, ~val, ~seq, + "1", 1, 10, 1, + "1", 1, 14, 2, + "1", 1, 9, 3, + "1", 2, 11, 4, + "2", 2, NA_real_, 1 + ) + + input_ref <- tibble::tribble( + ~subj, ~visit, + "1", 1, + "1", 2, + "2", 1, + "2", 2, + ) + + expected_output <- bind_rows( + input, + tibble::tribble( + ~subj, ~visit, ~aval, ~type, + "1", 1, 11, "AVERAGE", + "1", 2, 11, "AVERAGE", + "2", 1, 999999, "MISSING", + "2", 2, NA_real_, "AVERAGE", + ) + ) + + actual_output <- input %>% + derive_summary_records( + dataset_add = input, + dataset_ref = input_ref, + by_vars = exprs(subj, visit), + set_values_to = exprs( + aval = mean(val, na.rm = TRUE), + type = "AVERAGE" + ), + missing_values = exprs(aval = 999999, type = "MISSING") + ) + + expect_dfs_equal( + base = expected_output, + compare = actual_output, + keys = c("subj", "visit", "seq", "type") + ) +}) diff --git a/vignettes/articles/website-versions.Rmd b/vignettes/articles/website-versions.Rmd index 8b1763402b..fdb51e2805 100644 --- a/vignettes/articles/website-versions.Rmd +++ b/vignettes/articles/website-versions.Rmd @@ -5,6 +5,7 @@ title: "Previous Versions of Website" ```{r, include = FALSE} # TO USE THIS ARTICLE, THE DESCRIPTION FILE MUST INCLUDE # Config/Needs/website: gert +# Make sure to copy the gh-pages branch to your local git knitr::opts_chunk$set( collapse = TRUE, diff --git a/vignettes/bds_exposure.Rmd b/vignettes/bds_exposure.Rmd index 0258e1fc8a..fd88cd7913 100644 --- a/vignettes/bds_exposure.Rmd +++ b/vignettes/bds_exposure.Rmd @@ -361,6 +361,7 @@ For example, to calculate the total dose by subject and treatment, ```{r eval=TRUE, echo=TRUE} adex <- derive_param_exposure( adex, + dataset_add = adex, by_vars = exprs(STUDYID, USUBJID, !!!adsl_vars), input_code = "DOSE", analysis_var = AVAL, @@ -428,6 +429,7 @@ adex <- adex %>% summary_fun = function(x) if_else(sum(!is.na(x)) > 0, "Y", NA_character_) ) ), + dataset_add = adex, by_vars = exprs(STUDYID, USUBJID, !!!adsl_vars) ) diff --git a/vignettes/bds_finding.Rmd b/vignettes/bds_finding.Rmd index 05a65d5494..1a45382e28 100644 --- a/vignettes/bds_finding.Rmd +++ b/vignettes/bds_finding.Rmd @@ -991,9 +991,10 @@ Set `DTYPE` to `AVERAGE`. ```{r eval=TRUE} advs_ex2 <- derive_summary_records( advs, + dataset_add = advs, by_vars = exprs(STUDYID, USUBJID, PARAMCD, VISITNUM, ADT), set_values_to = exprs( - AVAL = mean(AVAL), + AVAL = mean(AVAL, na.rm = TRUE), DTYPE = "AVERAGE" ) ) diff --git a/vignettes/questionnaires.Rmd b/vignettes/questionnaires.Rmd index d6e0761ea4..ef37f997e5 100644 --- a/vignettes/questionnaires.Rmd +++ b/vignettes/questionnaires.Rmd @@ -141,9 +141,11 @@ adgad7 <- adqs %>% # Select records to keep in the GAD-7 ADaM filter(PARCAT1 == "GAD-7 V2") %>% derive_summary_records( + dataset = ., + dataset_add = ., by_vars = exprs(STUDYID, USUBJID, AVISIT, ADT, ADY, TRTSDT, DTHCAUS), # Select records contributing to total score - filter = str_detect(PARAMCD, "GAD020[1-7]"), + filter_add = str_detect(PARAMCD, "GAD020[1-7]"), set_values_to = exprs( AVAL = sum(AVAL, na.rm = TRUE), PARAMCD = "GAD02TS", @@ -169,9 +171,11 @@ adgdssf <- adqs %>% # Select records to keep in the GDS-SF ADaM filter(PARCAT1 == "GDS SHORT FORM") %>% derive_summary_records( + dataset = ., + dataset_add = ., by_vars = exprs(STUDYID, USUBJID, AVISIT, ADT, ADY, TRTSDT, DTHCAUS), # Select records contributing to total score - filter = str_detect(PARAMCD, "GDS02[01][0-9]"), + filter_add = str_detect(PARAMCD, "GDS02[01][0-9]"), set_values_to = exprs( AVAL = compute_scale( AVAL, @@ -523,7 +527,8 @@ be derived by `derive_summary_records()`. ```{r} adgdssf <- adgdssf %>% derive_summary_records( - filter = str_detect(PARAMCD, "GDS02[01][0-9]"), + dataset_add = adgdssf, + filter_add = str_detect(PARAMCD, "GDS02[01][0-9]"), by_vars = exprs(USUBJID, AVISIT), set_values_to = exprs( AVAL = sum(!is.na(AVAL)) / 15 >= 0.9, @@ -572,7 +577,9 @@ adgdssf <- adgdssf %>% ) ) %>% derive_summary_records( - filter = str_detect(PARAMCD, "GDS02[01][0-9]"), + dataset = ., + dataset_add = ., + filter_add = str_detect(PARAMCD, "GDS02[01][0-9]"), by_vars = exprs(USUBJID, AVISIT), set_values_to = exprs( AVAL = all(!is.na(AVAL)),