Creating ADRS with iRECIST endpoints

Introduction

This article describes creating an ADRS ADaM with oncology endpoint parameters based on iRECIST. It shows a similar way of deriving the endpoints presented in Creating ADRS (Including Non-standard Endpoints). Most of the endpoints are derived by calling admiral::derive_extreme_event().

This vignette follows the iRECIST guidelines, for more information user may visit https://recist.eortc.org/irecist/

Examples are currently presented and tested using ADSL (ADaM) and RS (SDTM) inputs. However, other domains could be used. The RS test data contains iRECIST response for target, non-target and overall response. Further pre-processing and considerations may be needed if iRECIST are only collected after RECIST 1.1 progression and input data contains multiple response criteria. The functions and workflow could similarly be used to create an intermediary ADEVENT ADaM.

Note: All examples assume CDISC SDTM and/or ADaM format as input unless otherwise specified.

Programming Workflow

Read in Data

To start, all data frames needed for the creation of ADRS should be read into the environment. This will be a company specific process. Some of the data frames needed may be ADSL, RS and TU. For this vignette we assume that RS provides the response values "iCR", "iPR", "iSD", "NON-iCR/NON-iUPD", "iUPD", "iCPD", and "NE". All examples can be easily modified to consider other response values (see Handling Different Input Response Values).

For example purpose, the SDTM and ADaM datasets (based on CDISC Pilot test data)—which are included in {pharmaversesdtm} and {pharmaverseadam}—are used.

library(admiral)
library(admiralonco)
library(dplyr)
library(pharmaverseadam)
library(pharmaversesdtm)
library(lubridate)
library(stringr)
data("adsl")
# iRECIST oncology sdtm data
data("rs_onco_irecist")

rs <- rs_onco_irecist

rs <- convert_blanks_to_na(rs)

At this step, it may be useful to join ADSL to your RS domain. Only the ADSL variables used for derivations are selected at this step. The rest of the relevant ADSL would be added later.

adsl_vars <- exprs(RANDDT)
adrs <- derive_vars_merged(
  rs,
  dataset_add = adsl,
  new_vars = adsl_vars,
  by_vars = get_admiral_option("subject_keys")
)
USUBJID RSTESTCD RSDTC VISIT RANDDT
01-701-1015 OVRLRESP 2014-02-12 WEEK 6 2014-01-02
01-701-1028 OVRLRESP 2013-08 WEEK 6 2013-07-19
01-701-1028 OVRLRESP 2013-10-09 WEEK 12 2013-07-19
01-701-1028 OVRLRESP 2013-11-20 WEEK 18 2013-07-19
01-701-1034 OVRLRESP 2014-08-11 WEEK 6 2014-07-01
01-701-1034 OVRLRESP 2014-09-25 WEEK 12 2014-07-01
01-701-1034 OVRLRESP 2014-11-04 WEEK 18 2014-07-01
01-701-1097 OVRLRESP 2014-02-11 WEEK 6 2014-01-01
01-701-1115 OVRLRESP 2013-01-10 WEEK 6 2012-11-30
01-701-1118 OVRLRESP 2014-04-23 WEEK 6 2014-03-12

Pre-processing of Input Records

The first step involves company-specific pre-processing of records for the required input to the downstream parameter functions. Note that this could be needed multiple times (e.g. once for investigator and once for Independent Review Facility (IRF)/Blinded Independent Central Review (BICR) records). It could even involve merging input data from other sources besides RS, such as ADTR.

This step would include any required selection/derivation of ADT or applying any necessary partial date imputations, updating AVAL (e.g. this should be ordered from best to worst response), and setting analysis flag ANL01FL. Common options for ANL01FL would be to set null for invalid assessments or those occurring after new anti-cancer therapy, or to only flag assessments on or after date of first treatment/randomization, or rules to cover the case when a patient has multiple observations per visit (e.g. by selecting the worst value). Another consideration could be extra potential protocol-specific sources of Progressive Disease such as radiological assessments, which could be pre-processed here to create a PD record to feed downstream derivations.

For the derivation of the parameters it is expected that the subject identifier variables (usually STUDYID and USUBJID) and ADT are a unique key. This can be achieved by deriving an analysis flag (ANLzzFL). See Derive ANL01FL for an example.

The below shows an example of a possible company-specific implementation of this step.

Select Overall Response Records and Set Parameter Details

In this case we use the overall response records from RS from the investigator as our starting point. The parameter details such as PARAMCD, PARAM etc will always be company-specific, but an example is shown below so that you can trace through how these records feed into the other parameter derivations.

adrs <- adrs %>%
  filter(RSEVAL == "INVESTIGATOR" & RSTESTCD == "OVRLRESP") %>%
  mutate(
    PARAMCD = "OVR",
    PARAM = "Overall Response by Investigator",
    PARCAT1 = "Tumor Response",
    PARCAT2 = "Investigator",
    PARCAT3 = "iRECIST"
  )
