---
title: "Creating ADRS (Including Non-standard Endpoints)"
output: 
  rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Creating ADRS (Including Non-standard Endpoints)}
  %\VignetteEncoding{UTF-8}
  %\VignetteEngine{knitr::rmarkdown}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)

library(admiraldev)
```

# Introduction

This article describes creating an `ADRS` ADaM with oncology endpoint parameters
based on RECIST v1.1. It shows an alternative way of deriving the endpoints
presented in [Creating a Basic ADRS](adrs_basic.html) and additionally modified
versions of the endpoints (see [Derive Non-standard Parameters](#nonstandard))
which cannot be derived by the admiralonco functions. Most of the endpoints are
derived by calling `admiral::derive_extreme_event()`. It is very flexible. Thus
the examples in this vignette can also be used as a starting point for
implementing other response criteria than RECIST 1.1, e.g., iRECIST or
International Myeloma Working Group (IMWG) criteria for the diagnosis of
multiple myeloma.

Examples are currently presented and tested using `ADSL` (ADaM) and
`RS`, `TU` (SDTM) inputs. However, other domains could be used. 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](#readdata)
-   [Pre-processing of Input Records](#input)
-   [Derive Progressive Disease Parameter](#pd)
-   [Derive Response Parameter](#rsp)
-   [Derive Clinical Benefit Parameter](#cb)
-   [Derive Best Overall Response Parameter](#bor)
-   [Derive Best Overall Response of CR/PR Parameter](#bcp)
-   [Derive Response Parameters requiring Confirmation](#confirm)
-   [Derive Non-standard Parameters](#nonstandard)
-   [Derive Parameters using Independent Review Facility (IRF)/
    Blinded Independent Central Review (BICR) responses](#irf)
-   [Derive Death Parameter](#death)
-   [Derive Last Disease Assessment Parameters](#lsta)
-   [Derive Measurable Disease at Baseline Parameter](#mdis)
-   [Derive `AVAL` for New Parameters](#aval)
-   [Assign `ASEQ`](#aseq)
-   [Add ADSL variables](#adsl_vars)

## Read in Data {#readdata}

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 example purpose, the SDTM and ADaM datasets (based on CDISC Pilot
test data)---which are included in `{pharmaversesdtm}` and
`{pharmaverseadam}`---are used.

```{r message=FALSE}
library(admiral)
library(admiralonco)
library(dplyr)
library(pharmaversesdtm)
library(pharmaverseadam)
library(lubridate)
library(stringr)
data("adsl")
data("rs_onco_recist")
data("tu_onco_recist")

rs <- rs_onco_recist
tu <- tu_onco_recist

