Skip to contents

[Experimental]

Derives 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 with NA in this variable will have NFRLT set to NA.

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 to NA for all unscheduled visits. Can use any variables in the dataset.

Permitted values

Condition (optional)

Default value

NULL

Value

The input dataset with the new nominal relative time variable added.

Details

The nominal relative time is calculated as:

NFRLT = day_offset * 24 + timepoint_hours

Where:

  • day_offset is calculated from visit_day and first_dose_day, accounting for the absence of Day 0 in clinical trial convention

  • timepoint_hours is derived from the timepoint description using convert_xxtpt_to_hours(), or 0 if tpt_var is 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 = 0 for instantaneous absorption

  • IV infusions: Specify treatment_duration as infusion duration in hours (scalar) or as a variable name containing duration per record

  • Exposure records (EX): Can be called without tpt_var to derive NFRLT based only on visit day

  • Unscheduled visits: Use set_values_to_na to set NFRLT to NA for unscheduled or early discontinuation visits

  • Variable treatment durations: Use a variable name (e.g., EXDUR) when different subjects or visits have different treatment durations

Important Notes:

  • The function assumes visit_day represents the nominal/planned day, not the actual study day

  • Day numbering follows clinical trial convention with no Day 0

  • For timepoints that span multiple days (e.g., "24H Post-dose"), ensure visit_day is 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 have visit_day = 4.

  • For crossover studies, consider deriving NFRLT separately per period

  • NA values in visit_day will automatically result in NA for NFRLT (no need to use set_values_to_na for this case)

  • NA values in tpt_var will result in NA for NFRLT

  • NA values in the treatment_duration variable (if using a variable) will result in NA for NFRLT for those records

  • Use set_values_to_na when you need to set NFRLT to NA based on other variables (e.g., VISIT == "UNSCHEDULED"), especially when visit_day is populated but should not be used for the NFRLT calculation

  • If tpt_var is 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:

dataset %>%
  derive_var_nfrlt(
    ...,
    set_values_to_na = VISIT == "UNSCHEDULED"
  ) %>%
  mutate(NFRLT = if_else(is.na(NFRLT) & VISIT == "UNSCHEDULED", 99999, NFRLT))

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