USUBJID VISIT RSTESTCD RSEVAL PARAMCD PARAM PARCAT1 PARCAT2 PARCAT3
01-701-1015 WEEK 6 OVRLRESP INVESTIGATOR OVR Overall Response by Investigator Tumor Response Investigator iRECIST
01-701-1028 WEEK 6 OVRLRESP INVESTIGATOR OVR Overall Response by Investigator Tumor Response Investigator iRECIST
01-701-1028 WEEK 12 OVRLRESP INVESTIGATOR OVR Overall Response by Investigator Tumor Response Investigator iRECIST
01-701-1028 WEEK 18 OVRLRESP INVESTIGATOR OVR Overall Response by Investigator Tumor Response Investigator iRECIST
01-701-1034 WEEK 6 OVRLRESP INVESTIGATOR OVR Overall Response by Investigator Tumor Response Investigator iRECIST
01-701-1034 WEEK 12 OVRLRESP INVESTIGATOR OVR Overall Response by Investigator Tumor Response Investigator iRECIST
01-701-1034 WEEK 18 OVRLRESP INVESTIGATOR OVR Overall Response by Investigator Tumor Response Investigator iRECIST
01-701-1097 WEEK 6 OVRLRESP INVESTIGATOR OVR Overall Response by Investigator Tumor Response Investigator iRECIST
01-701-1115 WEEK 6 OVRLRESP INVESTIGATOR OVR Overall Response by Investigator Tumor Response Investigator iRECIST
01-701-1118 WEEK 6 OVRLRESP INVESTIGATOR OVR Overall Response by Investigator Tumor Response Investigator iRECIST

Partial Date Imputation and Deriving ADT, ADTF, AVISIT etc

If your data collection allows for partial dates, you could apply a company-specific imputation rule at this stage when deriving ADT. For this example, here we impute missing day to last possible date.

adrs <- adrs %>%
  derive_vars_dt(
    dtc = RSDTC,
    new_vars_prefix = "A",
    highest_imputation = "D",
    date_imputation = "last"
  ) %>%
  mutate(AVISIT = VISIT)
USUBJID AVISIT PARAMCD PARAM RSSTRESC RSDTC ADT ADTF
01-701-1015 WEEK 6 OVR Overall Response by Investigator iUPD 2014-02-12 2014-02-12 NA
01-701-1028 WEEK 6 OVR Overall Response by Investigator iUPD 2013-08 2013-08-31 D
01-701-1028 WEEK 12 OVR Overall Response by Investigator iCPD 2013-10-09 2013-10-09 NA
01-701-1028 WEEK 18 OVR Overall Response by Investigator iSD 2013-11-20 2013-11-20 NA
01-701-1034 WEEK 6 OVR Overall Response by Investigator iUPD 2014-08-11 2014-08-11 NA
01-701-1034 WEEK 12 OVR Overall Response by Investigator iSD 2014-09-25 2014-09-25 NA
01-701-1034 WEEK 18 OVR Overall Response by Investigator NON-iCR/NON-iUPD 2014-11-04 2014-11-04 NA
01-701-1097 WEEK 6 OVR Overall Response by Investigator NE 2014-02-11 2014-02-11 NA
01-701-1115 WEEK 6 OVR Overall Response by Investigator iUPD 2013-01-10 2013-01-10 NA
01-701-1118 WEEK 6 OVR Overall Response by Investigator iUPD 2014-04-23 2014-04-23 NA

Derive AVALC and AVAL

Here we populate AVALC and create the numeric version as AVAL (ordered from worst to best response, followed by NE and MISSING). The AVAL values are not considered in the parameter derivations below, and so changing AVAL here would not change the result of those derivations. However, please note that the ordering of AVAL will be used to determine ANL01FL in the subsequent step, ensure that the appropriate mode is being set in the admiral::derive_var_extreme_flag().

iRECIST ordering will be used or if you’d like to provide your own company-specific ordering here you could do this as follows:

aval_resp_new <- function(arg) {
  case_when(
    arg == "NE" ~ 8,
    arg == "MISSING" ~ 7,
    arg == "iCR" ~ 6,
    arg == "iPR" ~ 5,
    arg == "iSD" ~ 4,
    arg == "NON-iCR/NON-iUPD" ~ 3,
    arg == "iUPD" ~ 2,
    arg == "iCPD" ~ 1,
    TRUE ~ NA_real_
  )
}

adrs <- adrs %>%
  mutate(
    AVALC = RSSTRESC,
    AVAL = aval_resp_new(AVALC)
  )
USUBJID AVISIT PARAMCD PARAM RSSTRESC AVALC AVAL
01-701-1015 WEEK 6 OVR Overall Response by Investigator iUPD iUPD 2
01-701-1028 WEEK 6 OVR Overall Response by Investigator iUPD iUPD 2
01-701-1028 WEEK 12 OVR Overall Response by Investigator iCPD iCPD 1
01-701-1028 WEEK 18 OVR Overall Response by Investigator iSD iSD 4
01-701-1034 WEEK 6 OVR Overall Response by Investigator iUPD iUPD 2
01-701-1034 WEEK 12 OVR Overall Response by Investigator iSD iSD 4
01-701-1034 WEEK 18 OVR Overall Response by Investigator NON-iCR/NON-iUPD NON-iCR/NON-iUPD 3
01-701-1097 WEEK 6 OVR Overall Response by Investigator NE NE 8
01-701-1115 WEEK 6 OVR Overall Response by Investigator iUPD iUPD 2
01-701-1118 WEEK 6 OVR Overall Response by Investigator iUPD iUPD 2