rs <- convert_blanks_to_na(rs)
tu <- convert_blanks_to_na(tu)
```

```{r echo=FALSE}
# select subjects from adsl such that there is one subject without RS data
rs_subjects <- unique(rs$USUBJID)
adsl_subjects <- unique(adsl$USUBJID)
adsl <- filter(
  adsl,
  USUBJID %in% union(rs_subjects, setdiff(adsl_subjects, rs_subjects)[1])
)
```

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.

```{r eval=TRUE}
adsl_vars <- exprs(RANDDT)
adrs <- derive_vars_merged(
  rs,
  dataset_add = adsl,
  new_vars = adsl_vars,
  by_vars = exprs(STUDYID, USUBJID)
)
```

```{r, eval=TRUE, echo=FALSE}
dataset_vignette(
  adrs,
  display_vars = exprs(USUBJID, RSTESTCD, RSDTC, VISIT, RANDDT),
  filter = RSTESTCD == "OVRLRESP"
)
```

## Pre-processing of Input Records {#input}

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 after date of first
treatment/randomization, or rules to cover the case when a patient has
multiple observations per visit (e.g. by selecting 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`](#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.

```{r}
adrs <- adrs %>%
  filter(RSEVAL == "INVESTIGATOR" & RSTESTCD == "OVRLRESP") %>%
  mutate(
    PARAMCD = "OVR",
    PARAM = "Overall Response by Investigator",
    PARCAT1 = "Tumor Response",
    PARCAT2 = "Investigator",
    PARCAT3 = "RECIST 1.1"
  )
```

```{r, echo=FALSE}
dataset_vignette(
  adrs,
  display_vars = exprs(USUBJID, VISIT, RSTESTCD, RSEVAL, PARAMCD, PARAM, PARCAT1, PARCAT2, PARCAT3)
)
```

### 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.

```{r}
adrs <- adrs %>%
  derive_vars_dt(
    dtc = RSDTC,
    new_vars_prefix = "A",
    highest_imputation = "D",
    date_imputation = "last"
  ) %>%
  mutate(AVISIT = VISIT)
```

```{r, echo=FALSE}
dataset_vignette(
  adrs,
  display_vars = exprs(USUBJID, AVISIT, PARAMCD, PARAM, RSSTRESC, RSDTC, ADT, ADTF)
)
```

### Derive `AVALC` and `AVAL`

Here we populate `AVALC` and create the numeric version as `AVAL`
(ordered from best to worst response). The `AVAL` values are not considered in
the parameter derivations below, and so changing `AVAL` here would not change
the result of those derivations.

```{r}
adrs <- adrs %>%
  mutate(
    AVALC = RSSTRESC,
    AVAL = aval_resp(AVALC)
  )
```

```{r, echo=FALSE}
dataset_vignette(
  adrs,
  display_vars = exprs(USUBJID, AVISIT, PARAMCD, PARAM, RSSTRESC, AVALC, AVAL)
)
```

### Flag Worst Assessment at Each Date (`ANL01FL`) {#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.

```{r}
worst_resp <- function(arg) {
  case_when(
    arg == "NE" ~ 1,
    arg == "CR" ~ 2,
    arg == "PR" ~ 3,
    arg == "SD" ~ 4,
    arg == "NON-CR/NON-PD" ~ 5,
    arg == "PD" ~ 6,
    TRUE ~ 0
  )
}

adrs <- adrs %>%
  restrict_derivation(
    derivation = derive_var_extreme_flag,
    args = params(
      by_vars = exprs(STUDYID, USUBJID, ADT),
      order = exprs(worst_resp(AVALC), RSSEQ),
      new_var = ANL01FL,
      mode = "last"
    ),
    filter = !is.na(AVAL) & ADT >= RANDDT
  )
```

```{r, echo=FALSE}
dataset_vignette(
  adrs,
  display_vars = exprs(USUBJID, AVISIT, PARAMCD, PARAM, AVALC, ADT, RANDDT, ANL01FL)
)
```

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](nactdt.html) for deriving this
variable).

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

### Flag Assessments up to First PD (`ANL02FL`) {#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()`.

```{r}
adrs <- adrs %>%
  derive_var_relative_flag(
    by_vars = exprs(STUDYID, USUBJID),
    order = exprs(ADT, RSSEQ),
    new_var = ANL02FL,
    condition = AVALC == "PD",
    mode = "first",
    selection = "before",
    inclusive = TRUE
  )
```

```{r, echo=FALSE}
dataset_vignette(
  adrs,
  display_vars = exprs(USUBJID, AVISIT, PARAMCD, AVALC, ADT, ANL01FL, ANL02FL)
)
```

### Select Source Assessments for Parameter derivations

For most parameter derivations the post-baseline overall response assessments up
to and including first PD are considered.
```{r}
ovr <- filter(adrs, PARAMCD == "OVR" & ANL01FL == "Y" & ANL02FL == "Y")
```

```{r, echo=FALSE}
dataset_vignette(
  ovr,
  display_vars = exprs(USUBJID, AVISIT, AVALC, ADT, RANDDT)
)
```

## 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 (see [Pre-Defined Response
Event Objects](../reference/event_objects.html)). Some may need to be adjusted
for study-specific needs, e.g., minimum time between response and confirmation
assessment. Here the confirmation period and the `keep_source_vars` argument is
updated.

