From 04dc8b526891ffbf484016ca770425eeab997ac8 Mon Sep 17 00:00:00 2001 From: Edoardo Mancini <53403957+manciniedoardo@users.noreply.github.com> Date: Mon, 27 Nov 2023 19:07:40 +0000 Subject: [PATCH] Closes #74 higher order post (#93) * #74 higher order post * #74 spelling and syler * #74 updates following review * #74 chore: spellcheck * chore: new date to be closer to publishign * chore: fixing cosa links * chore: fix links * chore: packages for workflow --------- Co-authored-by: Ben Straub --- .github/workflows/publish.yml | 1 + inst/WORDLIST.txt | 24 ++ posts/2023-06-27__hackathon_app/index.qmd | 2 +- posts/2023-06-27_hackathon_writeup/index.qmd | 4 +- .../cross_industry_dev.qmd | 2 +- posts/2023-11-27_higher_order/admiral.png | Bin 0 -> 16971 bytes posts/2023-11-27_higher_order/appendix.R | 78 +++++ .../2023-11-27_higher_order/higher_order.qmd | 294 ++++++++++++++++++ 8 files changed, 401 insertions(+), 4 deletions(-) create mode 100644 posts/2023-11-27_higher_order/admiral.png create mode 100644 posts/2023-11-27_higher_order/appendix.R create mode 100644 posts/2023-11-27_higher_order/higher_order.qmd diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 73bb4a6b..2a0bb923 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -35,6 +35,7 @@ jobs: patchwork here reactable + pharmaversesdtm - name: Install tinytex diff --git a/inst/WORDLIST.txt b/inst/WORDLIST.txt index 0940cfb3..0d0bf7ee 100644 --- a/inst/WORDLIST.txt +++ b/inst/WORDLIST.txt @@ -476,3 +476,27 @@ representable Representable resizable rsc +AEDECOD +AEs +AESEQ +AESEV +AESEVN +AESTDY +AHIFL +ahilofl +ahsev +AHSEV +ahsevfl +AHSEVFL +ALOFL +ASTDT +modularity +pharmaversesdtm +preprocess +stdy +STUDYID +TRTEMFL +VSDY +VSORRES +VSSEQ +VSTESTCD diff --git a/posts/2023-06-27__hackathon_app/index.qmd b/posts/2023-06-27__hackathon_app/index.qmd index 492345d3..3d0b6964 100644 --- a/posts/2023-06-27__hackathon_app/index.qmd +++ b/posts/2023-06-27__hackathon_app/index.qmd @@ -44,7 +44,7 @@ Please keep in mind that this work was done under tight time restraints. The [hackathon application](https://zxqguo-stefan0pascal-thoma.shinyapps.io/data_upload/?_ga=2.75919894.2036952320.1679990144-1584712930.1674550185) is still online (although data-upload is switched off) and the [GitHub repository](https://github.com/StefanThoma/hackathon_app) is publicly available. The application is embedded into this post right after this paragraph. I have also uploaded to GitHub a `.zip` file of the workspace to which hackathon participants had access via [posit cloud](https://posit.cloud). -For more context you can watch [recordings of the hackathon-meetings](https://www.cdisc.org/events/webinar/admiral-hackathon-kickoff). +For more context you can watch [recordings of the hackathon-meetings](https://www.cdisc.org/cosa). ```{r} #| echo: false diff --git a/posts/2023-06-27_hackathon_writeup/index.qmd b/posts/2023-06-27_hackathon_writeup/index.qmd index 7567f406..328c34ac 100644 --- a/posts/2023-06-27_hackathon_writeup/index.qmd +++ b/posts/2023-06-27_hackathon_writeup/index.qmd @@ -41,7 +41,7 @@ The hackathon event was structured in two parts. First, we offered an *Introduction to R* for SAS programmers, a three hour workshop for R beginners to get them up to speed. Here we covered practical R basics, talking about how the R-workflow differs from a SAS workflow, and discussed common R functions - mostly from the tidyverse. This ensured that hackathon participants were familiar with core R concepts. -The [workshop recording](https://www.cdisc.org/events/webinar/pre-admiral-hackathon-workshop-introduction-r-sas-programmers) and the [course materials](https://pharmaverse.github.io/intro-to-r-for-sas-programmers-workshop/) are available online. +The [workshop recording](https://www.cdisc.org/cosa) and the [course materials](https://pharmaverse.github.io/intro-to-r-for-sas-programmers-workshop/) are available online. The main hackathon consisted of several ADAM data generating tasks based on a specs file and synthetic data. Participants were able to solve these tasks in groups at their own pace thanks to a online tool where participants could upload their task specific R scripts and they would get automatic feedback for the data-set produced by their script. @@ -165,7 +165,7 @@ Congratulations to the winners: Although this was uncertain during the hackathon we were excited to provide a Certificate of Completion to all participants who uploaded a script to the Web Application. -A recording of the hackathon readout can be found in the [CDISC Open Source Alliance Quarterly Spotlight](https://www.cdisc.org/events/webinar/cosa-quarterly-spotlight-q1-2023). +A recording of the hackathon readout can be found in the [CDISC Open Source Alliance Quarterly Spotlight](https://www.cdisc.org/cosa). ## Conclusion diff --git a/posts/2023-07-20_cross_company_dev/cross_industry_dev.qmd b/posts/2023-07-20_cross_company_dev/cross_industry_dev.qmd index 1524ad4b..26382053 100644 --- a/posts/2023-07-20_cross_company_dev/cross_industry_dev.qmd +++ b/posts/2023-07-20_cross_company_dev/cross_industry_dev.qmd @@ -84,7 +84,7 @@ If you would like to learn more about licenses for open source projects in the c ## Development workflow Every improvement, task, or feature we want to implement on [{admiral}](https://github.com/pharmaverse/admiral) starts as an issue on our [GitHub repository](https://github.com/pharmaverse/admiral). -It is the centerpiece of our development workflow, along with our [developer guides](https://pharmaverse.github.io/admiraldev/devel/articles/development_process.html) which describe in detail the strategies, conventions, and workflows used in development. +It is the centerpiece of our development workflow, along with our [developer guides](https://pharmaverse.github.io/admiraldev/articles/programming_strategy.html) which describe in detail the strategies, conventions, and workflows used in development. The guides help us keep the [{admiral}](https://github.com/pharmaverse/admiral) package internally consistent (e.g. naming conventions, function logic) but also ensure that [{admiral}](https://github.com/pharmaverse/admiral) adjacent packages follow the same conventions and share the user interface. This is further helped by the implemented CICD pipeline which ensures styling convention and spelling (and much more). diff --git a/posts/2023-11-27_higher_order/admiral.png b/posts/2023-11-27_higher_order/admiral.png new file mode 100644 index 0000000000000000000000000000000000000000..cc69ba33e7683f7822a46cd4cf66770026ec9df1 GIT binary patch literal 16971 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 + +```{r setup, include=FALSE} +long_slug <- "2023-11-03_higher_order" +# renv::use(lockfile = "renv.lock") +``` + + + +# Introduction + +Picture the following scenario: + +_You, a budding [{admiral}](https://pharmaverse.github.io/admiral/) programmer, are finding your groove chaining together modular code blocks to derive variables and parameters in a drive to construct your favorite ADaM dataset, `ADAE`. Suddenly you notice that one of the flags you are deriving should only use records on or after study day 1. In a moment of mild annoyance, you get to work modifying what was originally a simple call to `derive_var_extreme_flag()` by first subsetting `ADAE` to records where `AESTDY > 1`, then deriving the flag only for the subsetted `ADAE`, and finally binding the two portions of `ADAE` back together before continuing on with your program. Miffed by this interruption, you think to yourself: "I wish there was a neater, faster way to do this in stride, that didn't break my code modularity..."_ + +If the above could never be you, then you'll probably be alright never reading this blog post. However, if you want to learn more about the tools that [{admiral}](https://pharmaverse.github.io/admiral/) provides to make your life easier in cases like this one, then you are in the right place, since this blog post will highlight how higher order functions can solve such issues. + +A higher order function is a function that takes another function as input. By introducing these higher order functions, [{admiral}](https://pharmaverse.github.io/admiral/) intends to give the user greater power over derivations, whilst trying to negate the need for both adding additional [{admiral}](https://pharmaverse.github.io/admiral/) functions/arguments, and the user needing many separate steps. + +The functions covered in this post are: + +* `restrict_derivation()`: Allows the user to execute a single derivation on a subset of the input dataset. +* `call_derivation()`: Allows the user to call a single derivation multiple times with some arguments being fixed across iterations and others varying. +* `slice_derivation()`: Allows the user to split the input dataset into slices (subsets) and for each slice a single derivation is called separately. Some or all arguments of the derivation may vary depending on the slice. + +## Required Packages + +The examples in this blog post require the following packages. + +```{r, warning=FALSE, message=FALSE} +library(admiral) +library(pharmaversesdtm) +library(dplyr, warn.conflicts = FALSE) +``` + +For example purpose, the ADSL dataset - which is included in [{admiral}](https://pharmaverse.github.io/admiral/) - and the SDTM datasets from [{pharmaversesdtm}](https://pharmaverse.github.io/pharmaversesdtm) are used. + +```{r, warning=FALSE, message=FALSE} +data("admiral_adsl") +data("ae") +data("vs") +adsl <- admiral_adsl +ae <- convert_blanks_to_na(ae) +vs <- convert_blanks_to_na(vs) +``` + +```{r echo=FALSE} +adsl <- filter(adsl, USUBJID %in% c("01-701-1111", "01-705-1393")) +ae <- filter(ae, USUBJID %in% c("01-701-1111", "01-705-1393")) +vs <- filter(vs, USUBJID %in% c("01-701-1015")) +``` + +The following code creates a minimally viable ADAE dataset to be used where needed in the following examples. + +```{r} +adae <- ae %>% + left_join(adsl, by = c("STUDYID", "USUBJID")) %>% + derive_vars_dt( + new_vars_prefix = "AST", + dtc = AESTDTC, + highest_imputation = "M" + ) %>% + mutate( + TRTEMFL = if_else(ASTDT >= TRTSDT, "Y", NA_character_), + TEMP_AESEVN = as.integer(factor(AESEV, levels = c("SEVERE", "MODERATE", "MILD"))) + ) +``` + +# Restrict Derivation + +The idea behind `restrict_derivation()` is largely to solve the problem outlined in the introduction: sometimes one may want to easily apply a derivation only for certain records from the input dataset. `restrict_derivation()` gives the users the ability to achieve this across any [{admiral}](https://pharmaverse.github.io/admiral/) function, without each function needing to have such an argument to allow for this. + +Putting this into practice with an example: suppose the user has some code flagging the first occurring AE with the highest severity for each patient: + +```{r} +adae_ahsevfl <- adae %>% + derive_var_extreme_flag( + new_var = AHSEVFL, + by_vars = exprs(USUBJID), + order = exprs(TEMP_AESEVN, AESTDY, AESEQ), + mode = "first" + ) +``` + +To derive `AHSEVFL` for records occurring on or after study day 1, the user could try to split the dataset before applying `derive_var_extreme_flag()`, and then re-join everything at the end... + +```{r} +adae_pre_stdy1 <- adae %>% filter(AESTDY >= 1) +adae_post_stdy1 <- adae %>% filter(!(AESTDY >= 1)) + +adae_pre_stdy1_flag <- adae_pre_stdy1 %>% + derive_var_extreme_flag( + new_var = AHSEVFL, + by_vars = exprs(USUBJID), + order = exprs(TEMP_AESEVN, AESTDY, AESEQ), + mode = "first" + ) + +adae_ahsevfl <- adae_post_stdy1 %>% + mutate(AHSEVFL = NA_character_) %>% # need to make AHSEVFL in this dataset too, to enable binding below + rbind(adae_pre_stdy1_flag) +``` + +..or, `restrict_derivation()` could be wrapped around `derive_var_extreme_flag()`, using the following structure: + +* The function to restrict, `derive_var_extreme_flag()` is passed to `restrict_derivation()` through the `derivation` argument; +* The arguments to `derive_var_extreme_flag()` are passed using a call to `params()`; +* The restriction criterion is provided using the `filter` argument. + +```{r} +adae_ahsevfl <- adae %>% + restrict_derivation( + derivation = derive_var_extreme_flag, + args = params( + new_var = AHSEVFL, + by_vars = exprs(USUBJID), + order = exprs(TEMP_AESEVN, AESTDY, AESEQ), + mode = "first" + ), + filter = AESTDY >= 1 + ) +``` + +```{r, eval=TRUE, echo=FALSE, include = FALSE} +library(admiraldev) +``` + +```{r, eval=TRUE, echo=FALSE} +adae_ahsevfl %>% + arrange(USUBJID, AESTDY, AESEQ, desc(TEMP_AESEVN)) %>% + dataset_vignette( + display_vars = exprs(USUBJID, AEDECOD, AESTDY, AESEQ, AESEV, AHSEVFL) + ) +``` + +Though the ultimate result is the same, the second approach is often preferable as it allows everything to be achieved within one code block, meaning one doesn't necessarily need to break the rhythm achieved when chaining multiple blocks together due to the requirement to "preprocess" the ADaM dataset by only keeping records relevant for the derivation. + +# Call Derivation + +`call_derivation()` is a function that exists purely for convenience: it saves the user repeating numerous similar derivation function calls. It is best used when multiple derived variables have very similar specifications with only slight variations. + +As an example, imagine the case where all the parameters in a BDS ADaM require both a highest value flag and a lowest value flag. + +Here is an example of how to achieve this without using `call_derivation()`: + +```{r} +vs_ahilofl <- vs %>% + derive_var_extreme_flag( + by_vars = exprs(USUBJID, VSTESTCD), + order = exprs(VSORRES, VSSEQ), + new_var = AHIFL, + mode = "last" + ) %>% + derive_var_extreme_flag( + by_vars = exprs(USUBJID, VSTESTCD), + order = exprs(VSORRES, VSSEQ), + new_var = ALOFL, + mode = "first" + ) +``` + +Conversely, here is how to achieve the same objective by using `call_derivation()`. Any arguments differing across runs (such as the name of the new variable) are passed using `params()`, and again the function that needs to be repeatedly called is passed through the `derivation` argument. + +```{r} +vs_ahilofl <- vs %>% + call_derivation( + derivation = derive_var_extreme_flag, + variable_params = list( + params(new_var = AHIFL, mode = "last"), + params(new_var = ALOFL, mode = "first") + ), + by_vars = exprs(USUBJID, VSTESTCD), + order = exprs(VSORRES, VSSEQ) + ) +``` + +```{r, eval=TRUE, echo=FALSE} +vs_ahilofl %>% + arrange(USUBJID, VSTESTCD, VSDY, VSSEQ) %>% + dataset_vignette( + display_vars = exprs(USUBJID, VSTESTCD, VSORRES, ALOFL, AHIFL), + filter = VSTESTCD %in% c("TEMP", "WEIGHT") + ) +``` + +Notice that any arguments that _stay the same_ across iterations (here, `by_vars` and `order`) are instead passed outside of `variable_params`. However, it is important to observe that although the arguments outside `variable_params` are invariant across derivation calls, if any such argument is also specified inside `variable_params` then this selection overrides the outside selection. This can be useful in cases where for most derivation calls, the set of invariant arguments is constant, but for one or two calls a small modification is required. + +Clearly, the advantage of using `call_derivation()` instead of duplicating code blocks only _grows_ as the number of variable derivations with similar needs also grows. + +# Slice Derivation + +This function is essentially a combination of `call_derivation()` and `restrict_derivation()`, since it allows a single derivation to be applied with different arguments for different slices (subsets) of records from the input dataset. One could do this with separate `restrict_derivation()` calls for each different set of records, but `slice_derivation()` allows to achieve this in one call. + +For instance, consider the case where one wanted to achieve a similar derivation to that in the `restrict_derivation()` example (flagging AE with the highest severity for each patient) but while for records occurring on or after study day 1 the intent remains to flag the _first_ occurring AE, for pre-treatment AEs one instead targets the _last_ occurring AE. + +`slice_derivation()` comes to the rescue! + +* Once again, the function to restrict is passed through the `derivation` argument; +* The arguments that remain constant across slices are passed in the `args` selection using a call to `params()`; +* The user passes `derivation_slice`'s to the function detailing the filter condition for the slice in the `filter` argument and what differs across runs in the `args` call. + +Note: observations that match with more than one slice are only considered for the first matching slice. Moreover, observations with no match to any of the slices are included in the output dataset but the derivation is not called for them. + +```{r} +adae_ahsev2fl <- adae %>% + slice_derivation( + derivation = derive_var_extreme_flag, + args = params( + new_var = AHSEV2FL, + by_vars = exprs(USUBJID) + ), + derivation_slice( + filter = AESTDY >= 1, + args = params(order = exprs(TEMP_AESEVN, AESTDY, AESEQ), mode = "first") + ), + derivation_slice( + filter = TRUE, + args = params(order = exprs(AESTDY, AESEQ), mode = "last") + ) + ) +``` + +```{r, eval=TRUE, echo=FALSE} +adae_ahsev2fl %>% + arrange(USUBJID, AESTDY, AESEQ, desc(TEMP_AESEVN)) %>% + dataset_vignette( + display_vars = exprs(USUBJID, AEDECOD, AESTDY, AESEQ, AESEV, AHSEV2FL) + ) +``` + +Notice that the `derivation_slice` ordering is important. in the above examples, all the AEs on or after study day 1 were addressed first, and then the `filter = TRUE` option was employed to catch all remaining records (in this case pre-treatment AEs). + +The ordering is perhaps shown even more when in the below example where three slices are taken. Remember that observations that match with more than one slice are only considered for the first matching slice. Thus, in this case the objective is to create a flag for each patient for the record with the first severe AE, and then the first moderate AE, and finally the last occurring AE which is neither severe or moderate. + +```{r} +adae_ahsev3fl <- adae %>% + slice_derivation( + derivation = derive_var_extreme_flag, + args = params( + new_var = AHSEV3FL, + by_vars = exprs(USUBJID) + ), + derivation_slice( + filter = AESEV == "SEVERE", + args = params(order = exprs(AESTDY, AESEQ), mode = "first") + ), + derivation_slice( + filter = AESEV == "MODERATE", + args = params(order = exprs(AESTDY, AESEQ), mode = "first") + ), + derivation_slice( + filter = TRUE, + args = params(order = exprs(AESTDY, AESEQ), mode = "last") + ) + ) +``` + +```{r, eval=TRUE, echo=FALSE} +adae_ahsev3fl %>% + arrange(USUBJID, AESTDY, AESEQ) %>% + dataset_vignette( + display_vars = exprs(USUBJID, AEDECOD, AESTDY, AESEQ, AESEV, AHSEV3FL) + ) +``` + +The order is only important when the slices are not mutually exclusive, so in the above case the moderate AE slice could have been above the severe AE slice, for example, and there would have been no difference to the result. However the third slice had to come last to check all remaining (i.e. not severe or moderate) records only. + +# Conclusion + +The three higher order functions available in [{admiral}](https://pharmaverse.github.io/admiral/) `restrict_derivation()`, `call_derivation()` and `slice_derivation()`, are a flexible toolset provided by [{admiral}](https://pharmaverse.github.io/admiral/) to streamline ADaM code. They are never the _only_ way to achieve a derivation, but they are often the _most efficient_ way to do so. When code becomes long or convoluted, it is often worth pausing to examine whether one of these could come to the rescue to make life simpler. + + + +```{r, echo=FALSE} +source("appendix.R") +insert_appendix( + repo_spec = "pharmaverse/blog", + name = long_slug +) +```