Flag Worst Assessment at Each Date (ANL01FL)

When deriving ANL01FL this is an opportunity to exclude any records that should not contribute to any downstream parameter derivations. In the below example this includes only selecting valid assessments and those occurring on or after randomization date. If there is more than one assessment at a date, the worst one is flagged.

adrs <- adrs %>%
  restrict_derivation(
    derivation = derive_var_extreme_flag,
    args = params(
      by_vars = c(get_admiral_option("subject_keys"), exprs(ADT)),
      order = exprs(AVAL, RSSEQ),
      new_var = ANL01FL,
      mode = "first"
    ),
    filter = !is.na(AVAL) & AVALC != "MISSING" & ADT >= RANDDT
  )
USUBJID AVISIT PARAMCD PARAM AVALC ADT RANDDT ANL01FL
01-701-1015 WEEK 6 OVR Overall Response by Investigator iUPD 2014-02-12 2014-01-02 Y
01-701-1028 WEEK 6 OVR Overall Response by Investigator iUPD 2013-08-31 2013-07-19 Y
01-701-1028 WEEK 12 OVR Overall Response by Investigator iCPD 2013-10-09 2013-07-19 Y
01-701-1028 WEEK 18 OVR Overall Response by Investigator iSD 2013-11-20 2013-07-19 Y
01-701-1034 WEEK 6 OVR Overall Response by Investigator iUPD 2014-08-11 2014-07-01 Y
01-701-1034 WEEK 12 OVR Overall Response by Investigator iSD 2014-09-25 2014-07-01 Y
01-701-1034 WEEK 18 OVR Overall Response by Investigator NON-iCR/NON-iUPD 2014-11-04 2014-07-01 Y
01-701-1097 WEEK 6 OVR Overall Response by Investigator NE 2014-02-11 2014-01-01 Y
01-701-1115 WEEK 6 OVR Overall Response by Investigator iUPD 2013-01-10 2012-11-30 Y
01-701-1118 WEEK 6 OVR Overall Response by Investigator iUPD 2014-04-23 2014-03-12 Y

Here is an alternative example where those records occurring after new anti-cancer therapy are additionally excluded (where NACTDT would be pre-derived as first date of new anti-cancer therapy. See {admiralonco} Creating and Using New Anti-Cancer Start Date for deriving this variable).

adrs <- adrs %>%
  mutate(
    ANL01FL = case_when(
      !is.na(AVAL) & ADT >= RANDDT & ADT < NACTDT ~ "Y",
      TRUE ~ NA_character_
    )
  )

Flag Assessments up to First iCPD (ANL02FL)

To restrict response data up to and including first reported progressive disease ANL02FL flag could be created by using {admiral} function admiral::derive_var_relative_flag().

adrs <- adrs %>%
  derive_var_relative_flag(
    by_vars = get_admiral_option("subject_keys"),
    order = exprs(ADT, RSSEQ),
    new_var = ANL02FL,
    condition = AVALC == "iCPD",
    mode = "first",
    selection = "before",
    inclusive = TRUE
  )
USUBJID AVISIT PARAMCD AVALC ADT ANL01FL ANL02FL
01-701-1015 WEEK 6 OVR iUPD 2014-02-12 Y Y
01-701-1028 WEEK 6 OVR iUPD 2013-08-31 Y Y
01-701-1028 WEEK 12 OVR iCPD 2013-10-09 Y Y
01-701-1028 WEEK 18 OVR iSD 2013-11-20 Y NA
01-701-1034 WEEK 6 OVR iUPD 2014-08-11 Y Y
01-701-1034 WEEK 12 OVR iSD 2014-09-25 Y Y
01-701-1034 WEEK 18 OVR NON-iCR/NON-iUPD 2014-11-04 Y Y
01-701-1097 WEEK 6 OVR NE 2014-02-11 Y Y
01-701-1115 WEEK 6 OVR iUPD 2013-01-10 Y Y
01-701-1118 WEEK 6 OVR iUPD 2014-04-23 Y Y

Select Source Assessments for Parameter derivations

For most parameter derivations the post-baseline overall response assessments up to and including first iCPD are considered.

ovr <- filter(adrs, PARAMCD == "OVR" & ANL01FL == "Y" & ANL02FL == "Y")
USUBJID AVISIT AVALC ADT RANDDT
01-701-1015 WEEK 6 iUPD 2014-02-12 2014-01-02
01-701-1028 WEEK 6 iUPD 2013-08-31 2013-07-19
01-701-1028 WEEK 12 iCPD 2013-10-09 2013-07-19
01-701-1034 WEEK 6 iUPD 2014-08-11 2014-07-01
01-701-1034 WEEK 12 iSD 2014-09-25 2014-07-01
01-701-1034 WEEK 18 NON-iCR/NON-iUPD 2014-11-04 2014-07-01
01-701-1097 WEEK 6 NE 2014-02-11 2014-01-01
01-701-1115 WEEK 6 iUPD 2013-01-10 2012-11-30
01-701-1118 WEEK 6 iUPD 2014-04-23 2014-03-12
01-701-1118 WEEK 12 iSD 2014-06-05 2014-03-12