```{r}
confirmation_period <- 21

crsp_y_cr <- event_joined(
  description = paste(
    "Define confirmed response as CR followed by CR 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 == "CR" &
    ADT.join >= ADT + days(confirmation_period),
  condition = AVALC == "CR" &
    all(AVALC.join %in% c("CR", "NE")) &
    count_vals(var = AVALC.join, val = "NE") <= 1,
  set_values_to = exprs(AVALC = "Y")
)

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

cbor_cr <- event_joined(
  description = paste(
    "Define complete response (CR) for confirmed best overall response (CBOR) as",
    "CR followed by CR 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 == "CR" &
    ADT.join >= ADT + confirmation_period,
  condition = AVALC == "CR" &
    all(AVALC.join %in% c("CR", "NE")) &
    count_vals(var = AVALC.join, val = "NE") <= 1,
  set_values_to = exprs(AVALC = "CR")
)

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

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
)
```

## Derive Progressive Disease Parameter {#pd}

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.

The function `admiral::derive_extreme_records()` can be used to find
the date of first `PD`.

```{r}
adrs <- adrs %>%
  derive_extreme_records(
    dataset_ref = adsl,
    dataset_add = adrs,
    by_vars = exprs(STUDYID, USUBJID),
    filter_add = PARAMCD == "OVR" & AVALC == "PD" & ANL01FL == "Y",
    order = exprs(ADT, RSSEQ),
    mode = "first",
    exist_flag = AVALC,
    false_value = "N",
    set_values_to = exprs(
      PARAMCD = "PD",
      PARAM = "Disease Progression by Investigator",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "RECIST 1.1",
      AVAL = yn_to_numeric(AVALC),
      ANL01FL = "Y"
    )
  )
```

```{r, echo=FALSE}
dataset_vignette(
  adrs,
  display_vars = exprs(USUBJID, AVISIT, PARAMCD, PARAM, AVALC, ADT, ANL01FL),
  filter = PARAMCD == "PD"
)
```

For progressive disease, response and death parameters 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 `PD` as a variable, rather than as a new parameter record.

## Derive Response Parameter {#rsp}

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 `CR` or `PR` via the `rsp_y`[^1] event.

[^1]:
```{r}
rsp_y
```

```{r}
adrs <- adrs %>%
  derive_extreme_event(
    by_vars = exprs(STUDYID, USUBJID),
    order = exprs(event_nr, ADT),
    tmp_event_nr_var = event_nr,
    mode = "first",
    events = list(rsp_y, no_data_n),
    source_datasets = list(
      ovr = ovr,
      adsl = adsl
    ),
    set_values_to = exprs(
      PARAMCD = "RSP",
      PARAM = "Response by Investigator (confirmation not required)",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "RECIST 1.1",
      AVAL = yn_to_numeric(AVALC),
      ANL01FL = "Y"
    )
  )
```

```{r, echo=FALSE}
dataset_vignette(
  adrs,
  display_vars = exprs(USUBJID, AVISIT, PARAMCD, PARAM, AVALC, ADT, ANL01FL),
  filter = PARAMCD == "RSP"
)
```

## Derive Clinical Benefit Parameter {#cb}

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 `PD`. 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 `cb_y`[^2] event.

[^2]:
```{r}
cb_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 = TRUE` is specified.

```{r}
adrs <- adrs %>%
  derive_extreme_event(
    by_vars = exprs(STUDYID, USUBJID),
    order = exprs(desc(AVALC), ADT, event_nr),
    tmp_event_nr_var = event_nr,
    mode = "first",
    events = list(rsp_y, cb_y, no_data_n),
    source_datasets = list(
      ovr = ovr,
      adsl = adsl
    ),
    set_values_to = exprs(
      PARAMCD = "CB",
      PARAM = "Clinical Benefit by Investigator (confirmation for response not required)",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "RECIST 1.1",
      AVAL = yn_to_numeric(AVALC),
      ANL01FL = "Y"
    )
  )
```

```{r, echo=FALSE}
dataset_vignette(
  adrs,
  display_vars = exprs(USUBJID, AVISIT, PARAMCD, PARAM, AVALC, ADT, RANDDT, ANL01FL),
  filter = PARAMCD == "CB"
)
```

