Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closes #2510 enhance derive param computed #2544

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ Instances of abusive, harassing, or otherwise unacceptable behavior may be repor
opening an issue or contacting one or more of the project maintainers.

This Code of Conduct is adapted from the Contributor Covenant
(http://contributor-covenant.org), version 1.0.0, available at
http://contributor-covenant.org/version/1/0/0/
(http://www.contributor-covenant.org), version 1.0.0, available at
http://www.contributor-covenant.org/version/1/0/0/
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@

## Updates of Existing Functions

- The `keep_nas` argument of `derive_param_computed()` was enhanced such that it
is now possible to specify a list of variables for which `NA`s are acceptable.
I.e., records are added even if some of the specified variables are `NA`.
(#2510)

## Breaking Changes

- The following function arguments are entering the next phase of the deprecation process: (#2487)
Expand Down
95 changes: 77 additions & 18 deletions R/derive_param_computed.R
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,21 @@
#' @param keep_nas Keep observations with `NA`s
#'
#' If the argument is set to `TRUE`, observations are added even if some of
#' the values contributing to the computed value are `NA`.
#' the values contributing to the computed value are `NA` (see Example 1b).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be so cool if we could hyperlink to this example

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, linking to examples would be really cool.

Unfortunately, I'm not aware of an easy way to do this. We discussed creating a roclet for such improvements in #1590 but it was never implemented and I don't think we have resources for this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day we shall be great again!!

#'
#' If the argument is set to a list of variables, observations are added even
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So keep_nas can be TRUE, FALSE or a list of variables? I like not adding another argument but do we do this in other functions - is this common in other packages?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have something similar for the parameters argument in derive_param_computed(). I'm not sure if we do this in other functions.

I don't know how common this is in other packages but there are definitely examples in other packages. Consider for example dplyr::select(). It accepts both symbols and strings.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool Cool! That is good example.

All good for me then.

#' if some of specified variables are `NA` (see Example 1c).
#'
#' *Permitted Values:* `TRUE`, `FALSE`, or a list of variables created by
#' `exprs()` e.g. `exprs(ADTF, ATMF)`
#'
#' @details For each group (with respect to the variables specified for the
#' `by_vars` parameter) an observation is added to the output dataset if the
#' filtered input dataset (`dataset`) or the additional dataset
#' (`dataset_add`) contains exactly one observation for each parameter code
#' specified for `parameters`.
#' specified for `parameters` and all contributing values like `AVAL.SYSBP`
#' are not `NA`. The `keep_nas` can be used to specify variables for which
#' `NA`s are acceptable. See also Example 1b and 1c.
#'
#' For the new observations the variables specified for `set_values_to` are
#' set to the provided values. The values of the other variables of the input
Expand All @@ -145,17 +153,18 @@
#'
#' # Example 1a: Derive MAP
#' advs <- tribble(
#' ~USUBJID, ~PARAMCD, ~PARAM, ~AVAL, ~AVALU, ~VISIT,
#' "01-701-1015", "DIABP", "Diastolic Blood Pressure (mmHg)", 51, "mmHg", "BASELINE",
#' "01-701-1015", "DIABP", "Diastolic Blood Pressure (mmHg)", 50, "mmHg", "WEEK 2",
#' "01-701-1015", "SYSBP", "Systolic Blood Pressure (mmHg)", 121, "mmHg", "BASELINE",
#' "01-701-1015", "SYSBP", "Systolic Blood Pressure (mmHg)", 121, "mmHg", "WEEK 2",
#' "01-701-1028", "DIABP", "Diastolic Blood Pressure (mmHg)", 79, "mmHg", "BASELINE",
#' "01-701-1028", "DIABP", "Diastolic Blood Pressure (mmHg)", 80, "mmHg", "WEEK 2",
#' "01-701-1028", "SYSBP", "Systolic Blood Pressure (mmHg)", 130, "mmHg", "BASELINE",
#' "01-701-1028", "SYSBP", "Systolic Blood Pressure (mmHg)", 132, "mmHg", "WEEK 2"
#' ~USUBJID, ~PARAMCD, ~PARAM, ~AVAL, ~VISIT,
#' "01-701-1015", "DIABP", "Diastolic Blood Pressure (mmHg)", 51, "BASELINE",
#' "01-701-1015", "DIABP", "Diastolic Blood Pressure (mmHg)", 50, "WEEK 2",
#' "01-701-1015", "SYSBP", "Systolic Blood Pressure (mmHg)", 121, "BASELINE",
#' "01-701-1015", "SYSBP", "Systolic Blood Pressure (mmHg)", 121, "WEEK 2",
#' "01-701-1028", "DIABP", "Diastolic Blood Pressure (mmHg)", 79, "BASELINE",
#' "01-701-1028", "DIABP", "Diastolic Blood Pressure (mmHg)", 80, "WEEK 2",
#' "01-701-1028", "SYSBP", "Systolic Blood Pressure (mmHg)", 130, "BASELINE",
#' "01-701-1028", "SYSBP", "Systolic Blood Pressure (mmHg)", NA, "WEEK 2"
#' ) %>%
#' mutate(
#' AVALU = "mmHg",
#' ADT = case_when(
#' VISIT == "BASELINE" ~ as.Date("2024-01-10"),
#' VISIT == "WEEK 2" ~ as.Date("2024-01-24")
Expand All @@ -176,8 +185,8 @@
#' )
#' )
#'
#' # Example 1b: Using option `keep_nas = TRUE` to derive MAP in the case where some/all values
#' # of a variable used in the computation are missing
#' # Example 1b: Using option `keep_nas = TRUE` to derive MAP in the case where some/all
#' # values of a variable used in the computation are missing
#'
#' derive_param_computed(
#' advs,
Expand All @@ -194,6 +203,24 @@
#' keep_nas = TRUE
#' )
#'
#' # Example 1c: Using option `keep_nas = exprs(ADTF)` to derive MAP in the case where
#' # some/all values of a variable used in the computation are missing but ignoring ADTF
#'
#' derive_param_computed(
#' advs,
#' by_vars = exprs(USUBJID, VISIT),
#' parameters = c("SYSBP", "DIABP"),
#' set_values_to = exprs(
#' AVAL = (AVAL.SYSBP + 2 * AVAL.DIABP) / 3,
#' PARAMCD = "MAP",
#' PARAM = "Mean Arterial Pressure (mmHg)",
#' AVALU = "mmHg",
#' ADT = ADT.SYSBP,
#' ADTF = ADTF.SYSBP
yurovska marked this conversation as resolved.
Show resolved Hide resolved
#' ),
#' keep_nas = exprs(ADTF)
#' )
#'
#' # Example 2: Derive BMI where height is measured only once
#' advs <- tribble(
#' ~USUBJID, ~PARAMCD, ~PARAM, ~AVAL, ~AVALU, ~VISIT,
Expand Down Expand Up @@ -303,7 +330,17 @@ derive_param_computed <- function(dataset = NULL,
if (!is.null(set_values_to$PARAMCD) && !is.null(dataset)) {
assert_param_does_not_exist(dataset, set_values_to$PARAMCD)
}
assert_logical_scalar(keep_nas)
if (typeof(keep_nas) == "list") {
assert_vars(keep_nas)
} else {
assert_logical_scalar(
keep_nas,
message = paste(
"Argument {.arg {arg_name}} must be either {.val {TRUE}}, {.val {FALSE}},",
"or a list of {.cls symbol}, but is {.obj_type_friendly {arg}}."
)
)
}

parameters <- assert_parameters_argument(parameters)
constant_parameters <- assert_parameters_argument(constant_parameters, optional = TRUE)
Expand Down Expand Up @@ -346,17 +383,39 @@ derive_param_computed <- function(dataset = NULL,
hori_data <- inner_join(hori_data, hori_const_data, by = vars2chr(constant_by_vars))
}

# add analysis value (AVAL) and parameter variables, e.g., PARAMCD
if (!keep_nas) {
# keep only observations where all analysis values are available
if (isFALSE(keep_nas) || typeof(keep_nas) == "list") {
# keep only observations where the specified analysis values are available
if (typeof(keep_nas) == "list") {
na_vars <- discard(
analysis_vars_chr,
~ str_detect(., paste0("^(", paste(vars2chr(keep_nas), collapse = "|"), ")\\."))
)
} else {
na_vars <- analysis_vars_chr
}
nobs_before <- nrow(hori_data)
hori_data <- filter(
hori_data,
!!!parse_exprs(map_chr(
analysis_vars_chr,
na_vars,
~ str_c("!is.na(", .x, ")")
))
)
if (nobs_before > 0 && nrow(hori_data) == 0) {
cli_inform(c(
paste(
"No computed records were added because for all potential computed",
"records at least one of the contributing values was {.val {NA}}."
),
paste(
"If this is not expected, please check the input data and the value of",
"the {.arg keep_nas} argument."
)
))
}
}

# add computed variables like AVAL and constant variables like PARAMCD
hori_data <- hori_data %>%
process_set_values_to(set_values_to) %>%
select(-all_of(analysis_vars_chr[str_detect(analysis_vars_chr, "\\.")]))
Expand Down
1 change: 1 addition & 0 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
url: https://pharmaverse.github.io/admiral

template:
math-rendering: mathjax
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this intentional? Just checking!?! :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I rendered the documentation with pkgdown 2.1.1 and noticed that formulas are no longer rendered correctly. Adding this line fixes the issues.

bootstrap: 5
params:
bootswatch: flatly
Expand Down
53 changes: 40 additions & 13 deletions man/derive_param_computed.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 36 additions & 2 deletions tests/testthat/_snaps/derive_param_computed.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,46 @@
# assert_parameters_argument Test 10: error if argument is of wrong type
# derive_param_computed Test 11: error if keep_nas is invalid

Code
derive_param_computed(advs, by_vars = exprs(USUBJID, AVISIT), parameters = c(
"SYSBP", "DIABP"), set_values_to = exprs(AVAL = (AVAL.SYSBP + 2 *
AVAL.DIABP) / 3, PARAMCD = "MAP", PARAM = "Mean Arterial Pressure (mmHg)"),
keep_nas = 3)
Condition
Error in `derive_param_computed()`:
! Argument `keep_nas` must be either TRUE, FALSE, or a list of <symbol>, but is a number.

# derive_param_computed Test 12: inform if no new records due to NAs

Code
derive_param_computed(advs, by_vars = exprs(USUBJID, AVISIT), parameters = c(
"SYSBP", "DIABP"), set_values_to = exprs(AVAL = (AVAL.SYSBP + 2 *
AVAL.DIABP) / 3, PARAMCD = "MAP", PARAM = "Mean Arterial Pressure (mmHg)", ADT = ADT.SYSBP,
ADTF = ADTF.SYSBP))
Message
No computed records were added because for all potential computed records at least one of the contributing values was NA.
If this is not expected, please check the input data and the value of the `keep_nas` argument.
Output
# A tibble: 8 x 7
USUBJID PARAMCD PARAM AVAL AVISIT ADT ADTF
<chr> <chr> <chr> <dbl> <chr> <date> <chr>
1 01-701-1015 DIABP Diastolic Blood Pressure (m~ 51 BASEL~ 2024-01-10 <NA>
2 01-701-1015 DIABP Diastolic Blood Pressure (m~ 50 WEEK 2 2024-01-24 <NA>
3 01-701-1015 SYSBP Systolic Blood Pressure (mm~ 121 BASEL~ 2024-01-10 <NA>
4 01-701-1015 SYSBP Systolic Blood Pressure (mm~ 121 WEEK 2 2024-01-24 <NA>
5 01-701-1028 DIABP Diastolic Blood Pressure (m~ 79 BASEL~ 2024-01-10 <NA>
6 01-701-1028 DIABP Diastolic Blood Pressure (m~ 80 WEEK 2 2024-01-24 <NA>
7 01-701-1028 SYSBP Systolic Blood Pressure (mm~ 130 BASEL~ 2024-01-10 <NA>
8 01-701-1028 SYSBP Systolic Blood Pressure (mm~ NA WEEK 2 2024-01-24 <NA>

# assert_parameters_argument Test 13: error if argument is of wrong type

Code
assert_parameters_argument(myparameters <- c(1, 2, 3))
Condition
Error in `assert_parameters_argument()`:
! `myparameters <- c(1, 2, 3)` must be a character vector or a list of expressions but it is a double vector.

# get_hori_data Test 11: error if variables with more than one dot
# get_hori_data Test 14: error if variables with more than one dot

Code
get_hori_data(input, parameters = exprs(SYSBP, DIABP), by_vars = exprs(USUBJID,
Expand Down
Loading
Loading