Define Events

The building blocks for the events that contribute to deriving common endpoints like what constitutes a responder, or a Best Overall Response of complete response (CR), … are predefined in admiralonco for RECIST 1.1 (see Pre-Defined Response Event Objects). New Response Event Objects are needed for iRECIST and any study-specific needs.

icpd_y <- event_joined(
  description = paste(
    "Define confirmed progressive disease (iCPD) as",
    "iUPD followed by iCPD with only other iUPD and NE responses in between"
  ),
  dataset_name = "ovr",
  join_vars = exprs(AVALC, ADT),
  join_type = "after",
  first_cond_upper = AVALC.join == "iCPD",
  condition = AVALC == "iUPD" &
    all(AVALC.join %in% c("iCPD", "iUPD", "NE")),
  set_values_to = exprs(AVALC = "Y")
)

iupd_y <- event_joined(
  description = paste(
    "Define unconfirmed progressive disease (iUPD) as",
    "iUPD followed only by other iUPD or NE responses"
  ),
  dataset_name = "ovr",
  join_vars = exprs(AVALC, ADT),
  join_type = "all",
  condition = ADT <= ADT.join & AVALC == "iUPD" & all(AVALC.join %in% c("iUPD", "NE")),
  set_values_to = exprs(AVALC = "Y")
)

no_data_n <- event(
  description = "Define no response for all patients in adsl (should be used as last event)",
  dataset_name = "adsl",
  condition = TRUE,
  set_values_to = exprs(AVALC = "N"),
  keep_source_vars = adsl_vars
)

no_data_missing <- event(
  description = paste(
    "Define missing response (MISSING) for all patients in adsl (should be used",
    "as last event)"
  ),
  dataset_name = "adsl",
  condition = TRUE,
  set_values_to = exprs(AVALC = "MISSING"),
  keep_source_vars = adsl_vars
)

Handling Different Input Response Values

If RS contains other response values than the iRECIST responses, the event() and event_joined() can be adjusted to cover this scenario. For example, if RECIST responses ("CR", "PR", "SD", …) are collected up to first PD and iRECIST responses ("iCR", "iPR", "iSD", …) thereafter, the event() object defining unconfirmed response can be adjusted in the following way.

irsp_y <- event(
  description = "Define CR, iCR, PR, or iPR as (unconfirmed) response",
  dataset_name = "ovr",
  condition = AVALC %in% c("CR", "iCR", "PR", "iPR"),
  set_values_to = exprs(AVALC = "Y")
)

Derive Confirmed and Unconfirmed Progressive Disease Parameter

Now that we have the input records prepared above with any company-specific requirements, we can start to derive new parameter records. For the parameter derivations, all values except those overwritten by set_values_to argument are kept from the earliest occurring input record fulfilling the required criteria.

When an iCPD occurs, the date of progression would be the first occurrence of iUPD in that block. For example, when we have values of iUPD, iUPD, and iCPD, the iRECIST PD date would be the first occurrence of iUPD. In cases where we have SD, SD, iUPD, PR, PR, iUPD, and iCPD, the iRECIST PD date would be the second occurrence of iUPD.

The function admiral::derive_extreme_records(), in conjunction with the event icpd_y, could be used to find the date of the first iUPD.

For the Unconfirmed Progressive Disease Parameter, it can be of interest to look at iUPD that has never been confirmed and no subsequent iSD, iPR or iCR has been observed.

adrs <- adrs %>%
  derive_extreme_event(
    by_vars = get_admiral_option("subject_keys"),
    order = exprs(ADT),
    mode = "first",
    source_datasets = list(
      ovr = ovr,
      adsl = adsl
    ),
    events = list(icpd_y, no_data_n),
    set_values_to = exprs(
      PARAMCD = "ICPD",
      PARAM = "iRECIST Confirmation of Disease Progression by Investigator",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "iRECIST",
      AVAL = yn_to_numeric(AVALC),
      ANL01FL = "Y"
    )
  )

ovr_orig <- ovr
ovr <- ovr %>%
  group_by(!!!get_admiral_option("subject_keys")) %>%
  filter(ADT >= max_cond(var = ADT, cond = AVALC == "iUPD")) %>%
  ungroup(!!!get_admiral_option("subject_keys"))

adrs <- adrs %>%
  derive_extreme_event(
    by_vars = get_admiral_option("subject_keys"),
    order = exprs(ADT),
    mode = "first",
    source_datasets = list(
      ovr = ovr,
      adsl = adsl
    ),
    events = list(iupd_y, no_data_n),
    set_values_to = exprs(
      PARAMCD = "IUPD",
      PARAM = "iRECIST Unconfirmed Disease Progression by Investigator",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "iRECIST",
      AVAL = yn_to_numeric(AVALC),
      ANL01FL = "Y"
    )
  )
