Introduction
The basic concept of preparing data for time-to-event analyses is quite simple:
- we need to know whether the event occurred or not
- if it did, the first time when it occurred is set as the event time
- if it did not, the last time when it is known that the subject didn’t have an event is set as the censoring time.
Depending on the definition of the event and the collection of the
data, the creation of a time-to-event ADaM dataset can be more or less
complex. In this vignette, we will discuss different scenarios and how
to derive the essential variables CNSR and
ADT. For a complete programming workflow see the Creating a BDS Time-to-Event ADaM vignette.
Observation Period
The observation period is the time during which the subjects are at risk of experiencing the event. Usually it starts at the beginning of the treatment. The end of the observation period is study- or analysis-specific. It may be derived from more than one date, e.g., the end of the treatment plus a fixed time, the end of the study, death, the start of an alternative treatment, etc.
The records of the input datasets need to be restricted to the
observation period. This can be done by deriving ANLzzFL
variables in the input datasets and then filtering the records based on
these flags.
Another option is to use the end_dates argument of the
derive_param_tte() function to specify the dates which
restrict the observation period. The input records are then
automatically restricted to records before the specified end dates.
Scenarios
There are three main scenarios to consider when deriving time-to-event datasets:
Continuous Assessments
The simplest case are events which are assessed continuously, e.g., death or adverse events. These can occur at any time within the observation period. It is assumed that the event didn’t occur if no event is recorded. In this case, the event time is the time of the first occurrence of the event and the censoring time is the end of the observation period.

Discrete Assessments, Negative Event
Many events require dedicated assessments to determine whether the event occurred or not, e.g., lab assessments, tumor assessments, questionnaires, etc. That is, information about the event is available only at these time points and it may happen that for some assessments it is unknown if the event occurred or not, e.g., tumor scans were not readable or the score couldn’t be calculated because too few questions were answered. In this case, the event time is the time of the first assessment where the event is recorded. For the censoring time it depends on the type of the event. If the event is a negative event like death, worsening, adverse event, etc., the most conservative approach is to ignore time points where it is not known if the event occurred, i.e., the censoring time is set to the time of the last assessment where it is known that the event didn’t occur 1.

For the examples, we will use the following questionnaire ADaM
dataset. The variable CHGCAT1 indicates whether the subject
worsened, improved, or was unchanged compared to baseline. For some
records it is unknown whether the subject worsened or not.
adqs_a dataset (click to
expand/collapse)

A “time to worsening” parameter is derived by using
derive_param_tte(). By default a negative event is assumed,
thus the event_type argument doesn’t need to be
specified.
trt_end <- censor_source(
dataset_name = "adsl",
date = TRTEDT
)
worsening <- event_source(
dataset_name = "adqs",
filter = CHGCAT1 == "WORSENED",
date = ADT
)
valid_assessment <- censor_source(
dataset_name = "adqs",
filter = !is.na(CHGCAT1),
date = ADT,
order = exprs(PARAMCD)
)
adtte <- derive_param_tte(
dataset_adsl = adsl,
source_datasets = list(adsl = adsl, adqs = adqs_a),
end_dates = list(trt_end),
event_conditions = list(worsening),
censor_conditions = list(valid_assessment),
set_values_to = exprs(
PARAMCD = "TTWORS",
PARAM = "Time to worsening"
)
)adtte dataset (click to
expand/collapse)

Discrete Assessments, Positive Event
For positive events like improvement, response, etc., the most conservative approach is to set the censoring time to the end of the observation period, even if it is not known whether the event occurred or not at this time point.

For positive events, the event_type argument of the
derive_param_tte() function can be set to
"positive".
improvement <- event_source(
dataset_name = "adqs",
filter = CHGCAT1 == "IMPROVED",
date = ADT
)
adtte <- derive_param_tte(
dataset_adsl = adsl,
source_datasets = list(adsl = adsl, adqs = adqs_a),
end_dates = list(trt_end),
event_type = "positive",
event_conditions = list(improvement),
censor_conditions = list(valid_assessment),
set_values_to = exprs(
PARAMCD = "TTIMPR",
PARAM = "Time to improvement"
)
)adtte dataset (click to
expand/collapse)

