+ - 0:00:00
Notes for current slide
Notes for next slide

Exploring the Advantages of R Admiral Package

Shuang Gao

BeiGene

1

Agenda

  • The three W's of admiral

    • What is admiral
    • Where is the package located
    • Why use admiral
  • Design of admiral

  • How to use admiral

  • Summary

2

What is admiral

  • An open-source toolbox which enables the development of ADaM datasets in R.
  • Modularised functions, each with a standalone purpose.
  • Designed for code readability, ease of understanding and flexibility
  • Developed in the collaboration between following companies:

3

Where is the package located

  • Find installation guidance on the Admiral website homepage.
  • See user guides for creating ADaMs with Admiral.
  • Also look at our therapeutic area extension packages Admiralonco, Admiraloptha and Admiralvaccine.

Plug Circle Check Find out more: Admiral website

GitHub Feedback: Admiral GitHub

4

Why use admiral

Triangle Exclamation Challenge

Viacoin No standard solutions for ADaMs

Flag A changing and novel data landscape

Gifts New therapeutic areas and analysis concepts

Tumblr Modularized toolbox

Modularized toolbox aims to create a toolset that is both flexible and powerful.

5

Why use admiral

Gifts Good program design is the ability to easily understand what the program does by reading the code, not just how it does it.

Clean Code

Concise

"The code should be small so that we can easily understand the intent of the function by just reading it."

"The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that." — Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanshi

Single Responsibility

"Functions should do one thing. They should do it well. They should do it only."

Functions should have a single responsibility and not be overly complex. Breaking down tasks into smaller, single-purpose functions improves maintainability.

6

Design of admiral - Ways to Think About Data

Conceptual Diagram

Analysts

Programming languages

7

Design of admiral - Data Manipulation

8

Design of admiral - Data Manipulation

9

Design of admiral - Derive Family

Use Intention-Revealing Names: "The name of a variable, function, or class, should answer all the big questions. It should tell you why it exists, what it does, and how it is used."

10

Design of admiral - Derive Family

Usage

derive_vars_dt(
dataset,
new_vars_prefix,
dtc,
highest_imputation = "n",
date_imputation = "first",
flag_imputation = "auto",
min_dates = NULL,
max_dates = NULL,
preserve = FALSE
)

Input

library(tibble)
library(lubridate)
mhdt <- tribble(
~MHSTDTC,
"2019-07-18T15:25:40",
"2019-07-18T15:25",
"2019-07-18",
"2019-02",
"2019",
"2019---07",
""
)

R Code

# Create ASTDT and ASTDTF
# No imputation for partial date
derive_vars_dt(
mhdt,
new_vars_prefix = "AST",
dtc = MHSTDTC
)

Output

#> # A tibble: 7 × 2
#> MHSTDTC ASTDT
#> <chr> <date>
#> 1 "2019-07-18T15:25:40" 2019-07-18
#> 2 "2019-07-18T15:25" 2019-07-18
#> 3 "2019-07-18" 2019-07-18
#> 4 "2019-02" NA
#> 5 "2019" NA
#> 6 "2019---07" NA
#> 7 "" NA
11

Design of admiral - Derive Family

Usage

derive_vars_duration(
dataset,
new_var,
new_var_unit = NULL,
start_date,
end_date,
in_unit = "days",
out_unit = "days",
floor_in = TRUE,
add_one = TRUE,
trunc_out = FALSE
)

R code

library(lubridate)
library(tibble)
data <- tribble(
~USUBJID, ~ASTDT, ~AENDT,
"P01", ymd("2021-03-05"), ymd("2021-03-02"),
"P02", ymd("2019-09-18"), ymd("2019-09-18"),
"P03", ymd("1985-01-01"), NA,
"P04", NA, NA
)
derive_vars_duration(data,
new_var = ADURN,
new_var_unit = ADURU,
start_date = ASTDT,
end_date = AENDT,
out_unit = "days"
)

Output

#> # A tibble: 4 × 5
#> USUBJID ASTDT AENDT ADURN ADURU
#> <chr> <date> <date> <dbl> <chr>
#> 1 P01 2021-03-05 2021-03-02 -3 DAYS
#> 2 P02 2019-09-18 2019-09-18 1 DAYS
#> 3 P03 1985-01-01 NA NA NA
#> 4 P04 NA NA NA NA
12

Design of admiral - Derive Family

Usage