ovr <- ovr_orig
USUBJID AVISIT PARAMCD PARAM AVALC ADT ANL01FL
01-701-1015 NA ICPD iRECIST Confirmation of Disease Progression by Investigator N NA Y
01-701-1023 NA ICPD iRECIST Confirmation of Disease Progression by Investigator N NA Y
01-701-1028 WEEK 6 ICPD iRECIST Confirmation of Disease Progression by Investigator Y 2013-08-31 Y
01-701-1034 NA ICPD iRECIST Confirmation of Disease Progression by Investigator N NA Y
01-701-1097 NA ICPD iRECIST Confirmation of Disease Progression by Investigator N NA Y
01-701-1115 NA ICPD iRECIST Confirmation of Disease Progression by Investigator N NA Y
01-701-1118 NA ICPD iRECIST Confirmation of Disease Progression by Investigator N NA Y
01-701-1130 NA ICPD iRECIST Confirmation of Disease Progression by Investigator N NA Y
01-701-1133 NA ICPD iRECIST Confirmation of Disease Progression by Investigator N NA Y
01-701-1146 NA ICPD iRECIST Confirmation of Disease Progression by Investigator N NA Y

For progressive disease and response shown in steps here and below, in our examples we show these as ADRS parameters, but they could equally be achieved via ADSL dates or ADEVENT parameters.If you prefer to store as an ADSL date, then the function admiral::derive_var_extreme_dt() could be used to find the date of first iCPD as a variable, rather than as a new parameter record.

Derive Response Parameter

The function admiral::derive_extreme_event() can then be used to find the date of first response. In the below example, the response condition has been defined as iCR or iPR via the event irsp_y that was created for iRECIST.

irsp_y <- event(
  description = "Define iCR or iPR as (unconfirmed) response",
  dataset_name = "ovr",
  condition = AVALC %in% c("iCR", "iPR"),
  set_values_to = exprs(AVALC = "Y")
)

adrs <- adrs %>%
  derive_extreme_event(
    by_vars = get_admiral_option("subject_keys"),
    order = exprs(ADT),
    mode = "first",
    events = list(irsp_y, no_data_n),
    source_datasets = list(
      ovr = ovr,
      adsl = adsl
    ),
    set_values_to = exprs(
      PARAMCD = "IRSP",
      PARAM = "iRECIST Response by Investigator (confirmation not required)",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "iRECIST",
      AVAL = yn_to_numeric(AVALC),
      ANL01FL = "Y"
    )
  )
USUBJID AVISIT PARAMCD PARAM AVALC ADT ANL01FL
01-701-1015 NA IRSP iRECIST Response by Investigator (confirmation not required) N NA Y
01-701-1023 NA IRSP iRECIST Response by Investigator (confirmation not required) N NA Y
01-701-1028 NA IRSP iRECIST Response by Investigator (confirmation not required) N NA Y
01-701-1034 NA IRSP iRECIST Response by Investigator (confirmation not required) N NA Y
01-701-1097 NA IRSP iRECIST Response by Investigator (confirmation not required) N NA Y
01-701-1115 NA IRSP iRECIST Response by Investigator (confirmation not required) N NA Y
01-701-1118 NA IRSP iRECIST Response by Investigator (confirmation not required) N NA Y
01-701-1130 WEEK 12 IRSP iRECIST Response by Investigator (confirmation not required) Y 2014-05-16 Y
01-701-1133 WEEK 12 IRSP iRECIST Response by Investigator (confirmation not required) Y 2013-01-22 Y
01-701-1146 NA IRSP iRECIST Response by Investigator (confirmation not required) N NA Y

Derive Clinical Benefit Parameter

The function admiral::derive_extreme_event() can then be used to derive the clinical benefit parameter, which we define as a patient having had a response or a sustained period of time before first iUPD. This could also be known as disease control. In this example the “sustained period” has been defined as 42 days after randomization date via the created icb_y event.

icb_y <- event(
  description = paste(
    "Define iCR, iPR, iSD, or NON-iCR/NON-iUPD occuring at least 42 days after",
    "randomization as clinical benefit"
  ),
  dataset_name = "ovr",
  condition = AVALC %in% c("iCR", "iPR", "iSD", "NON-iCR/NON-iUPD") &
    ADT >= RANDDT + 42,
  set_values_to = exprs(AVALC = "Y")
)

Please note that the result AVALC = "Y" is defined by the first two events specified for events. For subjects with observations fulfilling both events the one with the earlier date should be selected (and not the first one in the list). Thus ignore_event_order and tmp_event_nr_var are not specified.

adrs <- adrs %>%
  derive_extreme_event(
    by_vars = get_admiral_option("subject_keys"),
    order = exprs(desc(AVALC), ADT),
    mode = "first",
    events = list(irsp_y, icb_y, no_data_n),
    source_datasets = list(
      ovr = ovr,
      adsl = adsl
    ),
    set_values_to = exprs(
      PARAMCD = "ICB",
      PARAM = "iRECIST Clinical Benefit by Investigator (confirmation for response not required)",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "iRECIST",
      AVAL = yn_to_numeric(AVALC),
      ANL01FL = "Y"
    ),
    check_type = "none"
  )
