
Derive Nominal Relative Time from First Dose (NFRLT)
Source:R/derive_var_nfrlt.R
derive_var_nfrlt.RdDerives nominal/planned time from first dose in hours by combining visit day
information with timepoint descriptions. The function converts timepoint
strings to hours using convert_xxtpt_to_hours() and adds them to the
day-based offset.
Usage
derive_var_nfrlt(
dataset,
new_var = NFRLT,
tpt_var = NULL,
visit_day,
first_dose_day = 1,
treatment_duration = 0,
range_method = "midpoint",
set_values_to_na = NULL
)Arguments
- dataset
-
Input dataset containing visit day variable and optionally timepoint variable.
- Permitted values
A data frame or tibble
- Default value
none
- new_var
-
Name of the new variable to create (unquoted). Default is
NFRLT.- Permitted values
Unquoted variable name
- Default value
NFRLT
- tpt_var
-
Timepoint variable containing descriptions like "Pre-dose", "1H Post-dose", etc. (unquoted). If not provided or if the variable doesn't exist in the dataset, only the visit day offset is calculated (timepoint contribution is 0).
- Permitted values
Unquoted variable name (optional)
- Default value
NULL
- visit_day
-
Visit day variable (unquoted). This should be the planned/ nominal visit day (e.g.,
VISITDY). Records withNAin this variable will have NFRLT set toNA.- Permitted values
Unquoted variable name
- Default value
none
- first_dose_day
-
The day number considered as the first dose day. Default is 1. For multiple-dose studies, this is typically Day 1.
- Permitted values
Numeric scalar (positive integer)
- Default value
1
- treatment_duration
-
Duration of treatment in hours. Can be either:
A numeric scalar (used for all records), or
An unquoted variable name from the dataset (e.g.,
EXDUR) where each record can have a different treatment duration
Passed to
convert_xxtpt_to_hours(). Must be non-negative. Default is 0 hours (for instantaneous treatments like oral medications).- Permitted values
Numeric scalar or unquoted variable name (non-negative)
- Default value
0
- range_method
-
Method for converting time ranges to single values. Options are "midpoint" (default), "start", or "end". Passed to
convert_xxtpt_to_hours(). For example, "0-6h" with midpoint returns 3, with start returns 0, with end returns 6.- Permitted values
Character scalar ("midpoint", "start", or "end")
- Default value
"midpoint"
- set_values_to_na
-
An optional condition that marks derived NFRLT values as
NA. For example,set_values_to_na = VISIT == "UNSCHEDULED"will set NFRLT toNAfor all unscheduled visits. Can use any variables in the dataset.- Permitted values
Condition (optional)
- Default value
NULL
Details
The nominal relative time is calculated as:
NFRLT = day_offset * 24 + timepoint_hours
Where:
day_offsetis calculated fromvisit_dayandfirst_dose_day, accounting for the absence of Day 0 in clinical trial conventiontimepoint_hoursis derived from the timepoint description usingconvert_xxtpt_to_hours(), or 0 iftpt_varis not provided
Handling "No Day 0":
In clinical trials, day numbering typically follows the convention:
..., Day -2, Day -1, Day 1, Day 2, ... (no Day 0). This function accounts
for this by adjusting the day offset when visit_day is negative and
first_dose_day is positive.
For example, with first_dose_day = 1:
Day -1 -> -24 hours (1 day before Day 1, not 2 days)
Day -7 -> -168 hours (7 days before Day 1)
Day 1 -> 0 hours (first dose day)
Day 8 -> 168 hours (7 days after Day 1)
With first_dose_day = 7:
Day -1 -> -168 hours (7 days before Day 7, accounting for no Day 0)
Day 1 -> -144 hours (6 days before Day 7)
Day 6 -> -24 hours (1 day before Day 7)
Day 7 -> 0 hours (first dose day)
Common Use Cases:
Single dose study: Day 1 only, with samples at various timepoints (e.g., Pre-dose, 1H, 2H, 4H, 8H, 24H)
Multiple dose study: Dosing on multiple days (e.g., Day 1, Day 8, Day 15) with samples around each dose
Screening visits: Negative visit days (e.g., Day -14, Day -7) before first dose
Steady state study: Multiple daily doses with sampling on specific days
Oral medications: Use default
treatment_duration = 0for instantaneous absorptionIV infusions: Specify
treatment_durationas infusion duration in hours (scalar) or as a variable name containing duration per recordExposure records (EX): Can be called without
tpt_varto derive NFRLT based only on visit dayUnscheduled visits: Use
set_values_to_nato set NFRLT toNAfor unscheduled or early discontinuation visitsVariable treatment durations: Use a variable name (e.g.,
EXDUR) when different subjects or visits have different treatment durations
Important Notes:
The function assumes
visit_dayrepresents the nominal/planned day, not the actual study dayDay numbering follows clinical trial convention with no Day 0
For timepoints that span multiple days (e.g., "24H Post-dose"), ensure
visit_dayis set to the day when the sample was taken. For example, if dosing occurs on Day 3, a "24H Post-dose" sample taken on Day 4 should havevisit_day = 4.For crossover studies, consider deriving NFRLT separately per period
NAvalues invisit_daywill automatically result inNAfor NFRLT (no need to useset_values_to_nafor this case)NAvalues intpt_varwill result inNAfor NFRLTNAvalues in thetreatment_durationvariable (if using a variable) will result inNAfor NFRLT for those recordsUse
set_values_to_nawhen you need to set NFRLT toNAbased on other variables (e.g.,VISIT == "UNSCHEDULED"), especially whenvisit_dayis populated but should not be used for the NFRLT calculationIf
tpt_varis not provided or doesn't exist in the dataset, timepoint contribution is assumed to be 0 hours
Setting Special Values:
If you need to set NFRLT to a specific value (e.g., 99999) for certain visits
instead of NA, use set_values_to_na first to set them to NA, then use
a subsequent mutate() call to replace those NA values:
See also
BDS-Findings Functions that returns variable appended to dataset:
derive_basetype_records(),
derive_var_analysis_ratio(),
derive_var_anrind(),
derive_var_atoxgr(),
derive_var_atoxgr_dir(),
derive_var_base(),
derive_var_chg(),
derive_var_ontrtfl(),
derive_var_pchg(),
derive_var_shift(),
derive_vars_crit_flag()
Examples
Single dose study
Day 1 only with oral medication
library(dplyr)
library(tibble)
adpc <- tribble(
~USUBJID, ~VISITDY, ~PCTPT,
"001", 1, "Pre-dose",
"001", 1, "1H Post-dose",
"001", 1, "2H Post-dose",
"001", 1, "4H Post-dose",
"001", 1, "24H Post-dose"
)
derive_var_nfrlt(
adpc,
new_var = NFRLT,
tpt_var = PCTPT,
visit_day = VISITDY
)
#> # A tibble: 5 × 4
#> USUBJID VISITDY PCTPT NFRLT
#> <chr> <dbl> <chr> <dbl>
#> 1 001 1 Pre-dose 0
#> 2 001 1 1H Post-dose 1
#> 3 001 1 2H Post-dose 2
#> 4 001 1 4H Post-dose 4
#> 5 001 1 24H Post-dose 24
Study with screening visits
Handling negative visit days (no Day 0 in clinical trials)
adpc_screen <- tribble(
~USUBJID, ~VISITDY, ~PCTPT,
"001", -14, "Screening",
"001", -7, "Pre-dose",
"001", -1, "Pre-dose",
"001", 1, "Pre-dose",
"001", 1, "2H Post-dose"
)
derive_var_nfrlt(
adpc_screen,
new_var = NFRLT,
tpt_var = PCTPT,
visit_day = VISITDY
)
#> # A tibble: 5 × 4
#> USUBJID VISITDY PCTPT NFRLT
#> <chr> <dbl> <chr> <dbl>
#> 1 001 -14 Screening -336
#> 2 001 -7 Pre-dose -168
#> 3 001 -1 Pre-dose -24
#> 4 001 1 Pre-dose 0
#> 5 001 1 2H Post-dose 2
Multiple dose study
Dosing on Days 1, 8, and 15
adpc_md <- tribble(
~USUBJID, ~VISITDY, ~PCTPT,
"001", 1, "Pre-dose",
"001", 1, "2H Post-dose",
"001", 8, "Pre-dose",
"001", 8, "2H Post-dose",
"001", 15, "Pre-dose",
"001", 15, "2H Post-dose"
)
derive_var_nfrlt(
adpc_md,
new_var = NFRLT,
tpt_var = PCTPT,
visit_day = VISITDY
)
#> # A tibble: 6 × 4
#> USUBJID VISITDY PCTPT NFRLT
#> <chr> <dbl> <chr> <dbl>
#> 1 001 1 Pre-dose 0
#> 2 001 1 2H Post-dose 2
#> 3 001 8 Pre-dose 168
#> 4 001 8 2H Post-dose 170
#> 5 001 15 Pre-dose 336
#> 6 001 15 2H Post-dose 338
Custom first dose day
First dose on Day 7 instead of Day 1
adpc_day7 <- tribble(
~USUBJID, ~VISITDY, ~PCTPT,
"001", -1, "Pre-dose",
"001", 1, "Pre-dose",
"001", 6, "Pre-dose",
"001", 7, "Pre-dose",
"001", 8, "Pre-dose"
)
derive_var_nfrlt(
adpc_day7,
new_var = NFRLT,
tpt_var = PCTPT,
visit_day = VISITDY,
first_dose_day = 7
)
#> # A tibble: 5 × 4
#> USUBJID VISITDY PCTPT NFRLT
#> <chr> <dbl> <chr> <dbl>
#> 1 001 -1 Pre-dose -168
#> 2 001 1 Pre-dose -144
#> 3 001 6 Pre-dose -24
#> 4 001 7 Pre-dose 0
#> 5 001 8 Pre-dose 24
IV infusion with scalar treatment duration
2-hour infusion duration for all records
adpc_inf <- tribble(
~USUBJID, ~VISITDY, ~PCTPT,
"001", 1, "Pre-dose",
"001", 1, "EOI",
"001", 1, "1H Post EOI",
"001", 1, "10MIN PRE EOI"
)
derive_var_nfrlt(
adpc_inf,
new_var = NFRLT,
tpt_var = PCTPT,
visit_day = VISITDY,
treatment_duration = 2
)
#> # A tibble: 4 × 4
#> USUBJID VISITDY PCTPT NFRLT
#> <chr> <dbl> <chr> <dbl>
#> 1 001 1 Pre-dose 0
#> 2 001 1 EOI 2
#> 3 001 1 1H Post EOI 3
#> 4 001 1 10MIN PRE EOI 1.83
Variable treatment duration
Different treatment durations per subject using a variable
adpc_var_dur <- tribble(
~USUBJID, ~VISITDY, ~PCTPT, ~EXDUR,
"001", 1, "Pre-dose", 1,
"001", 1, "EOI", 1,
"001", 1, "1H POST EOI", 1,
"002", 1, "Pre-dose", 2,
"002", 1, "EOI", 2,
"002", 1, "1H POST EOI", 2
)
derive_var_nfrlt(
adpc_var_dur,
new_var = NFRLT,
tpt_var = PCTPT,
visit_day = VISITDY,
treatment_duration = EXDUR
)
#> # A tibble: 6 × 5
#> USUBJID VISITDY PCTPT EXDUR NFRLT
#> <chr> <dbl> <chr> <dbl> <dbl>
#> 1 001 1 Pre-dose 1 0
#> 2 001 1 EOI 1 1
#> 3 001 1 1H POST EOI 1 2
#> 4 002 1 Pre-dose 2 0
#> 5 002 1 EOI 2 2
#> 6 002 1 1H POST EOI 2 3
Exposure records without timepoint variable
Deriving NFRLT based only on visit day
ex <- tribble(
~USUBJID, ~VISITDY,
"001", 1,
"001", 8,
"001", 15
)
derive_var_nfrlt(
ex,
new_var = NFRLT,
visit_day = VISITDY
)
#> # A tibble: 3 × 3
#> USUBJID VISITDY NFRLT
#> <chr> <dbl> <dbl>
#> 1 001 1 0
#> 2 001 8 168
#> 3 001 15 336
Unscheduled visits
Setting NFRLT to NA for unscheduled visits
adpc_unsched <- tribble(
~USUBJID, ~VISITDY, ~VISIT, ~PCTPT,
"001", 1, "VISIT 1", "Pre-dose",
"001", 1, "VISIT 1", "2H Post-dose",
"001", NA_real_, "UNSCHEDULED", "Pre-dose",
"001", NA_real_, "UNSCHEDULED", "2H Post-dose"
)
derive_var_nfrlt(
adpc_unsched,
new_var = NFRLT,
tpt_var = PCTPT,
visit_day = VISITDY,
set_values_to_na = VISIT == "UNSCHEDULED"
)
#> # A tibble: 4 × 5
#> USUBJID VISITDY VISIT PCTPT NFRLT
#> <chr> <dbl> <chr> <chr> <dbl>
#> 1 001 1 VISIT 1 Pre-dose 0
#> 2 001 1 VISIT 1 2H Post-dose 2
#> 3 001 NA UNSCHEDULED Pre-dose NA
#> 4 001 NA UNSCHEDULED 2H Post-dose NA
Early discontinuation visits
Handling study drug early discontinuation
adpc_disc <- tribble(
~USUBJID, ~VISITDY, ~VISIT, ~PCTPT,
"001", 1, "VISIT 1", "Pre-dose",
"001", 1, "VISIT 1", "2H Post-dose",
"001", NA_real_, "STUDY DRUG EARLY DISCONTINUATION", "Pre-dose"
)
derive_var_nfrlt(
adpc_disc,
new_var = NFRLT,
tpt_var = PCTPT,
visit_day = VISITDY,
set_values_to_na = VISIT == "STUDY DRUG EARLY DISCONTINUATION"
)
#> # A tibble: 3 × 5
#> USUBJID VISITDY VISIT PCTPT NFRLT
#> <chr> <dbl> <chr> <chr> <dbl>
#> 1 001 1 VISIT 1 Pre-dose 0
#> 2 001 1 VISIT 1 2H Post-dose 2
#> 3 001 NA STUDY DRUG EARLY DISCONTINUATION Pre-dose NA
Multiple exclusion criteria
Excluding multiple visit types
adpc_multi <- tribble(
~USUBJID, ~VISITDY, ~VISIT, ~PCTPT,
"001", 1, "VISIT 1", "Pre-dose",
"001", NA_real_, "UNSCHEDULED", "Pre-dose",
"001", NA_real_, "STUDY DRUG EARLY DISCONTINUATION", "Pre-dose"
)
derive_var_nfrlt(
adpc_multi,
new_var = NFRLT,
tpt_var = PCTPT,
visit_day = VISITDY,
set_values_to_na = VISIT %in% c("UNSCHEDULED", "STUDY DRUG EARLY DISCONTINUATION")
)
#> # A tibble: 3 × 5
#> USUBJID VISITDY VISIT PCTPT NFRLT
#> <chr> <dbl> <chr> <chr> <dbl>
#> 1 001 1 VISIT 1 Pre-dose 0
#> 2 001 NA UNSCHEDULED Pre-dose NA
#> 3 001 NA STUDY DRUG EARLY DISCONTINUATION Pre-dose NA
Setting special values instead of NA
Using mutate to set NFRLT to 99999 for unscheduled visits
adpc_unsched_value <- tribble(
~USUBJID, ~VISITDY, ~VISIT, ~PCTPT,
"001", 1, "VISIT 1", "Pre-dose",
"001", 1, "VISIT 1", "2H Post-dose",
"001", NA_real_, "UNSCHEDULED", "Pre-dose",
"001", NA_real_, "UNSCHEDULED", "2H Post-dose"
)
adpc_unsched_value %>%
derive_var_nfrlt(
new_var = NFRLT,
tpt_var = PCTPT,
visit_day = VISITDY,
set_values_to_na = VISIT == "UNSCHEDULED"
) %>%
mutate(
NFRLT = if_else(is.na(NFRLT) & VISIT == "UNSCHEDULED", 99999, NFRLT)
)
#> # A tibble: 4 × 5
#> USUBJID VISITDY VISIT PCTPT NFRLT
#> <chr> <dbl> <chr> <chr> <dbl>
#> 1 001 1 VISIT 1 Pre-dose 0
#> 2 001 1 VISIT 1 2H Post-dose 2
#> 3 001 NA UNSCHEDULED Pre-dose 99999
#> 4 001 NA UNSCHEDULED 2H Post-dose 99999
Custom range method
Using end of range instead of midpoint
adpc_range <- tribble(
~USUBJID, ~VISITDY, ~PCTPT,
"001", 1, "Pre-dose",
"001", 1, "0-6h Post-dose"
)
derive_var_nfrlt(
adpc_range,
new_var = NFRLT,
tpt_var = PCTPT,
visit_day = VISITDY,
range_method = "end"
)
#> # A tibble: 2 × 4
#> USUBJID VISITDY PCTPT NFRLT
#> <chr> <dbl> <chr> <dbl>
#> 1 001 1 Pre-dose 0
#> 2 001 1 0-6h Post-dose 6
Alternative terminology
Using "Before" and "After" terminology
adpc_alt <- tribble(
~USUBJID, ~VISITDY, ~PCTPT,
"001", 1, "Before",
"001", 1, "1H After",
"001", 1, "2H After"
)
derive_var_nfrlt(
adpc_alt,
new_var = NFRLT,
tpt_var = PCTPT,
visit_day = VISITDY
)
#> # A tibble: 3 × 4
#> USUBJID VISITDY PCTPT NFRLT
#> <chr> <dbl> <chr> <dbl>
#> 1 001 1 Before 0
#> 2 001 1 1H After 1
#> 3 001 1 2H After 2