derive_param_bsa(
dataset,
by_vars,
method,
set_values_to = exprs(PARAMCD = "BSA"),
height_code = "HEIGHT",
weight_code = "WEIGHT",
get_unit_expr,
filter = NULL
)

Input

library(tibble)
advs <- tribble(
~USUBJID, ~PARAMCD, ~PARAM, ~AVAL, ~VISIT,
"01-701-1015", "HEIGHT", "Height (cm)", 170, "BASELINE",
"01-701-1015", "WEIGHT", "Weight (kg)", 75, "BASELINE",
"01-701-1015", "WEIGHT", "Weight (kg)", 78, "MONTH 1",
"01-701-1015", "WEIGHT", "Weight (kg)", 80, "MONTH 2",
"01-701-1028", "HEIGHT", "Height (cm)", 185, "BASELINE",
"01-701-1028", "WEIGHT", "Weight (kg)", 90, "BASELINE",
"01-701-1028", "WEIGHT", "Weight (kg)", 88, "MONTH 1",
"01-701-1028", "WEIGHT", "Weight (kg)", 85, "MONTH 2",
)

R code

derive_param_bsa(
advs,
by_vars = exprs(USUBJID, VISIT),
method = "Mosteller",
set_values_to = exprs(
PARAMCD = "BSA",
PARAM = "Body Surface Area (m^2)"
),
get_unit_expr = extract_unit(PARAM)
)

Output

#> # A tibble: 10 × 5
#> USUBJID PARAMCD PARAM AVAL VISIT
#> <chr> <chr> <chr> <dbl> <chr>
#> 1 01-701-1015 HEIGHT Height (cm) 170 BASELINE
#> 2 01-701-1015 WEIGHT Weight (kg) 75 BASELINE
#> 3 01-701-1015 WEIGHT Weight (kg) 78 MONTH 1
#> 4 01-701-1015 WEIGHT Weight (kg) 80 MONTH 2
#> 5 01-701-1028 HEIGHT Height (cm) 185 BASELINE
#> 6 01-701-1028 WEIGHT Weight (kg) 90 BASELINE
#> 7 01-701-1028 WEIGHT Weight (kg) 88 MONTH 1
#> 8 01-701-1028 WEIGHT Weight (kg) 85 MONTH 2
#> 9 01-701-1015 BSA Body Surface Area (m^2) 1.88 BASELINE
#> 10 01-701-1028 BSA Body Surface Area (m^2) 2.15 BASELINE
13

Data Manipulation of Multiple Dataframes

14

Design of admiral - Data Manipulation

Usage

derive_vars_merged(
dataset,
dataset_add,
by_vars,
order = NULL,
new_vars = NULL,
filter_add = NULL,
mode = NULL,
match_flag = NULL,
missing_values = NULL,
check_type = "warning",
duplicate_msg = NULL
)

Input

library(dplyr, warn.conflicts = FALSE)
adsl <- tribble(
~USUBJID, ~SEX, ~COUNTRY,
"ST42-1", "F", "AUT",
"ST42-2", "M", "MWI",
"ST42-3", "M", "NOR",
"ST42-4", "F", "UGA"
)
advs <- tribble(
~USUBJID, ~PARAMCD, ~AVISIT, ~AVISITN, ~AVAL,
"ST42-1", "WEIGHT", "BASELINE", 0, 66,
"ST42-1", "WEIGHT", "WEEK 2", 1, 68,
"ST42-2", "WEIGHT", "BASELINE", 0, 88,
"ST42-3", "WEIGHT", "WEEK 2", 1, 55,
"ST42-3", "WEIGHT", "WEEK 4", 2, 50
)

R code

derive_vars_merged(
adsl,
dataset_add = advs,
by_vars = exprs(USUBJID),
new_vars = exprs(
LSTVSCAT = if_else(AVISIT == "BASELINE", "BASELINE", "POST-BASELINE")
),
order = exprs(AVISITN),
mode = "last",
missing_values = exprs(LSTVSCAT = "MISSING")
)

Output

#> # A tibble: 4 × 4
#> USUBJID SEX COUNTRY LSTVSCAT
#> <chr> <chr> <chr> <chr>
#> 1 ST42-1 F AUT POST-BASELINE
#> 2 ST42-2 M MWI BASELINE
#> 3 ST42-3 M NOR POST-BASELINE
#> 4 ST42-4 F UGA MISSING

15

Design of admiral - Data Manipulation

Usage