USUBJID AVISIT PARAMCD PARAM AVALC ADT RANDDT ANL01FL
01-701-1015 NA ICB iRECIST Clinical Benefit by Investigator (confirmation for response not required) N NA 2014-01-02 Y
01-701-1023 NA ICB iRECIST Clinical Benefit by Investigator (confirmation for response not required) N NA 2012-08-05 Y
01-701-1028 NA ICB iRECIST Clinical Benefit by Investigator (confirmation for response not required) N NA 2013-07-19 Y
01-701-1034 WEEK 12 ICB iRECIST Clinical Benefit by Investigator (confirmation for response not required) Y 2014-09-25 2014-07-01 Y
01-701-1097 NA ICB iRECIST Clinical Benefit by Investigator (confirmation for response not required) N NA 2014-01-01 Y
01-701-1115 NA ICB iRECIST Clinical Benefit by Investigator (confirmation for response not required) N NA 2012-11-30 Y
01-701-1118 WEEK 12 ICB iRECIST Clinical Benefit by Investigator (confirmation for response not required) Y 2014-06-05 2014-03-12 Y
01-701-1130 WEEK 12 ICB iRECIST Clinical Benefit by Investigator (confirmation for response not required) Y 2014-05-16 2014-02-15 Y
01-701-1133 WEEK 6 ICB iRECIST Clinical Benefit by Investigator (confirmation for response not required) Y 2012-12-11 2012-10-28 Y
01-701-1146 NA ICB iRECIST Clinical Benefit by Investigator (confirmation for response not required) N NA 2013-05-20 Y

Derive Best Overall Response Parameter

The function admiral::derive_extreme_event() can be used to derive the best overall response (without confirmation required) parameter. Similar to the above function you can optionally decide what period would you consider an iSD or NON-iCR/NON-iUPD as being eligible from. In this example, 42 days after randomization date has been used again.

Please note that the order of the events specified for events is important. For example, a subject with iPR, iPR, iCR qualifies for both ibor_icr and ibor_ipr. As ibor_icr is listed before ibor_ipr, iCR is selected as best overall response for this subject.

ibor_icr <- event(
  description = "Define complete response (iCR) for best overall response (iBOR)",
  dataset_name = "ovr",
  condition = AVALC == "iCR",
  set_values_to = exprs(AVALC = "iCR")
)

ibor_ipr <- event(
  description = "Define partial response (iPR) for best overall response (iBOR)",
  dataset_name = "ovr",
  condition = AVALC == "iPR",
  set_values_to = exprs(AVALC = "iPR")
)

ibor_isd <- event(
  description = paste(
    "Define stable disease (iSD) for best overall response (iBOR) as iCR, iPR, or iSD",
    "occurring at least 42 days after randomization"
  ),
  dataset_name = "ovr",
  condition = AVALC %in% c("iCR", "iPR", "iSD") & ADT >= RANDDT + 42,
  set_values_to = exprs(AVALC = "iSD")
)

ibor_non_icriupd <- event(
  description = paste(
    "Define NON-iCR/NON-iUPD for best overall response (iBOR) as NON-iCR/NON-iUPD",
    "occuring at least 42 days after randomization"
  ),
  dataset_name = "ovr",
  condition = AVALC == "NON-iCR/NON-iUPD" & ADT >= RANDDT + 42,
  set_values_to = exprs(AVALC = "NON-iCR/NON-iUPD")
)


ibor_icpd <- event_joined(
  description = paste(
    "Define confirmed progressive disease (iCPD) for best overall response (iBOR) as",
    "iUPD followed by iCPD with only other iUPD and NE responses in between"
  ),
  dataset_name = "ovr",
  join_vars = exprs(AVALC, ADT),
  join_type = "after",
  first_cond_upper = AVALC.join == "iCPD",
  condition = AVALC == "iUPD" &
    all(AVALC.join %in% c("iCPD", "iUPD", "NE")),
  set_values_to = exprs(AVALC = "iCPD")
)


ibor_iupd <- event(
  description = "Define unconfirmed progressive disease (iUPD) for best overall response (iBOR)",
  dataset_name = "ovr",
  condition = AVALC == "iUPD",
  set_values_to = exprs(AVALC = "iUPD")
)

ibor_ne <- event(
  description = paste(
    "Define not evaluable (NE) for best overall response (iBOR) as iCR, iPR, iSD,",
    "NON-iCR/NON-iUPD, or NE (should be specified after ibor_isd and ibor_non_icriupd)"
  ),
  dataset_name = "ovr",
  condition = AVALC %in% c("iCR", "iPR", "iSD", "NON-iCR/NON-iUPD", "NE"),
  set_values_to = exprs(AVALC = "NE")
)