## Derive Best Overall Response Parameter {#bor}

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 a `SD` or
`NON-CR/NON-PD` 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 `PR`, `PR`, `CR` qualifies for both `bor_cr` and
`bor_pr`. As `bor_cr` is listed before `bor_pr`, CR is selected as best overall
response for this subject.

```{r}
adrs <- adrs %>%
  derive_extreme_event(
    by_vars = exprs(STUDYID, USUBJID),
    order = exprs(event_nr, ADT),
    tmp_event_nr_var = event_nr,
    mode = "first",
    source_datasets = list(
      ovr = ovr,
      adsl = adsl
    ),
    events = list(bor_cr, bor_pr, bor_sd, bor_non_crpd, bor_pd, bor_ne, no_data_missing),
    set_values_to = exprs(
      PARAMCD = "BOR",
      PARAM = "Best Overall Response by Investigator (confirmation not required)",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "RECIST 1.1",
      AVAL = aval_resp(AVALC),
      ANL01FL = "Y"
    )
  )
```

```{r, echo=FALSE}
dataset_vignette(
  adrs,
  display_vars = exprs(USUBJID, AVISIT, PARAMCD, PARAM, AVALC, ADT, RANDDT, ANL01FL),
  filter = PARAMCD == "BOR"
)
```

Note that the above gives pre-defined `AVAL` values (defined by `aval_resp()`)
of: `"CR" ~ 1`, `"PR" ~ 2`, `"SD" ~ 3`, `"NON-CR/NON-PD" ~ 4`, `"PD" ~ 5`, `"NE"
~ 6`, `"MISSING" ~ 7`.

If you'd like to provide your own company-specific ordering here you
could do this as follows:

```{r, eval=FALSE}
aval_resp_new <- function(arg) {
  case_when(
    arg == "CR" ~ 7,
    arg == "PR" ~ 6,
    arg == "SD" ~ 5,
    arg == "NON-CR/NON-PD" ~ 4,
    arg == "PD" ~ 3,
    arg == "NE" ~ 2,
    arg == "MISSING" ~ 1,
    TRUE ~ NA_real_
  )
}
```

Then update the definition of `AVAL` in the `set_values_to` argument of the
above `admiral::derive_extreme_event()` call. Be aware that this will only impact
the `AVAL` mapping, not the derivation of BOR in any way - as the function
derivation relies only on the events and their order specified for the `events`
argument here.

## Derive Best Overall Response of CR/PR Parameter {#bcp}

The function `admiral::derive_extreme_records()` can be used to check if a
patient had a response for BOR.

```{r}
adrs <- adrs %>%
  derive_extreme_records(
    dataset_ref = adsl,
    dataset_add = adrs,
    by_vars = exprs(STUDYID, USUBJID),
    filter_add = PARAMCD == "BOR" & AVALC %in% c("CR", "PR"),
    exist_flag = AVALC,
    false_value = "N",
    set_values_to = exprs(
      PARAMCD = "BCP",
      PARAM = "Best Overall Response of CR/PR by Investigator (confirmation not required)",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "RECIST 1.1",
      AVAL = yn_to_numeric(AVALC),
      ANL01FL = "Y"
    )
  )
```

```{r, echo=FALSE}
dataset_vignette(
  adrs,
  display_vars = exprs(USUBJID, AVISIT, PARAMCD, PARAM, AVALC, ADT, ANL01FL),
  filter = PARAMCD == "BCP"
)
```

## Derive Response Parameters requiring Confirmation {#confirm}

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 `crsp_y_cr`[^3],
`crsp_y_pr`[^4], `cbor_cr`[^5], and `cbor_pr`[^6] event.

[^3]:
```{r}
crsp_y_cr
```
[^4]:
```{r}
crsp_y_pr
```
[^5]:
```{r}
cbor_cr
```
[^6]:
```{r}
cbor_pr
```

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). Thus `ignore_event_order = TRUE`
is specified.

