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 mostly absent, and the user is invited to consult the aforementioned article for guidance.
The full, open-source VFQ questionnaire can be accessed here.
Note: All examples assume CDISC SDTM and/or ADaM format as input unless otherwise specified. Also, some of the example datasets in this vignette contain more records than are displayed by default, but the number of displayed records can be expanded using the selectors at the bottom.
{admiralophtha} suggests to populate ADVFQ solely with
VFQ-related records. Any other questionnaire data should be placed in
separate datasets (e.g. ADQS).
The records in ADVFQ can be categorized in four groups:
To start, all datasets needed for the creation of the VFQ analysis
dataset should be read into the environment. For the purpose of
demonstration we shall use the {pharmaversesdtm}
qs_ophtha and the {admiral} ADSL test
datasets. Note that the former only contains VFQ records.
Next, it will prove useful to set up lookup tables ahead of time for
the PARAM/PARAMCD and PARCATy
variables for the original, transformed and composite parameters. This
is so that when the latter two are derived later in the script, we can
simply assign PARAMCD (or one of the PARCATys)
and then perform a merge with the lookup tables to associate to them the
remaining variables as well. Please note that the mappings
described through these lookup tables may vary from company to company -
this is just what {admiralophtha} suggests.
For convenience, we suggest setting up three separate lookup tables.
You can peruse how the tables are structured below - for the full set up
code, please visit the ad_advfq.R
template. There is a special importance for the contents of
PARCAT4 since this determines the categories which are then
averaged within the composite
parameters. You can differentiate the Base Items from the Optional
ones using PARCAT5, and the original, transformed and
composite parameters using PARCAT2.
param_lookup_original)#> Warning in attr(x, "align"): 'xfun::attr()' is deprecated.
#> Use 'xfun::attr2()' instead.
#> See help("Deprecated")
#> Warning in attr(x, "format"): 'xfun::attr()' is deprecated.
#> Use 'xfun::attr2()' instead.
#> See help("Deprecated")
| QSTESTCD | PARAM | PARAMCD | PARCAT1 | PARCAT2 | PARCAT3 | PARCAT4 | PARCAT5 |
|---|---|---|---|---|---|---|---|
| VFQ101 | Your Overall Health Is | VFQ101 | VFQ-25 INTERVIEWER ADMINISTERED | Original Items | general health | General Health | Base Item |
| VFQ102 | Eyesight Using Both Eyes Is | VFQ102 | VFQ-25 INTERVIEWER ADMINISTERED | Original Items | general vision | General Vision | Base Item |
| VFQ103 | How Often You Worry About Eyesight | VFQ103 | VFQ-25 INTERVIEWER ADMINISTERED | Original Items | well-being/distress | Vision Specific: Mental Health | Base Item |
| VFQ104 | How Much Pain in and Around Eyes | VFQ104 | VFQ-25 INTERVIEWER ADMINISTERED | Original Items | ocular pain | Ocular Pain | Base Item |
| VFQ105 | Difficulty Reading Newspapers | VFQ105 | VFQ-25 INTERVIEWER ADMINISTERED | Original Items | near vision | Near Activities | Base Item |
| VFQ106 | Difficulty Doing Work/Hobbies | VFQ106 | VFQ-25 INTERVIEWER ADMINISTERED | Original Items | near vision | Near Activities | Base Item |
| VFQ107 | Difficulty Finding on Crowded Shelf | VFQ107 | VFQ-25 INTERVIEWER ADMINISTERED | Original Items | near vision | Near Activities | Base Item |
| VFQ108 | Difficulty Reading Street Signs | VFQ108 | VFQ-25 INTERVIEWER ADMINISTERED | Original Items | distance vision | Distance Activities | Base Item |
| VFQ109 | Difficulty Going Down Step at Night | VFQ109 | VFQ-25 INTERVIEWER ADMINISTERED | Original Items | distance vision | Distance Activities | Base Item |
| VFQ110 | Difficulty Noticing Objects to Side | VFQ110 | VFQ-25 INTERVIEWER ADMINISTERED | Original Items | peripheral vision | Peripheral Vision | Base Item |
param_lookup_transformed)#> Warning in attr(x, "align"): 'xfun::attr()' is deprecated.
#> Use 'xfun::attr2()' instead.
#> See help("Deprecated")
#> Warning in attr(x, "format"): 'xfun::attr()' is deprecated.
#> Use 'xfun::attr2()' instead.
#> See help("Deprecated")
| PARAM | PARAMCD | PARCAT1 | PARCAT2 | PARCAT3 | PARCAT4 | PARCAT5 |
|---|---|---|---|---|---|---|
| Transformed - Your Overall Health Is | QR01 | VFQ-25 INTERVIEWER ADMINISTERED | Transformed - Original Items | general health | General Health | Base Item |
| Transformed - Eyesight Using Both Eyes Is | QR02 | VFQ-25 INTERVIEWER ADMINISTERED | Transformed - Original Items | general vision | General Vision | Base Item |
| Transformed - How Often You Worry About Eyesight | QR03 | VFQ-25 INTERVIEWER ADMINISTERED | Transformed - Original Items | well-being/distress | Vision Specific: Mental Health | Base Item |
| Transformed - How Much Pain in and Around Eyes | QR04 | VFQ-25 INTERVIEWER ADMINISTERED | Transformed - Original Items | ocular pain | Ocular Pain | Base Item |
| Transformed - Difficulty Reading Newspapers | QR05 | VFQ-25 INTERVIEWER ADMINISTERED | Transformed - Original Items | near vision | Near Activities | Base Item |
| Transformed - Difficulty Doing Work/Hobbies | QR06 | VFQ-25 INTERVIEWER ADMINISTERED | Transformed - Original Items | near vision | Near Activities | Base Item |
| Transformed - Difficulty Finding on Crowded Shelf | QR07 | VFQ-25 INTERVIEWER ADMINISTERED | Transformed - Original Items | near vision | Near Activities | Base Item |
| Transformed - Difficulty Reading Street Signs | QR08 | VFQ-25 INTERVIEWER ADMINISTERED | Transformed - Original Items | distance vision | Distance Activities | Base Item |
| Transformed - Difficulty Going Down Step at Night | QR09 | VFQ-25 INTERVIEWER ADMINISTERED | Transformed - Original Items | distance vision | Distance Activities | Base Item |
| Transformed - Difficulty Noticing Objects to Side | QR10 | VFQ-25 INTERVIEWER ADMINISTERED | Transformed - Original Items | peripheral vision | Peripheral Vision | Base Item |
param_lookup_composite)#> Warning in attr(x, "align"): 'xfun::attr()' is deprecated.
#> Use 'xfun::attr2()' instead.
#> See help("Deprecated")
#> Warning in attr(x, "format"): 'xfun::attr()' is deprecated.
#> Use 'xfun::attr2()' instead.
#> See help("Deprecated")
| PARAM | PARAMCD | PARCAT1 | PARCAT2 | PARCAT3 | PARCAT4 | PARCAT5 |
|---|---|---|---|---|---|---|
| General Health Score | QSBGH | VFQ-25 INTERVIEWER ADMINISTERED | Derived Scale | NA | General Health | VFQ-25 |
| General Vision Score | QSBGV | VFQ-25 INTERVIEWER ADMINISTERED | Derived Scale | NA | General Vision | VFQ-25 |
| Near Activities Score | QSBNA | VFQ-25 INTERVIEWER ADMINISTERED | Derived Scale | NA | Near Activities | VFQ-25 |
| Distance Activities Score | QSBDA | VFQ-25 INTERVIEWER ADMINISTERED | Derived Scale | NA | Distance Activities | VFQ-25 |
| Vision Specific: Social Functioning Score | QSBSF | VFQ-25 INTERVIEWER ADMINISTERED | Derived Scale | NA | Vision Specific: Social Functioning | VFQ-25 |
| Color Vision Score | QSBCV | VFQ-25 INTERVIEWER ADMINISTERED | Derived Scale | NA | Color Vision | VFQ-25 |
| Peripheral Vision Score | QSBPV | VFQ-25 INTERVIEWER ADMINISTERED | Derived Scale | NA | Peripheral Vision | VFQ-25 |
| Driving Score | QSBDR | VFQ-25 INTERVIEWER ADMINISTERED | Derived Scale | NA | Driving | VFQ-25 |
| Vision Specific: Role Difficulties Score | QSBRD | VFQ-25 INTERVIEWER ADMINISTERED | Derived Scale | NA | Vision Specific: Role Difficulties | VFQ-25 |
| Ocular Pain Score | QSBOP | VFQ-25 INTERVIEWER ADMINISTERED | Derived Scale | NA | Ocular Pain | VFQ-25 |
We can now start setting up ADVFQ by taking qs and
merging on some ADSL variables which are needed for BDS derivations
later down the line. Note that there is no need to merge on the whole
ADSL dataset immediately as in so doing we would be needlessly
increasing the size of the working dataset; the rest of the variables
can be merged on at the end.
adsl_vars <- exprs(TRTSDT, TRTEDT, TRT01A, TRT01P)
advfq <- qs %>%
derive_vars_merged(
dataset_add = adsl,
new_vars = adsl_vars,
by_vars = get_admiral_option("subject_keys")
)Now we can derive the analysis date (ADT) and analysis
relative day (ADY) variables. These derivations are
study-specific and so the ones below are just examples - the user is
again invited to consult the vignette on creating
a BDS dataset from SDTM for details on this topic.
advfq <- advfq %>%
derive_vars_dt(
new_vars_prefix = "A",
dtc = QSDTC
) %>%
derive_vars_dy(
reference_date = TRTSDT,
source_vars = exprs(ADT)
)Next, we can assign PARAMCD for the original parameters
by merging with the param_lookup_original table we set up
earlier. Using derive_vars_merged_lookup() allows us to get
console-level feedback that all the QSTESTCDs have been
mapped. We only add PARAMCD for now, and will derive
PARCATy and PARAM later - again to avoid
carrying forward too many variables.
We can also derive AVAL, AVALC and
BASETYPE for the original records with a simple
mutate() statement, and then AVISIT and
AVISITN with study-specific logic.
advfq <- advfq %>%
## Add PARAMCD for original parameters only - PARCATy and PARAM will be added later
derive_vars_merged_lookup(
dataset_add = param_lookup_original,
new_vars = exprs(PARAMCD),
by_vars = exprs(QSTESTCD)
) %>%
mutate(
AVAL = QSSTRESN,
AVALC = QSORRES,
BASETYPE = "LAST PERIOD 01"
) %>%
mutate(
AVISIT = case_when(
!is.na(VISIT) ~ str_to_title(VISIT),
TRUE ~ NA_character_
),
AVISITN = case_when(
AVISIT == "Baseline" ~ 1,
AVISIT == "Week 12" ~ 12,
AVISIT == "Week 24" ~ 24,
TRUE ~ NA
),
)
#> All `QSTESTCD` are mapped.Here’s what the data for the “Near Activities” and “Distance Activities” questions looks like for one patient’s first two visits:
#> Warning in attr(x, "align"): 'xfun::attr()' is deprecated.
#> Use 'xfun::attr2()' instead.
#> See help("Deprecated")
#> Warning in attr(x, "format"): 'xfun::attr()' is deprecated.
#> Use 'xfun::attr2()' instead.
#> See help("Deprecated")
| USUBJID | QSTEST | AVISIT | PARAMCD | AVAL | AVALC |
|---|---|---|---|---|---|
| 01-701-1034 | Difficulty Reading Newspapers | Baseline | VFQ105 | 1 | NO DIFFICULTY |
| 01-701-1034 | Difficulty Doing Work/Hobbies | Baseline | VFQ106 | 2 | VERY DIFFICULT |
| 01-701-1034 | Difficulty Finding on Crowded Shelf | Baseline | VFQ107 | 2 | SOME DIFFICULTY |
| 01-701-1034 | Difficulty Reading Street Signs | Baseline | VFQ108 | 2 | SOME DIFFICULTY |
| 01-701-1034 | Difficulty Going Down Step at Night | Baseline | VFQ109 | 2 | SOME DIFFICULTY |
| 01-701-1034 | Difficulty Going Out to See Movies | Baseline | VFQ114 | 1 | NO DIFFICULTY |
| 01-701-1034 | Difficulty Reading Newspapers | Week 12 | VFQ105 | 3 | VERY DIFFICULT |
| 01-701-1034 | Difficulty Doing Work/Hobbies | Week 12 | VFQ106 | 2 | VERY DIFFICULT |
| 01-701-1034 | Difficulty Finding on Crowded Shelf | Week 12 | VFQ107 | 2 | SOME DIFFICULTY |
| 01-701-1034 | Difficulty Reading Street Signs | Week 12 | VFQ108 | 2 | SOME DIFFICULTY |
Now we are ready to derive the transformed parameters. Excluding 15C
(see later down this section), all of these are derived by re-scaling a
single original record. As such, the prototypical code which can be used
to derive them is a call to derive_extreme_records() which
is structured as follows:
derive_extreme_records(
dataset = advfq,
dataset_add = advfq,
filter_add = QSTESTCD == "VFQ1xx" & !is.na(AVAL),
set_values_to = exprs(
AVAL = transform_range(
source = AVAL,
source_range = c(1, 5), # or some other range, e.g. c(1, 6), depending on the parameter
target_range = c(0, 100),
flip_direction = TRUE # or FALSE, depending on the parameter
),
PARAMCD = "QRxx"
)
)The function transform_range() is a helper function from
{admiral} which performs the re-scaling. You will need to
specify the source_range (i.e. the range of possible values
for the original record) and whether or not to
flip_direction (i.e. whether higher values of the original
record correspond to better or worse outcomes). Note that both the
source_range and flip_direction will
change across parameters - for instance, the source range is
c(1, 5) for PARAMCD == "VFQ101" but
c(1, 6) for PARAMCD == "VFQ102". As such it is
useful to group all parameters (excluding 15C, for which a different
approach will be needed) based on which transformation they require; in
so doing the transformations for each group can be done together.
range1to5_flip_params <- c(
"VFQ101", "VFQ103", "VFQ104", "VFQ105", "VFQ106", "VFQ107", "VFQ108",
"VFQ109", "VFQ110", "VFQ111", "VFQ112", "VFQ113", "VFQ114", "VFQ116",
"VFQ116A", "VFQ1A03", "VFQ1A04", "VFQ1A05", "VFQ1A06", "VFQ1A07",
"VFQ1A08", "VFQ1A09"
)
range1to6_flip_params <- c("VFQ102")
range1to5_noflip_params <- c(
"VFQ117", "VFQ118", "VFQ119", "VFQ120", "VFQ121", "VFQ122", "VFQ123",
"VFQ124", "VFQ125", "VFQ1A11A", "VFQ1A11B", "VFQ1A12", "VFQ1A13"
)
range0to10_noflip_params <- c("VFQ1A01", "VFQ1A02")For question 15C we have to be a little more careful as the
derivation depends on whether or not question 15C was asked at that
visit. If it was, then we can derive the transformed record as normal.
However, if it wasn’t, then we have to check the response to question
15B - if the response to 15B indicates that the patient has never driven
or given up driving (i.e. QSSTRESN == 1), then we set the
transformed record to 0; otherwise, we do not derive a transformed
record for that visit. To do this, we can set up a temporary flag
variable using derive_var_merged_exist_flag() to identify
visits where question 15C was not asked, and then use that flag in the
derivation of the transformed record for 15C.
advfq <- advfq %>%
derive_var_merged_exist_flag(
dataset_add = advfq,
by_vars = exprs(!!!adsl_vars, ADT, ADY),
new_var = TEMP_VFQ115C_FL,
condition = QSTESTCD == "VFQ115C",
true_value = "Y",
false_value = "N",
missing_value = "M"
)We can then derive the transformed records, including the special
handling for 15C, in a single call to call_derivation(),
since each call to derive_extreme_records() contains the
same assignment of dataset, dataset_add and
keep_source_vars, then only differs in the
filter_add and set_values_to arguments. Each
list passed to variable_params performs the transformation
for one of the groups of parameters set up above, including dynamical
generation of the PARAMCD, though 15C is done separately.
Note that we set keep_source_vars = adsl_vars to ensure
SDTM records do not get populated for derived parameters.
advfq <- advfq %>%
call_derivation(
derivation = derive_extreme_records,
dataset = .,
dataset_add = .,
keep_source_vars = c(
get_admiral_option("subject_keys"),
exprs(PARAMCD, AVISIT, AVISITN, ADT, ADY),
adsl_vars
),
variable_params = list(
params(
filter_add = QSTESTCD %in% range1to5_flip_params & !is.na(AVAL),
set_values_to = exprs(
AVAL = transform_range(
source = AVAL,
source_range = c(1, 5),
target_range = c(0, 100),
flip_direction = TRUE
),
PARAMCD = str_replace(QSTESTCD, "VFQ1", "QR")
)
),
params(
filter_add = QSTESTCD %in% range1to6_flip_params & !is.na(AVAL),
set_values_to = exprs(
AVAL = transform_range(
source = AVAL,
source_range = c(1, 6),
target_range = c(0, 100),
flip_direction = TRUE
),
PARAMCD = str_replace(QSTESTCD, "VFQ1", "QR")
)
),
params(
filter_add = QSTESTCD %in% range1to5_noflip_params & !is.na(AVAL),
set_values_to = exprs(
AVAL = transform_range(
source = AVAL,
source_range = c(1, 5),
target_range = c(0, 100),
flip_direction = FALSE
),
PARAMCD = str_replace(QSTESTCD, "VFQ1", "QR")
)
),
params(
filter_add = QSTESTCD %in% range0to10_noflip_params & !is.na(AVAL),
set_values_to = exprs(
AVAL = transform_range(
source = AVAL,
source_range = c(0, 10),
target_range = c(0, 100),
flip_direction = FALSE
),
PARAMCD = str_replace(QSTESTCD, "VFQ1", "QR")
)
),
# For QR15C, do it in two parts
# first in the case where QSTESTCD == "VFQ115C" is present at that visit
params(
filter_add = QSTESTCD == "VFQ115C" & !is.na(AVAL),
set_values_to = exprs(
AVAL = transform_range(
source = AVAL,
source_range = c(1, 5),
target_range = c(0, 100),
flip_direction = TRUE
),
PARAMCD = "QR15C"
)
),
# second in the case where QSTESTCD == "VFQ115C" is not present at that visit
params(
filter_add = TEMP_VFQ115C_FL == "N" & QSTESTCD == "VFQ115B" & AVAL == 1,
set_values_to = exprs(
AVAL = 0,
PARAMCD = "QR15C"
)
)
)
) %>%
select(-TEMP_VFQ115C_FL)We can then add the PARAM and PARCATy
variables for both the original and transformed records by merging with
the relevant lookup tables.
advfq <- advfq %>%
derive_vars_merged_lookup(
dataset_add = rbind(
param_lookup_original %>% select(-QSTESTCD),
param_lookup_transformed
),
by_vars = exprs(PARAMCD)
)
#> All `PARAMCD` are mapped.Here’s what some of the transformed parameters and original records look like alongside each other for one patient’s first two visits:
#> Warning in attr(x, "align"): 'xfun::attr()' is deprecated.
#> Use 'xfun::attr2()' instead.
#> See help("Deprecated")
#> Warning in attr(x, "format"): 'xfun::attr()' is deprecated.
#> Use 'xfun::attr2()' instead.
#> See help("Deprecated")
| USUBJID | AVISIT | PARAM | PARAMCD | AVAL |
|---|---|---|---|---|
| 01-701-1034 | Baseline | Transformed - Your Overall Health Is | QR01 | 75 |
| 01-701-1034 | Baseline | Transformed - Eyesight Using Both Eyes Is | QR02 | 80 |
| 01-701-1034 | Baseline | Transformed - Eye Pain Keep From Doing What Like | QR19 | 25 |
| 01-701-1034 | Baseline | Your Overall Health Is | VFQ101 | 2 |
| 01-701-1034 | Baseline | Eyesight Using Both Eyes Is | VFQ102 | 2 |
| 01-701-1034 | Baseline | Eye Pain Keep From Doing What Like | VFQ119 | 2 |
| 01-701-1034 | Week 12 | Transformed - Your Overall Health Is | QR01 | 25 |
| 01-701-1034 | Week 12 | Transformed - Eyesight Using Both Eyes Is | QR02 | 40 |
| 01-701-1034 | Week 12 | Transformed - Eye Pain Keep From Doing What Like | QR19 | 25 |
| 01-701-1034 | Week 12 | Your Overall Health Is | VFQ101 | 4 |
With the now-derived transformed parameters (identifiable through
PARCAT2 == "Transformed - Original Items"), we have every
question measured on the same scale and can derive the composite
parameters. These are essentially just means across categories of
questions, with the category being determined by the contents of
PARCAT4. The VFQ guidelines dictate that for each category,
two different composite parameters should be derived: one including just
the Base items of the questionnaire
(PARCAT5 == "Base Item") and the other one also including
any Optional items. As such, below we derive the composite parameters in
two stages, first constructing advfq_qsb for the Base
item-only composite means, and then advfq_qso for the means
including all items.
Note that the dataset argument is not passed to
derive_summary_records(), meaning the output datasets
contain only the new composite parameters. Also, this time we use
PARCAT4 as a by-variable, meaning that the new composite
scores are assigned the same value of PARCAT4
(e.g. “Distance Activities”) as the records that were used to constitute
them. Then, we can then use derive_vars_merged_lookup() to
add on the PARCATy (excluding PARCAT4) and
PARAM/PARAMCD variables for these new records.
At the end, we append the new records to the existing advfq
using bind_rows().
advfq_qsb <- derive_summary_records(
dataset_add = advfq,
filter_add = PARCAT2 == "Transformed - Original Items" & PARCAT5 == "Base Item" & !is.na(AVAL),
by_vars = c(
get_admiral_option("subject_keys"),
exprs(!!!adsl_vars, AVISIT, AVISITN, ADT, ADY, PARCAT4)
),
set_values_to = exprs(AVAL = mean(AVAL))
) %>%
derive_vars_merged_lookup(
dataset_add = filter(param_lookup_composite, str_starts(PARAMCD, "QSB")),
new_vars = exprs(PARAMCD, PARAM, PARCAT1, PARCAT2, PARCAT3, PARCAT5),
by_vars = exprs(PARCAT4)
)
#> All `PARCAT4` are mapped.
advfq_qso <- derive_summary_records(
dataset_add = advfq,
filter_add = PARCAT2 == "Transformed - Original Items" & !is.na(AVAL),
by_vars = c(
get_admiral_option("subject_keys"),
exprs(!!!adsl_vars, AVISIT, AVISITN, ADT, ADY, PARCAT4)
),
set_values_to = exprs(AVAL = mean(AVAL))
) %>%
derive_vars_merged_lookup(
dataset_add = filter(param_lookup_composite, str_starts(PARAMCD, "QSO")),
new_vars = exprs(PARAMCD, PARAM, PARCAT1, PARCAT2, PARCAT3, PARCAT5),
by_vars = exprs(PARCAT4)
)
#> All `PARCAT4` are mapped.
advfq <- bind_rows(advfq, advfq_qsb, advfq_qso)Here’s what the Base item composite scores by category look like for the “Near Activities” and “Distance Activities” categories for one patient’s first two visits:
#> Warning in attr(x, "align"): 'xfun::attr()' is deprecated.
#> Use 'xfun::attr2()' instead.
#> See help("Deprecated")
#> Warning in attr(x, "format"): 'xfun::attr()' is deprecated.
#> Use 'xfun::attr2()' instead.
#> See help("Deprecated")
| USUBJID | AVISIT | PARAM | PARAMCD | PARCAT4 | AVAL |
|---|---|---|---|---|---|
| 01-701-1034 | Baseline | Transformed - Difficulty Reading Newspapers | QR05 | Near Activities | 100.00000 |
| 01-701-1034 | Baseline | Transformed - Difficulty Doing Work/Hobbies | QR06 | Near Activities | 75.00000 |
| 01-701-1034 | Baseline | Transformed - Difficulty Finding on Crowded Shelf | QR07 | Near Activities | 75.00000 |
| 01-701-1034 | Baseline | Transformed - Difficulty Reading Street Signs | QR08 | Distance Activities | 75.00000 |
| 01-701-1034 | Baseline | Transformed - Difficulty Going Down Step at Night | QR09 | Distance Activities | 75.00000 |
| 01-701-1034 | Baseline | Transformed - Difficulty Going Out to See Movies | QR14 | Distance Activities | 100.00000 |
| 01-701-1034 | Baseline | Distance Activities Score | QSBDA | Distance Activities | 83.33333 |
| 01-701-1034 | Baseline | Near Activities Score | QSBNA | Near Activities | 83.33333 |
| 01-701-1034 | Week 12 | Transformed - Difficulty Reading Newspapers | QR05 | Near Activities | 50.00000 |
| 01-701-1034 | Week 12 | Transformed - Difficulty Doing Work/Hobbies | QR06 | Near Activities | 75.00000 |
Finally, for the overall composite scores, we take all the newly-derived composite parameters, excluding “General Health”, and create:
PARAMCD == "QBCSCORE") using the
composite scores that were calculated with Base items only;PARAMCD == "QOCSCORE") using the
composite scores that were calculated with Base and Optional items.As was done for the transformed
parameters, we do this in a single call to
call_derivation(), since the only difference between the
two derivations is the filter_add and
set_values_to arguments.
advfq <- advfq %>%
call_derivation(
derivation = derive_summary_records,
dataset_add = advfq,
by_vars = c(
get_admiral_option("subject_keys"),
exprs(!!!adsl_vars, AVISIT, AVISITN, ADT, ADY)
),
variable_params = list(
params(
# Use Base Items only
filter_add = PARCAT5 == "VFQ-25" & str_sub(PARAMCD, 1, 3) == "QSB" &
PARCAT4 != "General Health" & !is.na(AVAL),
set_values_to = exprs(
AVAL = mean(AVAL),
PARAMCD = "QBCSCORE"
)
),
params(
# Use optional items items only
filter_add = PARCAT5 == "VFQ-39" & str_sub(PARAMCD, 1, 3) == "QSO" &
PARCAT4 != "General Health" & !is.na(AVAL),
set_values_to = exprs(
AVAL = mean(AVAL),
PARAMCD = "QOCSCORE"
)
)
)
)We then assign PARAM/PARAMCD and
PARCATy for these new overall composite records by merging
with the relevant lookup table, and append them to
advfq.
advfq <- advfq %>%
filter(str_detect(PARAMCD, "SCORE")) %>%
select(-PARAM, -starts_with("PARCAT")) %>%
derive_vars_merged_lookup(
dataset_add = param_lookup_composite,
new_vars = exprs(PARAM, PARCAT1, PARCAT2, PARCAT3, PARCAT4, PARCAT5),
by_vars = exprs(PARAMCD)
) %>%
rbind(advfq %>% filter(!str_detect(PARAMCD, "SCORE")))
#> All `PARAMCD` are mapped.Here’s what the overall composite records using the Base and Optional items for one patient’s baseline visit:
#> Warning in attr(x, "align"): 'xfun::attr()' is deprecated.
#> Use 'xfun::attr2()' instead.
#> See help("Deprecated")
#> Warning in attr(x, "format"): 'xfun::attr()' is deprecated.
#> Use 'xfun::attr2()' instead.
#> See help("Deprecated")
| USUBJID | AVISIT | PARAM | PARAMCD | PARCAT4 | AVAL |
|---|---|---|---|---|---|
| 01-701-1034 | Baseline | Composite Score (incl. Optional Items) | QOCSCORE | Composite Score | 70.50000 |
| 01-701-1034 | Baseline | Color Vision Score (incl. Optional Items) | QSOCV | Color Vision | 100.00000 |
| 01-701-1034 | Baseline | Distance Activities Score (incl. Optional Items) | QSODA | Distance Activities | 66.66667 |
| 01-701-1034 | Baseline | Vision Specific: Dependency Score (incl. Optional Items) | QSODP | Vision Specific: Dependency | 37.50000 |
| 01-701-1034 | Baseline | Driving Score (incl. Optional Items) | QSODR | Driving | 91.66667 |
| 01-701-1034 | Baseline | General Vision Score (incl. Optional Items) | QSOGV | General Vision | 80.00000 |
| 01-701-1034 | Baseline | Vision Specific: Mental Health Score (incl. Optional Items) | QSOMH | Vision Specific: Mental Health | 66.66667 |
| 01-701-1034 | Baseline | Near Activities Score (incl. Optional Items) | QSONA | Near Activities | 87.50000 |
| 01-701-1034 | Baseline | Ocular Pain Score (incl. Optional Items) | QSOOP | Ocular Pain | 37.50000 |
| 01-701-1034 | Baseline | Peripheral Vision Score (incl. Optional Items) | QSOPV | Peripheral Vision | 75.00000 |
The user is invited to consult the article on creating a BDS dataset from SDTM to learn how to add standard BDS variables to ADVFQ.
| ADaM | Sample Code |
|---|---|
| ADVFQ | ad_advfq.R |