Events Considering more than one Assessment
For some events it is necessary to consider more than one assessment. For example, improvement or worsening could require a confirmation at a subsequent assessment.
derive_param_tte() doesn’t allow to consider subsequent
records to decide whether an event occurred or not. Thus the
confirmation information needs to be derived in the input dataset, e.g.,
by deriving a variable or a parameter which indicates whether the event
is confirmed or not. Then this variable or parameter can be used in the
derive_param_tte() function to select the event
records.
Whether to derive a variable or a parameter depends mainly on the users preference. If the confirmed change is considered as a separate endpoint, CDISC recommends to derive a separate parameter. If the confirmation is considered only as a selection criterion for the time-to-event analysis, both options are possible.
In the following sections three options are presented how to derive a
“confirmed worsening” parameter in ADTTE. The dataset and
plot displayed at the end of each section is the same but the code to
derive it is different.
Adding a Confirmation Flag to the Source Dataset
To derive a variable (CONFFL) which indicates whether
the worsening or improvement is confirmed or not, the
derive_var_joined_exist_flag() function can be used. Here
an assessment is considered as confirmed if it doesn’t change at the
next visit. Only assessments within the observation period
(ANL01FL == "Y") are considered for the confirmation.
adqs_ext <- adqs_a %>%
derive_var_joined_exist_flag(
dataset_add = adqs_a,
filter_add = ANL01FL == "Y",
by_vars = exprs(USUBJID),
new_var = CONFFL,
tmp_obs_nr_var = tmp_obs_nr,
join_vars = exprs(CHGCAT1),
join_type = "after",
order = exprs(AVISITN),
filter_join = CHGCAT1 %in% c("IMPROVED", "WORSENED") & CHGCAT1 == CHGCAT1.join &
tmp_obs_nr + 1 == tmp_obs_nr.join
)adqs_ext dataset (click to
expand/collapse)
The new variable CONFFL is then used in the definition
of the event for confirmed worsening.
confirmed_worsening <- event_source(
dataset_name = "adqs",
filter = CHGCAT1 == "WORSENED" & CONFFL == "Y",
date = ADT
)
adtte <- derive_param_tte(
dataset_adsl = adsl,
source_datasets = list(adsl = adsl, adqs = adqs_ext),
end_dates = list(trt_end),
event_conditions = list(confirmed_worsening),
censor_conditions = list(valid_assessment),
set_values_to = exprs(
PARAMCD = "TTCWORS",
PARAM = "Time to confirmed worsening"
)
)adtte dataset (click to
expand/collapse)

Adding a Confirmation Parameter to the Source Dataset
For adding a new parameter instead of a new variable the
derive_extreme_event() function can be used. The
filter_source argument of the event_joined()
object is used to restrict the records to observation period
(ANL01FL == "Y").
adqs_ext <- adqs_a %>%
derive_extreme_event(
by_vars = exprs(USUBJID, AVISITN),
source_datasets = list(adqs = adqs_a),
tmp_event_nr_var = event_nr,
order = exprs(event_nr),
mode = "first",
events = list(
event_joined(
dataset_name = "adqs",
filter_source = ANL01FL == "Y",
by_vars = exprs(USUBJID),
order = exprs(AVISITN),
join_vars = exprs(CHGCAT1),
join_type = "after",
tmp_obs_nr_var = tmp_obs_nr,
condition = CHGCAT1 %in% c("IMPROVED", "WORSENED") & CHGCAT1 == CHGCAT1.join &
tmp_obs_nr.join == tmp_obs_nr + 1,
set_values_to = exprs(
AVALC = "Y"
)
),
event(
dataset_name = "adqs",
set_values_to = exprs(
AVALC = "N"
)
)
),
set_values_to = exprs(
PARAMCD = "CONFCHGA",
PARAM = "Confirmed change of score A",
AVAL = yn_to_numeric(AVALC)
)
)adqs_ext dataset (click to
expand/collapse)
The new parameter CONFCHGA is then used in the
definition of the event for confirmed worsening.
confirmed_worsening <- event_source(
dataset_name = "adqs",
filter = PARAMCD == "CONFCHGA" & CHGCAT1 == "WORSENED" & AVALC == "Y",
date = ADT
)
adtte <- derive_param_tte(
dataset_adsl = adsl,
source_datasets = list(adsl = adsl, adqs = adqs_ext),
end_dates = list(trt_end),
event_conditions = list(confirmed_worsening),
censor_conditions = list(valid_assessment),
set_values_to = exprs(
PARAMCD = "TTCWORS",
PARAM = "Time to confirmed worsening"
)
)adtte dataset (click to
expand/collapse)