```{r}
adrs <- adrs %>%
  derive_extreme_event(
    by_vars = exprs(STUDYID, USUBJID),
    order = exprs(desc(AVALC), ADT, event_nr),
    tmp_event_nr_var = event_nr,
    mode = "first",
    source_datasets = list(
      ovr = ovr,
      adsl = adsl
    ),
    events = list(crsp_y_cr, crsp_y_pr, no_data_n),
    set_values_to = exprs(
      PARAMCD = "CRSP",
      PARAM = "Confirmed Response by Investigator",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "RECIST 1.1",
      AVAL = yn_to_numeric(AVALC),
      ANL01FL = "Y"
    )
  )

adrs <- adrs %>%
  derive_extreme_event(
    by_vars = exprs(STUDYID, USUBJID),
    order = exprs(desc(AVALC), ADT, event_nr),
    tmp_event_nr_var = event_nr,
    mode = "first",
    events = list(crsp_y_cr, crsp_y_pr, cb_y, no_data_n),
    source_datasets = list(
      ovr = ovr,
      adsl = adsl
    ),
    set_values_to = exprs(
      PARAMCD = "CCB",
      PARAM = "Confirmed Clinical Benefit by Investigator",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "RECIST 1.1",
      AVAL = yn_to_numeric(AVALC),
      ANL01FL = "Y"
    )
  )

adrs <- adrs %>%
  derive_extreme_event(
    by_vars = exprs(STUDYID, USUBJID),
    order = exprs(event_nr, ADT),
    tmp_event_nr_var = event_nr,
    mode = "first",
    events = list(cbor_cr, cbor_pr, bor_sd, bor_non_crpd, bor_pd, bor_ne, no_data_missing),
    source_datasets = list(
      ovr = ovr,
      adsl = adsl
    ),
    set_values_to = exprs(
      PARAMCD = "CBOR",
      PARAM = "Best Confirmed Overall Response by Investigator",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "RECIST 1.1",
      AVAL = aval_resp(AVALC),
      ANL01FL = "Y"
    )
  ) %>%
  derive_extreme_records(
    dataset_ref = adsl,
    dataset_add = adrs,
    by_vars = exprs(STUDYID, USUBJID),
    filter_add = PARAMCD == "CBOR" & AVALC %in% c("CR", "PR"),
    exist_flag = AVALC,
    false_value = "N",
    set_values_to = exprs(
      PARAMCD = "CBCP",
      PARAM = "Best Confirmed Overall Response of CR/PR by Investigator",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "RECIST 1.1",
      AVAL = yn_to_numeric(AVALC),
      ANL01FL = "Y"
    )
  )
```

```{r, echo=FALSE}
dataset_vignette(
  adrs,
  display_vars = exprs(USUBJID, AVISIT, PARAMCD, PARAM, AVALC, ADT, RANDDT, ANL01FL),
  filter = PARAMCD %in% c("CRSP", "CCB", "CBOR", "CBCP")
)
```

## Derive Non-standard Parameters {#nonstandard}

As `admiral::derive_extreme_event()` is very flexible, it is easy to implement
non-standard parameters. Below two examples for modified RECIST 1.1 parameters
are shown.

### Adding a Criterion for Confirmed Clinical Benefit
Confirmed clinical benefit was defined before as confirmed response or CR, PR,
SD, or NON-CR/NON-PD at least 42 days after randomization. Here an alternative
definition is implemented which considers PD more than 42 days after
randomization as an additional criterion for clinical benefit.
```{r}
cb_y_pd <- event(
  description = paste(
    "Define PD occuring more than 42 days after",
    "randomization as clinical benefit"
  ),
  dataset_name = "ovr",
  condition = AVALC == "PD" & ADT > RANDDT + 42,
  set_values_to = exprs(AVALC = "Y")
)

adrs <- adrs %>%
  derive_extreme_event(
    by_vars = exprs(STUDYID, USUBJID),
    order = exprs(desc(AVALC), ADT, event_nr),
    tmp_event_nr_var = event_nr,
    mode = "first",
    events = list(crsp_y_cr, crsp_y_pr, cb_y, cb_y_pd, no_data_n),
    source_datasets = list(
      ovr = ovr,
      adsl = adsl
    ),
    set_values_to = exprs(
      PARAMCD = "ACCB",
      PARAM = "Alternative Confirmed Clinical Benefit by Investigator",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "RECIST 1.1",
      AVAL = yn_to_numeric(AVALC),
      ANL01FL = "Y"
    )
  )
```

