This article describes creating an ADTTE (time-to-event)
ADaM with common oncology endpoint parameters.
The main part in programming a time-to-event dataset is the
definition of the events and censoring times.
{admiral}/{admiralonco} supports single events
like death (Overall Survival) or composite events like disease
progression or death (Progression Free Survival). More than one source
dataset can be used for the definition of the event and censoring
times.
The majority of the functions used here exist from
{admiral}, except for the tte_sources helper
object, provided as an example from {admiralonco}. In
practice, each company would create their own version of this, as likely
the exact specifications such as filtering condition or description
metadata will vary.
Note: All examples assume CDISC SDTM and/or ADaM format as input unless otherwise specified.
CNSR,
ADT, STARTDT)AVAL)ASEQ)To start, all datasets needed for the creation of the time-to-event dataset should be read into the environment. This will be a company specific process.
For example purpose, the ADaM datasets—which are included in
{pharmaverseadam}—are used. An alternative might be to use
ADEVENT as input1.
CNSR, ADT,
STARTDT)To derive the parameter dependent variables like CNSR,
ADT, STARTDT, EVNTDESC,
SRCDOM, PARAMCD, … the
admiral::derive_param_tte() function can be used. It adds
one parameter to the input dataset with one observation per subject.
Usually it is called several times.
For each subject it is determined if an event occurred. In the
affirmative the analysis date ADT is set to the earliest
event date. If no event occurred, the analysis date is set to the latest
censoring date.
The events and censorings are defined by the
admiral::event_source() and the
admiral::censor_source() class respectively. It defines
filter parameter) of a source
dataset (dataset_name parameter) are potential events or
censorings,CNSR variable (censor
parameter), anddate parameter).The date can be provided as a date (*DT variable) or a
datetime (*DTM variable).
CDISC strongly recommends CNSR = 0 for events and
positive integers for censorings.
{admiral}/{admiralonco} enforce this
recommendation. Therefore the censor parameter is available
for admiral::censor_source() only. It is defaulted to
1.
The dataset_name parameter expects a character value
which is used as an identifier. The actual data which is used for the
derivation of the parameter is provided via the
source_datasets parameter of
admiral::derive_param_tte(). It expects a named list of
datasets. The names correspond to the identifiers specified for the
dataset_name parameter. This allows to define events and
censoring independent of the data.
The table below shows all pre-defined tte_source objects
which should cover the most common oncology use cases.
| object | dataset_name | filter | date | censor | set_values_to |
|---|---|---|---|---|---|
| lastalive_censor | adsl | NULL | LSTALVDT | 1 | EVNTDESC: “Alive” CNSDTDSC: “Alive During Study” SRCDOM: “ADSL” SRCVAR: “LSTALVDT” |
| trts_censor | adsl | NULL | TRTSDT | 1 | EVNTDESC: “Treatment Start” CNSDTDSC: “Treatment Start” SRCDOM: “ADSL” SRCVAR: “TRTSDT” |
| pd_event | adrs | PARAMCD == “PD” & AVALC == “Y” & ANL01FL == “Y” | ADT | 0 | EVNTDESC: “Disease Progression” SRCDOM: “ADRS” SRCVAR: “ADT” SRCSEQ: ASEQ |
| death_event | adrs | PARAMCD == “DEATH” & AVALC == “Y” & ANL01FL == “Y” | ADT | 0 | EVNTDESC: “Death” SRCDOM: “ADRS” SRCVAR: “ADT” SRCSEQ: ASEQ |
| lasta_censor | adrs | PARAMCD == “LSTA” & ANL01FL == “Y” | ADT | 1 | EVNTDESC: “Last Tumor Assessment” CNSDTDSC: “Last Tumor Assessment” SRCDOM: “ADRS” SRCVAR: “ADT” SRCSEQ: ASEQ |
| rand_censor | adsl | NULL | RANDDT | 1 | EVNTDESC: “Randomization” CNSDTDSC: “Randomization” SRCDOM: “ADSL” SRCVAR: “RANDDT” |
As mentioned in the introduction, each company would create their own
version of this with the required filtering conditions and metadata as
per your company approach. An example of a possible different approach
could be as follows, where death is sourced from ADSL,
instead of ADRS, and the given EVNTDESC is
different.
adsl_death_event <- event_source(
dataset_name = "adsl",
date = DTHDT,
set_values_to = exprs(
EVNTDESC = "STUDY DEATH",
SRCDOM = "ADSL",
SRCVAR = "DTHDT"
)
)An optional step at this stage would be required to enable derivation
of duration of response: If using ADRS /
ADEVENT parameters as input for any response dates (instead
of a variable in ADSL) then you would need to use
admiral::derive_vars_merged() to add the response date as a
temporary variable (e.g. TEMP_RESPDT) to be able to feed
into admiral::derive_param_tte() as the start date. You
would also need to use this to filter the source ADSL
dataset so as to only derive the records for responders. This could also
be repeated as needed for IRF/BICR and confirmed responses.
Here is an example of the code needed.
adsl <- adsl %>%
derive_vars_merged(
dataset_add = adrs,
filter_add = PARAMCD == "RSP" & AVALC == "Y" & ANL01FL == "Y",
by_vars = get_admiral_option("subject_keys"),
new_vars = exprs(TEMP_RESPDT = ADT)
)| USUBJID | RANDDT | TEMP_RESPDT | NACTDT | EOSDT |
|---|---|---|---|---|
| 01-701-1015 | 2014-01-02 | 2014-03-06 | 2014-06-19 | 2014-07-02 |
| 01-701-1028 | 2013-07-19 | NA | 2014-01-14 | 2014-01-14 |
| 01-701-1034 | 2014-07-01 | NA | 2014-12-30 | 2014-12-30 |
| 01-701-1097 | 2014-01-01 | NA | 2013-12-31 | 2014-07-09 |
| 01-701-1115 | 2012-11-30 | 2013-01-11 | NA | 2013-01-23 |
| 01-701-1118 | 2014-03-12 | 2014-04-23 | NA | 2014-09-09 |
| 01-701-1130 | 2014-02-15 | NA | NA | 2014-08-16 |
| 01-701-1133 | 2012-10-28 | 2012-11-18 | NA | 2013-04-29 |
| 01-701-1146 | 2013-05-20 | NA | NA | 2013-06-30 |
| 01-701-1211 | 2012-11-15 | NA | NA | 2013-01-14 |
The pre-defined objects can be passed directly to
admiral::derive_param_tte() to create a new time-to-event
parameter. Below shows example calls for Overall Survival (OS),
Progression Free Survival (PFS), and duration of response (as above,
this is only derived for responder patients so we have to filter source
ADSL dataset). Note that the reason for including a
randomization date censor is to catch those patients that never have a
tumor assessment.
adtte <- derive_param_tte(
dataset_adsl = adsl,
start_date = RANDDT,
event_conditions = list(death_event),
censor_conditions = list(lastalive_censor, rand_censor),
source_datasets = list(adsl = adsl, adrs = adrs),
set_values_to = exprs(PARAMCD = "OS", PARAM = "Overall Survival")
) %>%
derive_param_tte(
dataset_adsl = adsl,
start_date = RANDDT,
event_conditions = list(pd_event, death_event),
censor_conditions = list(lasta_censor, rand_censor),
source_datasets = list(adsl = adsl, adrs = adrs),
set_values_to = exprs(PARAMCD = "PFS", PARAM = "Progression Free Survival")
) %>%
derive_param_tte(
dataset_adsl = filter(adsl, !is.na(TEMP_RESPDT)),
start_date = TEMP_RESPDT,
event_conditions = list(pd_event, death_event),
censor_conditions = list(lasta_censor),
source_datasets = list(adsl = adsl, adrs = adrs),
set_values_to = exprs(PARAMCD = "RSD", PARAM = "Duration of Response")
)| USUBJID | PARAMCD | PARAM | STARTDT | ADT | CNSR |
|---|---|---|---|---|---|
| 01-701-1015 | OS | Overall Survival | 2014-01-02 | 2014-07-02 | 1 |
| 01-701-1028 | OS | Overall Survival | 2013-07-19 | 2014-01-14 | 1 |
| 01-701-1034 | OS | Overall Survival | 2014-07-01 | 2014-12-30 | 1 |
| 01-701-1097 | OS | Overall Survival | 2014-01-01 | 2014-07-09 | 1 |
| 01-701-1115 | OS | Overall Survival | 2012-11-30 | 2013-01-23 | 1 |
| 01-701-1118 | OS | Overall Survival | 2014-03-12 | 2014-09-09 | 1 |
| 01-701-1130 | OS | Overall Survival | 2014-02-15 | 2014-08-16 | 1 |
| 01-701-1133 | OS | Overall Survival | 2012-10-28 | 2013-04-29 | 1 |
| 01-701-1146 | OS | Overall Survival | 2013-05-20 | 2013-06-30 | 1 |
| 01-701-1211 | OS | Overall Survival | 2012-11-15 | 2013-01-14 | 0 |
We advise you to consult the {admiral} Creating
a BDS Time-to-Event ADaM vignette and Time-to-Event
Analyses for further guidance on the different options available and
more examples.
One additional common oncology use case described here involves PFS
when censoring at new anti-cancer therapy. This can be controlled either
by using ANLzzFL as explained in the ADRS vignette, so that
records after new anti-cancer therapy never contribute to the PD and
DEATH parameters, or by using the end_dates argument of
derive_param_tte() on the ADTTE side.
For end_dates, you can specify whichever date your
analysis requires, e.g., the start date of new anti-cancer therapy or
the date of surgery. The argument expects a list of
censor_source() objects. The earliest date is used as the
end of the observation period, and events or censorings occurring after
this date are not considered. If the end_dates argument is
used, “Overall Response by Investigator” parameter (OVR)
should be used instead of the “Last Disease Assessment by Investigator”
parameter (LSTA) to ensure all valid assessments are
considered.
In the example below, the end_dates argument is used to
restrict the events and censorings to those occurring on or before the
start of new anti-cancer therapy. NACTDT would be
pre-derived as the first date of new anti-cancer therapy. See
{admiralonco} Creating and Using New
Anti-Cancer Start Date for deriving NACTDT. In
addition, EOSDT is included in end_dates to
populate EVNTDESC when no new anti-cancer therapy was
started. For censored subjects, EVNTDESC will be set to
"Start of New Anti-Cancer Therapy" if the subject started
new anti-cancer therapy and set to "End of Study"
otherwise.
eosdt <- censor_source(
dataset_name = "adsl",
date = EOSDT,
set_values_to = exprs(
EVNTDESC = "End of Study"
)
)
nactdt <- censor_source(
dataset_name = "adsl",
date = NACTDT,
set_values_to = exprs(
EVNTDESC = "Start of New Anti-Cancer Therapy"
)
)
valid_assessment <- censor_source(
dataset_name = "adrs",
filter = PARAMCD == "OVR" & AVALC != "NE",
date = ADT,
set_values_to = exprs(
CNSDTDSC = "Last Valid Tumor Assessment",
SRCDOM = "ADRS",
SRCVAR = "ADT"
)
)
adtte <- adtte %>% derive_param_tte(
dataset_adsl = adsl,
start_date = RANDDT,
end_dates = list(nactdt, eosdt),
event_conditions = list(pd_event, death_event),
censor_conditions = list(valid_assessment, rand_censor),
source_datasets = list(adsl = adsl, adrs = adrs),
set_values_to = exprs(
PARAMCD = "PFSNACT",
PARAM = "Progression Free Survival prior to NACT"
)
)| USUBJID | PARAMCD | PARAM | STARTDT | ADT | CNSR | EVNTDESC | CNSDTDSC |
|---|---|---|---|---|---|---|---|
| 01-701-1015 | PFSNACT | Progression Free Survival prior to NACT | 2014-01-02 | 2014-03-06 | 1 | Start of New Anti-Cancer Therapy | Last Valid Tumor Assessment |
| 01-701-1028 | PFSNACT | Progression Free Survival prior to NACT | 2013-07-19 | 2013-08-30 | 0 | Disease Progression | NA |
| 01-701-1034 | PFSNACT | Progression Free Survival prior to NACT | 2014-07-01 | 2014-08-12 | 1 | Start of New Anti-Cancer Therapy | Last Valid Tumor Assessment |
| 01-701-1097 | PFSNACT | Progression Free Survival prior to NACT | 2014-01-01 | 2014-01-01 | 1 | Randomization | Randomization |
| 01-701-1115 | PFSNACT | Progression Free Survival prior to NACT | 2012-11-30 | 2013-01-11 | 1 | End of Study | Last Valid Tumor Assessment |
| 01-701-1118 | PFSNACT | Progression Free Survival prior to NACT | 2014-03-12 | 2014-06-04 | 1 | End of Study | Last Valid Tumor Assessment |
| 01-701-1130 | PFSNACT | Progression Free Survival prior to NACT | 2014-02-15 | 2014-04-19 | 0 | Disease Progression | NA |
| 01-701-1133 | PFSNACT | Progression Free Survival prior to NACT | 2012-10-28 | 2012-12-30 | 0 | Disease Progression | NA |
| 01-701-1146 | PFSNACT | Progression Free Survival prior to NACT | 2013-05-20 | 2013-05-20 | 1 | Randomization | Randomization |
| 01-701-1211 | PFSNACT | Progression Free Survival prior to NACT | 2012-11-15 | 2013-01-14 | 0 | Death | NA |
AVAL)The analysis value (AVAL) can be derived by calling
admiral::derive_vars_duration().
This example derives the time to event in days.
| STUDYID | USUBJID | ADT | EVNTDESC | SRCDOM | SRCVAR | SRCSEQ | CNSR | CNSDTDSC | STARTDT | PARAMCD | PARAM | AVAL |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| CDISCPILOT01 | 01-701-1015 | 2014-07-02 | Alive | ADSL | LSTALVDT | NA | 1 | Alive During Study | 2014-01-02 | OS | Overall Survival | 182 |
| CDISCPILOT01 | 01-701-1028 | 2014-01-14 | Alive | ADSL | LSTALVDT | NA | 1 | Alive During Study | 2013-07-19 | OS | Overall Survival | 180 |
| CDISCPILOT01 | 01-701-1034 | 2014-12-30 | Alive | ADSL | LSTALVDT | NA | 1 | Alive During Study | 2014-07-01 | OS | Overall Survival | 183 |
| CDISCPILOT01 | 01-701-1097 | 2014-07-09 | Alive | ADSL | LSTALVDT | NA | 1 | Alive During Study | 2014-01-01 | OS | Overall Survival | 190 |
| CDISCPILOT01 | 01-701-1115 | 2013-01-23 | Alive | ADSL | LSTALVDT | NA | 1 | Alive During Study | 2012-11-30 | OS | Overall Survival | 55 |
| CDISCPILOT01 | 01-701-1118 | 2014-09-09 | Alive | ADSL | LSTALVDT | NA | 1 | Alive During Study | 2014-03-12 | OS | Overall Survival | 182 |
| CDISCPILOT01 | 01-701-1130 | 2014-08-16 | Alive | ADSL | LSTALVDT | NA | 1 | Alive During Study | 2014-02-15 | OS | Overall Survival | 183 |
| CDISCPILOT01 | 01-701-1133 | 2013-04-29 | Alive | ADSL | LSTALVDT | NA | 1 | Alive During Study | 2012-10-28 | OS | Overall Survival | 184 |
| CDISCPILOT01 | 01-701-1146 | 2013-06-30 | Alive | ADSL | LSTALVDT | NA | 1 | Alive During Study | 2013-05-20 | OS | Overall Survival | 42 |
| CDISCPILOT01 | 01-701-1211 | 2013-01-14 | Death | ADRS | ADT | 8 | 0 | NA | 2012-11-15 | OS | Overall Survival | 61 |
Other time units, such as months that we commonly see in oncology
analyses, can be requested by specifying the out_unit
parameter. See the example below. Note that because of the underlying
lubridate::time_length() function that is used here this
may perform slightly differently to your expectations, e.g. both
time_length(ymd("2021-01-01") %--% ymd("2021-02-01"), "month")
and
time_length(ymd("2021-02-01") %--% ymd("2021-03-01"), "month")
results in exactly 1 month, which is a logical approach but it gives a
different result to the convention of assuming every month has exactly
equal days and just using /30.4375 here or some other such
convention. The difference would only be noticed for small durations,
but if the user prefers an alternative approach they could calculate in
the default days and then add extra processing to convert to months with
their company-specific convention.
ASEQ)The {admiral} function
admiral::derive_var_obs_number() can be used to derive
ASEQ:
adtte <- adtte %>%
derive_var_obs_number(
by_vars = get_admiral_option("subject_keys"),
order = exprs(PARAMCD),
check_type = "error"
)| STUDYID | USUBJID | ADT | EVNTDESC | SRCDOM | SRCVAR | SRCSEQ | CNSR | CNSDTDSC | STARTDT | PARAMCD | PARAM | AVAL | ASEQ |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| CDISCPILOT01 | 01-701-1015 | 2014-07-02 | Alive | ADSL | LSTALVDT | NA | 1 | Alive During Study | 2014-01-02 | OS | Overall Survival | 182 | 1 |
| CDISCPILOT01 | 01-701-1015 | 2014-03-06 | Last Tumor Assessment | ADRS | ADT | 9 | 1 | Last Tumor Assessment | 2014-01-02 | PFS | Progression Free Survival | 64 | 2 |
| CDISCPILOT01 | 01-701-1015 | 2014-03-06 | Start of New Anti-Cancer Therapy | ADRS | ADT | NA | 1 | Last Valid Tumor Assessment | 2014-01-02 | PFSNACT | Progression Free Survival prior to NACT | 64 | 3 |
| CDISCPILOT01 | 01-701-1015 | 2014-03-06 | Last Tumor Assessment | ADRS | ADT | 9 | 1 | Last Tumor Assessment | 2014-03-06 | RSD | Duration of Response | 1 | 4 |
| CDISCPILOT01 | 01-701-1028 | 2014-01-14 | Alive | ADSL | LSTALVDT | NA | 1 | Alive During Study | 2013-07-19 | OS | Overall Survival | 180 | 1 |
| CDISCPILOT01 | 01-701-1028 | 2013-08-30 | Disease Progression | ADRS | ADT | 14 | 0 | NA | 2013-07-19 | PFS | Progression Free Survival | 43 | 2 |
| CDISCPILOT01 | 01-701-1028 | 2013-08-30 | Disease Progression | ADRS | ADT | 14 | 0 | NA | 2013-07-19 | PFSNACT | Progression Free Survival prior to NACT | 43 | 3 |
| CDISCPILOT01 | 01-701-1034 | 2014-12-30 | Alive | ADSL | LSTALVDT | NA | 1 | Alive During Study | 2014-07-01 | OS | Overall Survival | 183 | 1 |
| CDISCPILOT01 | 01-701-1034 | 2014-08-12 | Last Tumor Assessment | ADRS | ADT | 9 | 1 | Last Tumor Assessment | 2014-07-01 | PFS | Progression Free Survival | 43 | 2 |
| CDISCPILOT01 | 01-701-1034 | 2014-08-12 | Start of New Anti-Cancer Therapy | ADRS | ADT | NA | 1 | Last Valid Tumor Assessment | 2014-07-01 | PFSNACT | Progression Free Survival prior to NACT | 43 | 3 |
Variables from ADSL which are required for time-to-event analyses,
e.g., treatment variables or covariates can be added using
admiral::derive_vars_merged().
adtte <- adtte %>%
derive_vars_merged(
dataset_add = adsl,
new_vars = exprs(ARMCD, ARM, ACTARMCD, ACTARM, AGE, SEX),
by_vars = get_admiral_option("subject_keys")
)| USUBJID | PARAMCD | CNSR | AVAL | ARMCD | AGE | SEX |
|---|---|---|---|---|---|---|
| 01-701-1015 | OS | 1 | 182 | Pbo | 63 | F |
| 01-701-1015 | PFS | 1 | 64 | Pbo | 63 | F |
| 01-701-1015 | PFSNACT | 1 | 64 | Pbo | 63 | F |
| 01-701-1015 | RSD | 1 | 1 | Pbo | 63 | F |
| 01-701-1028 | OS | 1 | 180 | Xan_Hi | 71 | M |
| 01-701-1028 | PFS | 0 | 43 | Xan_Hi | 71 | M |
| 01-701-1028 | PFSNACT | 0 | 43 | Xan_Hi | 71 | M |
| 01-701-1034 | OS | 1 | 183 | Xan_Hi | 77 | F |
| 01-701-1034 | PFS | 1 | 43 | Xan_Hi | 77 | F |
| 01-701-1034 | PFSNACT | 1 | 43 | Xan_Hi | 77 | F |
| ADaM | Sample Code |
|---|---|
ADTTE |
admiral::use_ad_template("ADTTE", package = "admiralonco") |
The subjects are restricted to
"01-701-1015", "01-701-1028",
"01-701-1034", "01-701-1097",
"01-701-1115", "01-701-1118",
"01-701-1130", "01-701-1133",
"01-701-1146", "01-701-1211".↩︎