adrs <- adrs %>%
  derive_extreme_event(
    by_vars = get_admiral_option("subject_keys"),
    tmp_event_nr_var = event_nr,
    order = exprs(event_nr, ADT),
    mode = "first",
    source_datasets = list(
      ovr = ovr,
      adsl = adsl
    ),
    events = list(ibor_icr, ibor_ipr, ibor_isd, ibor_non_icriupd, ibor_icpd, ibor_iupd, ibor_ne, no_data_missing),
    set_values_to = exprs(
      PARAMCD = "IBOR",
      PARAM = "iRECIST Best Overall Response by Investigator (confirmation not required)",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "iRECIST",
      AVAL = aval_resp_new(AVALC),
      ANL01FL = "Y"
    )
  )
USUBJID AVISIT PARAMCD PARAM AVALC ADT RANDDT ANL01FL
01-701-1015 WEEK 6 IBOR iRECIST Best Overall Response by Investigator (confirmation not required) iUPD 2014-02-12 2014-01-02 Y
01-701-1023 NA IBOR iRECIST Best Overall Response by Investigator (confirmation not required) MISSING NA 2012-08-05 Y
01-701-1028 WEEK 6 IBOR iRECIST Best Overall Response by Investigator (confirmation not required) iCPD 2013-08-31 2013-07-19 Y
01-701-1034 WEEK 12 IBOR iRECIST Best Overall Response by Investigator (confirmation not required) iSD 2014-09-25 2014-07-01 Y
01-701-1097 WEEK 6 IBOR iRECIST Best Overall Response by Investigator (confirmation not required) NE 2014-02-11 2014-01-01 Y
01-701-1115 WEEK 6 IBOR iRECIST Best Overall Response by Investigator (confirmation not required) iUPD 2013-01-10 2012-11-30 Y
01-701-1118 WEEK 12 IBOR iRECIST Best Overall Response by Investigator (confirmation not required) iSD 2014-06-05 2014-03-12 Y
01-701-1130 WEEK 12 IBOR iRECIST Best Overall Response by Investigator (confirmation not required) iCR 2014-05-16 2014-02-15 Y
01-701-1133 WEEK 12 IBOR iRECIST Best Overall Response by Investigator (confirmation not required) iPR 2013-01-22 2012-10-28 Y
01-701-1146 WEEK 6 IBOR iRECIST Best Overall Response by Investigator (confirmation not required) iUPD 2013-06-30 2013-05-20 Y

Derive Response Parameters requiring Confirmation

Any of the above response parameters can be repeated for “confirmed” responses only. For these the function admiral::derive_extreme_event() can be used with different events. Some of the other functions from above can then be re-used passing in these confirmed response records. See the examples below of derived parameters requiring confirmation. The assessment and the confirmatory assessment here need to occur at least 28 days apart (without any +1 applied to this calculation of days between visits), using the icrsp_y_cr, icrsp_y_ipr, icbor_icr, and icbor_ipr event. Here the confirmation period and the keep_source_vars argument is updated, as well as the first_cond_upper and condition for the iRECIST values.

confirmation_period <- 28

icrsp_y_icr <- event_joined(
  description = paste(
    "Define confirmed response as iCR followed by iCR at least",
    confirmation_period,
    "days later and at most one NE in between"
  ),
  dataset_name = "ovr",
  join_vars = exprs(AVALC, ADT),
  join_type = "after",
  order = exprs(ADT),
  first_cond_upper = AVALC.join == "iCR" &
    ADT.join >= ADT + days(confirmation_period),
  condition = AVALC == "iCR" &
    all(AVALC.join %in% c("iCR", "NE")) &
    count_vals(var = AVALC.join, val = "NE") <= 1,
  set_values_to = exprs(AVALC = "Y")
)

icrsp_y_ipr <- event_joined(
  description = paste(
    "Define confirmed response as iPR followed by iCR or iPR at least",
    confirmation_period,
    "days later at most one NE in between, and no iPR after iCR"
  ),
  dataset_name = "ovr",
  join_vars = exprs(AVALC, ADT),
  join_type = "after",
  order = exprs(ADT),
  first_cond_upper = AVALC.join %in% c("iCR", "iPR") &
    ADT.join >= ADT + days(confirmation_period),
  condition = AVALC == "iPR" &
    all(AVALC.join %in% c("iCR", "iPR", "NE")) &
    count_vals(var = AVALC.join, val = "NE") <= 1 &
    (
      min_cond(
        var = ADT.join,
        cond = AVALC.join == "iCR"
      ) > max_cond(var = ADT.join, cond = AVALC.join == "iPR") |
        count_vals(var = AVALC.join, val = "iCR") == 0 |
        count_vals(var = AVALC.join, val = "iPR") == 0
    ),
  set_values_to = exprs(AVALC = "Y")
)

icbor_icr <- event_joined(
  description = paste(
    "Define complete response (iCR) for confirmed best overall response (iCBOR) as",
    "iCR followed by iCR at least",
    confirmation_period,
    "days later and at most one NE in between"
  ),
  dataset_name = "ovr",
  join_vars = exprs(AVALC, ADT),
  join_type = "after",
  first_cond_upper = AVALC.join == "iCR" &
    ADT.join >= ADT + confirmation_period,
  condition = AVALC == "iCR" &
    all(AVALC.join %in% c("iCR", "NE")) &
    count_vals(var = AVALC.join, val = "NE") <= 1,
  set_values_to = exprs(AVALC = "iCR")
)