derive_vars_joined(
dataset,
dataset_add,
by_vars = NULL,
order = NULL,
new_vars = NULL,
join_vars = NULL,
filter_add = NULL,
filter_join = NULL,
mode = NULL,
missing_values = NULL,
check_type = "warning"
)

Input Data

adae <- tribble(
~USUBJID, ~ASTDT, ~AESEQ,
"1", "2020-02-02", 1,
"1", "2020-02-04", 2
) %>%
mutate(ASTDT = ymd(ASTDT))
ex <- tribble(
~USUBJID, ~EXSDTC,
"1", "2020-01-10",
"1", "2020-01",
"1", "2020-01-20",
"1", "2020-02-03"
)

R code

derive_vars_joined(
adae,
dataset_add = ex,
by_vars = exprs(USUBJID),
order = exprs(EXSDT = convert_dtc_to_dt(EXSDTC)),
new_vars = exprs(LDRELD = compute_duration(
start_date = EXSDT, end_date = ASTDT
)),
filter_add = !is.na(EXSDT),
filter_join = EXSDT <= ASTDT,
mode = "last"
)

Output

#> # A tibble: 2 × 4
#> USUBJID ASTDT AESEQ LDRELD
#> <chr> <date> <dbl> <dbl>
#> 1 1 2020-02-02 1 14
#> 2 1 2020-02-04 2 2

16

Design of admiral

Multiple Sources

Higher Order

17

How to use admiral

Tab1

## Derive variables for first/last treatment date and time imputation flags
adsl <- adsl %>%
derive_vars_merged(
dataset_add = ex_ext,
filter_add = !is.na(EXSTDTM),
new_vars = exprs(TRTSDTM = EXSTDTM, TRTSTMF = EXSTTMF),
order = exprs(EXSTDTM, EXSEQ),
mode = "first",
by_vars = exprs(STUDYID, USUBJID)
)

Tab2

# convert character date to numeric date without imputation
ds_ext <- derive_vars_dt(
ds,
dtc = DSSTDTC,
new_vars_prefix = "DSST"
)
adsl <- adsl %>%
derive_vars_merged(
dataset_add = ds_ext,
by_vars = exprs(STUDYID, USUBJID),
new_vars = exprs(EOSDT = DSSTDT),
filter_add = DSCAT == "DISPOSITION EVENT" & DSDECOD != "SCREEN FAILURE"
)

Tab3

src_ae <- dthcaus_source(
dataset_name = "ae",
filter = AEOUT == "FATAL",
date = convert_dtc_to_dtm(AESTDTC, highest_imputation = "M"),
mode = "first",
dthcaus = AEDECOD
)

Tab4

adsl <- adsl %>%
derive_var_extreme_dt(
new_var = LSTALVDT,
ae_start_date, ae_end_date, lb_date, trt_end_date,
source_datasets = list(ae = ae, adsl = adsl, lb = lb),
mode = "last"
)

Tab5

adsl <- adsl %>%
derive_var_merged_exist_flag(
dataset_add = ex,
by_vars = exprs(STUDYID, USUBJID),
new_var = SAFFL,
condition = (EXDOSE > 0 | (EXDOSE == 0 & str_detect(EXTRT, "PLACEBO")))
)
18

Summary

  • Triangle Exclamation Admiral, as an open-source project, allows anyone to access the source code, learn, modify, and enhance it. This fosters transparency, education, and innovation, enabling different teams and individuals to collaborate in the effort to improve the tool.

  • Code Admiral package advocates the use of simple, composable small functions to build complex behaviors, which helps to improve the readability and maintainability of the code.

  • Check This project provides an entry point for collaboration, co-creation, and contribution for everyone in the pharmaceutical industry. This collaborative effort helps in achieving standardized and consistent methods for developing ADaMs across the entire industry.

19

Acknowledgement

Qiao Yan

20

Agenda

  • The three W's of admiral

    • What is admiral
    • Where is the package located
    • Why use admiral
  • Design of admiral

  • How to use admiral

  • Summary

2
Paused

Help

Keyboard shortcuts

, , Pg Up, k Go to previous slide
, , Pg Dn, Space, j Go to next slide
Home Go to first slide
End Go to last slide
Number + Return Go to specific slide
b / m / f Toggle blackout / mirrored / fullscreen mode
c Clone slideshow
p Toggle presenter mode
t Restart the presentation timer
?, h Toggle this help
Esc Back to slideshow