### Considering Non-Standard Response Values

Assume no evidence of disease (NED) is a valid value collected for overall
response. A new event (`bor_ned`) can be defined for this response value and be
added to the list of events (`events`) in the `admiral::derive_extreme_event()`
call.

```{r}
bor_ned <- event(
  description = paste(
    "Define no evidence of disease (NED) for best overall response (BOR) as NED",
    "occuring at least 42 days after randomization"
  ),
  dataset_name = "ovr",
  condition = AVALC == "NED" & ADT >= RANDDT + 42,
  set_values_to = exprs(AVALC = "NED")
)

adrs <- adrs %>%
  derive_extreme_event(
    by_vars = exprs(STUDYID, USUBJID),
    order = exprs(event_nr, ADT),
    tmp_event_nr_var = event_nr,
    mode = "first",
    source_datasets = list(
      ovr = ovr,
      adsl = adsl
    ),
    events = list(bor_cr, bor_pr, bor_sd, bor_non_crpd, bor_ned, bor_pd, bor_ne, no_data_missing),
    set_values_to = exprs(
      PARAMCD = "A1BOR",
      PARAM = paste(
        "Best Overall Response by Investigator (confirmation not required)",
        "- RECIST 1.1 adjusted for NED at Baseline"
      ),
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "RECIST 1.1 adjusted for NED at Baseline",
      AVAL = aval_resp(AVALC),
      ANL01FL = "Y"
    )
  )
```

## Derive Parameters using Independent Review Facility (IRF)/Blinded Independent Central Review (BICR) responses {#irf}