icbor_ipr <- event_joined(
  description = paste(
    "Define partial response (iPR) for confirmed best overall response (iCBOR) as",
    "iPR followed by iCR or iPR at least",
    confirmation_period,
    "days later, at most one NE in between and no iPR after iCR"
  ),
  dataset_name = "ovr",
  join_vars = exprs(AVALC, ADT),
  join_type = "after",
  first_cond_upper = AVALC.join %in% c("iCR", "iPR") &
    ADT.join >= ADT + confirmation_period,
  condition = AVALC == "iPR" &
    all(AVALC.join %in% c("iCR", "iPR", "NE")) &
    count_vals(var = AVALC.join, val = "NE") <= 1 &
    (
      min_cond(
        var = ADT.join,
        cond = AVALC.join == "iCR"
      ) > max_cond(var = ADT.join, cond = AVALC.join == "iPR") |
        count_vals(var = AVALC.join, val = "iCR") == 0 |
        count_vals(var = AVALC.join, val = "iPR") == 0
    ),
  set_values_to = exprs(AVALC = "iPR")
)

Please note that the result AVALC = "Y" for confirmed clinical benefit is defined by the first two events specified for events. For subjects with observations fulfilling both events the one with the earlier date should be selected (and not the first one in the list).

adrs <- adrs %>%
  derive_extreme_event(
    by_vars = get_admiral_option("subject_keys"),
    order = exprs(desc(AVALC), ADT),
    mode = "first",
    source_datasets = list(
      ovr = ovr,
      adsl = adsl
    ),
    events = list(icrsp_y_icr, icrsp_y_ipr, no_data_n),
    set_values_to = exprs(
      PARAMCD = "ICRSP",
      PARAM = "iRECIST Confirmed Response by Investigator",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "iRECIST",
      AVAL = yn_to_numeric(AVALC),
      ANL01FL = "Y"
    )
  )

adrs <- adrs %>%
  derive_extreme_event(
    by_vars = get_admiral_option("subject_keys"),
    order = exprs(desc(AVALC), ADT),
    mode = "first",
    events = list(icrsp_y_icr, icrsp_y_ipr, icb_y, no_data_n),
    source_datasets = list(
      ovr = ovr,
      adsl = adsl
    ),
    set_values_to = exprs(
      PARAMCD = "ICCB",
      PARAM = "iRECIST Confirmed Clinical Benefit by Investigator",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "iRECIST",
      AVAL = yn_to_numeric(AVALC),
      ANL01FL = "Y"
    ),
    check_type = "none"
  )

adrs <- adrs %>%
  derive_extreme_event(
    by_vars = get_admiral_option("subject_keys"),
    tmp_event_nr_var = event_nr,
    order = exprs(event_nr, ADT),
    mode = "first",
    events = list(icbor_icr, icbor_ipr, ibor_isd, ibor_non_icriupd, ibor_icpd, ibor_iupd, ibor_ne, no_data_missing),
    source_datasets = list(
      ovr = ovr,
      adsl = adsl
    ),
    set_values_to = exprs(
      PARAMCD = "ICBOR",
      PARAM = "iRECIST Best Confirmed Overall Response by Investigator",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "iRECIST",
      AVAL = aval_resp(AVALC),
      ANL01FL = "Y"
    )
  )
USUBJID AVISIT PARAMCD PARAM AVALC ADT RANDDT ANL01FL
01-701-1015 NA ICRSP iRECIST Confirmed Response by Investigator N NA 2014-01-02 Y
01-701-1023 NA ICRSP iRECIST Confirmed Response by Investigator N NA 2012-08-05 Y
01-701-1028 NA ICRSP iRECIST Confirmed Response by Investigator N NA 2013-07-19 Y
01-701-1034 NA ICRSP iRECIST Confirmed Response by Investigator N NA 2014-07-01 Y
01-701-1097 NA ICRSP iRECIST Confirmed Response by Investigator N NA 2014-01-01 Y
01-701-1115 NA ICRSP iRECIST Confirmed Response by Investigator N NA 2012-11-30 Y
01-701-1118 NA ICRSP iRECIST Confirmed Response by Investigator N NA 2014-03-12 Y
01-701-1130 WEEK 12 ICRSP iRECIST Confirmed Response by Investigator Y 2014-05-16 2014-02-15 Y
01-701-1133 WEEK 12 ICRSP iRECIST Confirmed Response by Investigator Y 2013-01-22 2012-10-28 Y
01-701-1146 NA ICRSP iRECIST Confirmed Response by Investigator N NA 2013-05-20 Y

Other Endpoints

The following parameters may also be added:

IBCP - iRECIST Best Overall Response of CR/PR by Investigator (confirmation not required)
ICBCP - iRECIST Best Confirmed Overall Response of CR/PR by Investigator
IOVRB - iRECIST Overall Response by BICR
ILSTA - iRECIST Last Disease Assessment by Investigator
IMDIS - iRECIST Measurable Disease at Baseline by Investigator

For examples on the additional endpoints, please see Creating ADRS (Including Non-standard Endpoints).