Using derive_extreme_event() to Derive Confirmation and
Time-to-Event in One Step
Another option is to use derive_extreme_event() with
event_joined() objects to derive the time-to-event
parameter. This has the advantage that the input dataset doesn’t need to
be modified but it has the disadvantage that the results are harder to
review and trace back. E.g., in the example below, the assessments which
are considered confirmed are derived within the
derive_extreme_event() function, i.e., they are not
accessible for reviewers or for debugging.
adtte <- derive_extreme_event(
by_vars = exprs(USUBJID),
source_datasets = list(adqs = filter(adqs_a, ANL01FL == "Y")),
tmp_event_nr_var = tmp_event_nr,
order = exprs(tmp_event_nr, ADT),
mode = "first",
events = list(
event_joined(
description = "Confirmed worsening event",
dataset_name = "adqs",
order = exprs(AVISITN),
join_vars = exprs(CHGCAT1),
join_type = "after",
condition = CHGCAT1 == "WORSENED" & CHGCAT1.join == "WORSENED",
keep_source_vars = exprs(ADT, TRTSDT, TRTEDT, STUDYID),
set_values_to = exprs(CNSR = 0)
),
event(
description = "Censoring at last valid assessment",
dataset_name = "adqs",
condition = !is.na(CHGCAT1),
keep_source_vars = exprs(ADT, TRTSDT, TRTEDT, STUDYID),
order = exprs(ADT),
mode = "last",
set_values_to = exprs(CNSR = 1)
)
),
set_values_to = exprs(
PARAMCD = "TTCWORS",
PARAM = "Time to confirmed worsening",
STARTDT = TRTSDT
)
)adtte dataset (click to
expand/collapse)

Combined Events
Some events are defined as a combination of multiple events. For
example, progression-free survival is defined as progression or
death. For events combined by “or”, you can create separate
event_source() objects for each event and pass them to the
event_conditions argument of
derive_param_tte(). For events combined by “and” or more
complex combinations, you must first derive a variable or parameter in
the input dataset that indicates whether the combined event
occurred.
Events Combined by “or”
Assume we want to derive a time to improvement parameter which requires improvement in score A or score B.
adqs_all dataset (click to
expand/collapse)

We define the events for improvement in score A and score B
separately and then specify both events for the
event_conditions argument of
derive_param_tte().
improvement_a <- event_source(
dataset_name = "adqs",
filter = CHGCAT1 == "IMPROVED" & PARAMCD == "A",
date = ADT
)
improvement_b <- event_source(
dataset_name = "adqs",
filter = CHGCAT1 == "IMPROVED" & PARAMCD == "B",
date = ADT
)
adtte <- derive_param_tte(
dataset_adsl = adsl,
source_datasets = list(adsl = adsl, adqs = adqs_all),
end_dates = list(trt_end),
event_type = "positive",
event_conditions = list(improvement_a, improvement_b),
censor_conditions = list(valid_assessment),
set_values_to = exprs(
PARAMCD = "TTIMPR",
PARAM = "Time to improvement"
)
)adtte dataset (click to
expand/collapse)

Events Combined by “and”
If events are combined by “and”, e.g., score A improved and
score B didn’t worsen, a variable or parameter needs to be derived in
the input dataset which indicates whether the combined event occurred or
not. To derive a new parameter the derive_param_computed()
function can be used (use derive_var_computed() for
deriving a new variable):
adqs_all_ext <- adqs_all %>%
derive_param_computed(
by_vars = exprs(STUDYID, USUBJID, AVISIT, AVISITN, ADT, ADY, TRTSDT, TRTEDT),
parameters = c("A", "B"),
set_values_to = exprs(
AVALC = if_else(
CHGCAT1.A == "IMPROVED" & CHGCAT1.B %in% c("IMPROVED", "UNCHANGED"),
"Y",
NA_character_
),
PARAMCD = "IMPROVE",
PARAM = "Improvement in score A and stable score B"
)
)adqs_all_ext dataset (click to
expand/collapse)
Now the new parameter can be used in the
derive_param_tte() function to select the event
records.
improvement_ab <- event_source(
dataset_name = "adqs",
filter = AVALC == "Y" & PARAMCD == "IMPROVE",
date = ADT
)
adtte <- derive_param_tte(
dataset_adsl = adsl,
source_datasets = list(adsl = adsl, adqs = adqs_all_ext),
end_dates = list(trt_end),
event_type = "positive",
event_conditions = list(improvement_ab),
censor_conditions = list(valid_assessment),
set_values_to = exprs(
PARAMCD = "TTIMPRAB",
PARAM = "Time to improvement in score A and stable score B"
)
)adtte dataset (click to
expand/collapse)

Summary
The preparation of time-to-event datasets can be more or less complex
depending on the definition of the event and the collection of the data.
The derive_param_tte() function provides a flexible
framework to derive time-to-event parameters for a wide range of
scenarios. For more guidance and examples see the documentation of
derive_param_tte() and the Creating
a BDS Time-to-Event ADaM vignette.
If your use case is not covered or you are unsure how to implement it using admiral, please create an issue in the admiral GitHub repository. Any feedback helps us improving admiral!