All of the above steps can be repeated for different sets of records, such as
now using assessments from the IRF/BICR instead of investigator. For this you
would just need to replace the first steps with selecting the required records,
create the variables `AVALC`, `AVAL`, `ADT`, `AVISIT`, `ANL01FL`, `ANL02FL` and
the dataset `ovrb` (see [Pre-processing of Input Records](#input)) and then feed
these as input to the downstream parameter functions.

```{r}
adrs_bicr <- rs %>%
  filter(
    RSEVAL == "INDEPENDENT ASSESSOR" & RSACPTFL == "Y" & RSTESTCD == "OVRLRESP"
  ) %>%
  mutate(
    PARAMCD = "OVRB",
    PARAM = "Overall Response by BICR",
    PARCAT1 = "Tumor Response",
    PARCAT2 = "Blinded Independent Central Review",
    PARCAT3 = "RECIST 1.1"
  )
```

```{r, echo=FALSE}
dataset_vignette(
  adrs_bicr,
  display_vars = exprs(USUBJID, VISIT, RSTESTCD, RSEVAL, PARAMCD, PARAM, PARCAT1, PARCAT2, PARCAT3),
  filter = PARAMCD == "OVRB"
)
```

Then in all the calls to the parameter derivation functions you would replace
`ovr = ovr` with `ovr == ovrb` in the value of the `source_datasets` argument.

## Derive Death Parameter {#death}

The function `admiral::derive_extreme_records()` can be used to create
a new death parameter using death date from `ADSL`. We need to restrict
the columns from `ADSL` as we'll merge all required variables later
across all our `ADRS` records.

```{r}
adsldth <- adsl %>%
  select(STUDYID, USUBJID, DTHDT, !!!adsl_vars)

adrs <- adrs %>%
  derive_extreme_records(
    dataset_ref = adsldth,
    dataset_add = adsldth,
    by_vars = exprs(STUDYID, USUBJID),
    filter_add = !is.na(DTHDT),
    exist_flag = AVALC,
    false_value = "N",
    set_values_to = exprs(
      PARAMCD = "DEATH",
      PARAM = "Death",
      PARCAT1 = "Reference Event",
      AVAL = yn_to_numeric(AVALC),
      ANL01FL = "Y",
      ADT = DTHDT
    )
  ) %>%
  select(-DTHDT)
```

```{r, echo=FALSE}
dataset_vignette(
  adrs,
  display_vars = exprs(USUBJID, AVISIT, PARAMCD, PARAM, AVALC, ADT, ANL01FL),
  filter = PARAMCD == "DEATH"
)
```

## Derive Last Disease Assessment Parameters {#lsta}

The function `admiral::derive_extreme_records()` can be used to create a
parameter for last disease assessment.

```{r}
adrs <- adrs %>%
  derive_extreme_records(
    dataset_ref = adsl,
    dataset_add = adrs,
    by_vars = exprs(STUDYID, USUBJID),
    filter_add = PARAMCD == "OVR" & ANL01FL == "Y",
    order = exprs(ADT, RSSEQ),
    mode = "last",
    set_values_to = exprs(
      PARAMCD = "LSTA",
      PARAM = "Last Disease Assessment by Investigator",
      PARCAT1 = "Tumor Response",
      PARCAT2 = "Investigator",
      PARCAT3 = "RECIST 1.1",
      ANL01FL = "Y"
    )
  )
```

```{r, echo=FALSE}
dataset_vignette(
  adrs,
  display_vars = exprs(USUBJID, AVISIT, PARAMCD, PARAM, AVALC, ADT, ANL01FL),
  filter = PARAMCD == "LSTA"
)
```

## Derive Measurable Disease at Baseline Parameter {#mdis}

The function `admiral::derive_param_exist_flag()` can be used to check
whether a patient has measurable disease at baseline, according to a
company-specific condition. In this example we check `TU` for target
lesions during the baseline visit. We need to restrict the columns from
`ADSL` as we'll merge all required variables later across all our `ADRS`
records.

```{r}
adslmdis <- adsl %>%
  select(STUDYID, USUBJID, !!!adsl_vars)

adrs <- adrs %>%
  derive_param_exist_flag(
    dataset_ref = adslmdis,
    dataset_add = tu,
    condition = TUEVAL == "INVESTIGATOR" & TUSTRESC == "TARGET" & VISIT == "SCREENING",
    false_value = "N",
    missing_value = "N",
    set_values_to = exprs(
      PARAMCD = "MDIS",
      PARAM = "Measurable Disease at Baseline by Investigator",
      PARCAT2 = "Investigator",
      PARCAT3 = "RECIST 1.1",
      AVAL = yn_to_numeric(AVALC),
      ANL01FL = "Y"
    )
  )
```

```{r, echo=FALSE}
dataset_vignette(
  adrs,
  display_vars = exprs(USUBJID, AVISIT, PARAMCD, PARAM, AVALC, ADT, ANL01FL),
  filter = PARAMCD == "MDIS"
)
```

## Assign `ASEQ` {#aseq}

The function `admiral::derive_var_obs_number()` can be used to derive
`ASEQ`. An example call is:

```{r eval=TRUE}
adrs <- adrs %>%
  derive_var_obs_number(
    by_vars = exprs(STUDYID, USUBJID),
    order = exprs(PARAMCD, ADT, VISITNUM, RSSEQ),
    check_type = "error"
  )
```

```{r, eval=TRUE, echo=FALSE}
dataset_vignette(
  adrs,
  display_vars = exprs(USUBJID, PARAMCD, ADT, VISITNUM, AVISIT, ASEQ),
  filter = USUBJID == "01-701-1015"
)
```

## Add ADSL variables {#adsl_vars}

If needed, the other `ADSL` variables can now be added. List of ADSL
variables already merged held in vector `adsl_vars`.

```{r eval=TRUE}
adrs <- adrs %>%
  derive_vars_merged(
    dataset_add = select(adsl, !!!negate_vars(adsl_vars)),
    by_vars = exprs(STUDYID, USUBJID)
  )
```

```{r, eval=TRUE, echo=FALSE}
dataset_vignette(
  adrs,
  display_vars = exprs(USUBJID, RFSTDTC, RFENDTC, DTHDTC, DTHFL, AGE, AGEU),
  filter = USUBJID == "01-701-1015"
)
```

# Example Script {#example}

ADaM | Sample Code
---- | --------------
ADRS | `admiral::use_ad_template("ADRS", package = "admiralonco")`
