This article describes creating an ADVFQ ADaM with Visual Functioning Questionnaire data for ophthalmology endpoints. It is to be used in conjunction with the article on creating a BDS dataset from SDTM. As such, derivations and processes that are not specific to ADVFQ are absent, and the user is invited to consult the aforementioned article for guidance.
Note: All examples assume CDISC SDTM and/or ADaM format as input unless otherwise specified.
{admiralophtha}
suggests to populate ADVFQ solely with
VFQ records from the QS SDTM. Any other questionnaire data should be
placed in separate datasets (e.g. ADQS).
AVAL
)ANL01FL
ASEQ
)To start, all datasets needed for the creation of the questionnaire
dataset should be read into the environment. For the purpose of
demonstration we shall use the {admiral}
QS and ADSL test
data. The QS dataset is filtered to the VFQ parameters of interest.
data("admiral_adsl")
data("qs_ophtha")
adsl <- admiral_adsl
qs <- qs_ophtha
qs <- qs %>% filter(QSTESTCD %in% c("VFQ1", "VFQ2", "VFQ3", "VFQ4"))
Next, the programmer should create a parameter lookup table which
includes QSTESTCD
, PARAMCD
,
PARAM
, PARCAT1
and PARCAT2
variables. This should include all parameters that will be needed in the
final ADVFQ and will be used later to merge parameter information.
param_lookup <- tibble::tribble(
~QSTESTCD, ~PARAMCD, ~PARAM, ~PARCAT1, ~PARCAT2,
"VFQ1", "VFQ1", "Overall Health", "NEI VFQ-25", "Original Response",
"VFQ2", "VFQ2", "Eyesight in Both Eyes", "NEI VFQ-25", "Original Response",
"VFQ3", "VFQ3", "Worry About Eyesight", "NEI VFQ-25", "Original Response",
"VFQ4", "VFQ4", "Pain in and Around Eyes", "NEI VFQ-25", "Original Response",
"QR01", "QR01", "Recoded Item - 01", "NEI VFQ-25", "General 01",
"QR02", "QR02", "Recoded Item - 02", "NEI VFQ-25", "General 01",
"QR03", "QR03", "Recoded Item - 03", "NEI VFQ-25", "General 02",
"QR04", "QR04", "Recoded Item - 04", "NEI VFQ-25", "General 02",
"QSG01", "QSG01", "General Score 01", "NEI VFQ-25", "Averaged Result",
"QSG02", "QSG02", "General Score 02", "NEI VFQ-25", "Averaged Result",
"QBCSCORE", "QBCSCORE", "Composite Score", "NEI VFQ-25", "Averaged Result"
)
Now the ADVFQ dataset can be constructed, merging the filtered QS
dataset with ADSL. This is necessary because treatment start date
TRTSDT
is a prerequisite for the derivation of variables
such as Analysis Day ADY
which can be programmed by
following the article on creating
a BDS dataset from SDTM.
To derive the analysis values we use the function
admiral::derive_vars_merged_lookup()
which merges on
PARAMCD
from the parameter lookup table. This merges on the
parameter by QSTESTCD
and assigns AVAL
and
AVALC
.
Once we have included the initial records from QS, the programmer should next program new records for parameters which recode the original questions. Run this section of code for every question that you need recoding. This gives an example of recoding one question.
## QR01 Recoded Item 01
# set to 100 if [advfq.AVAL] = 1
# else set to 75 if [advfq.AVAL] = 2
# else set to 50 if [advfq.AVAL] = 3
# else set to 25 if [advfq.AVAL] = 4
# else set to 0 if [advfq.AVAL] = 5
advfq <- advfq %>%
derive_summary_records(
dataset_add = advfq,
by_vars = c(
get_admiral_option("subject_keys"),
exprs(!!!adsl_vars, PARAMCD, VISITNUM, VISIT)
),
filter_add = QSTESTCD == "VFQ1" & !is.na(AVAL),
set_values_to = exprs(
AVAL = identity(AVAL),
PARAMCD = "QR01"
)
) %>%
mutate(AVAL = ifelse(PARAMCD == "QR01",
case_when(
AVAL == 1 ~ 100,
AVAL == 2 ~ 75,
AVAL == 3 ~ 50,
AVAL == 4 ~ 25,
AVAL >= 5 ~ 0
),
AVAL
))
Next, the programmer should create summary records as average of
recoded questions using admiral::derive_summary_records
.
This example uses two of the recoded questions to create an average
record.
## Derive a new record as a summary record ----
## QSG01 General Score 01
# Average of QR01 and QR02 records
advfq <- advfq %>%
derive_summary_records(
dataset_add = advfq,
by_vars = c(
get_admiral_option("subject_keys"),
exprs(!!!adsl_vars, VISITNUM, VISIT, ADT, ADY)
),
filter_add = PARAMCD %in% c("QR01", "QR02") & !is.na(AVAL),
set_values_to = exprs(
AVAL = mean(AVAL),
PARAMCD = "QSG01"
)
)
In most finding ADaMs, an analysis flag is derived to identify the appropriate observation(s) to use for a particular analysis when a subject has multiple observations within a particular timing period.
In this situation, an analysis flag (e.g. ANLxxFL
) may
be used to choose the appropriate record for analysis.
This flag may be derived using the admiral
function admiral::derive_var_extreme_flag()
. For this
example, we will assume we would like to choose the latest value by our
subject keys along with PARAMCD
and
AVISIT
.
## ANL01FL: Flag last result within an AVISIT for post-baseline records ----
advfq <- advfq %>%
restrict_derivation(
derivation = derive_var_extreme_flag,
args = params(
new_var = ANL01FL,
by_vars = c(get_admiral_option("subject_keys"), exprs(PARAMCD, AVISIT)),
order = exprs(ADT, AVAL),
mode = "last"
),
filter = !is.na(AVISITN) & ONTRTFL == "Y"
)
We then derive ASEQ
using
admiral::derive_var_obs_number()
based on the observation
number within the dataset, additionally merge on PARAM
,
PARCAT1
and PARCAT2
using the earlier lookup
table.
## Get ASEQ and PARAM ----
advfq <- advfq %>%
# Calculate ASEQ
derive_var_obs_number(
new_var = ASEQ,
by_vars = get_admiral_option("subject_keys"),
order = exprs(PARAMCD, ADT, AVISITN, VISITNUM),
check_type = "error"
) %>%
# Derive PARAM
derive_vars_merged(dataset_add = select(param_lookup, -QSTESTCD), by_vars = exprs(PARAMCD))
Once analysis variables have been programmed, variables from ADSL
which are required should be merged on to the dataset using
admiral::derive_vars_merged
.
ADaM | Sample Code |
---|---|
ADVFQ | ad_advfq.R |