library(dplyr) library(tibble) library(knitr) library(PMDatR)
This vignette demonstrates the ADDL features of the PMDatR package. ADDL is a feature in NONMEM whereby a sequence of doses can be specified in a single entry, rather than requiring one record per dose. The ADDL algorithm in PMDatR can be used to compute ADDL sequencing between known dosing records in the sequence (e.g., first and last doses) and allows for additional features such as:
Dose records are specified with a start time (TIME), dose amount (AMT), event flag (EVID), missing flag indicator (MEX), and interdose interval (II) - at a minimum. The TIME column must be in POSIXct format (an R date/time value). A nonzero II will trigger the ADDL algorithm to fill in ADDL sequencing between dose records having the same II. That is, the doses must have the same II.
ex1 = data_frame(TIME=c("2018-01-01T08:15","2018-01-10T10:45"), AMT=100, EVID=1, II=24, MEX=FALSE) %>% mutate(TIME=iso_to_posix(TIME))
Input Data:
ex1 %>% kable
Output:
ex1 %>% get_addl_dosing() %>% kable
The original dose records are unmodified except that II must be set to 0 (NONMEM expects that). An ADDL record is inserted between them with the dose time set to align the final ADDL dose with the next dose record.
Note that if II doesn't match, the ADDL computation disregards the sequence, but still adjusts II and adds ADDL. Here II is 0 for the second record:
ex1 = data_frame(TIME=c("2018-01-01T08:15","2018-01-10T10:45"), AMT=100, EVID=1, II=c(24,0), MEX=FALSE) %>% mutate(TIME=iso_to_posix(TIME)) ex1 %>% kable
Which produces:
ex1 %>% get_addl_dosing() %>% kable
And if the dose changes?
ex1 = data_frame(TIME=c("2018-01-01T08:15","2018-01-10T10:45", "2018-01-23T09:30"), AMT=c(100, 50, 100), EVID=1, II=24, MEX=FALSE) %>% mutate(TIME=iso_to_posix(TIME))
Input Data:
ex1 %>% kable
Which produces:
ex1 %>% get_addl_dosing() %>% kable
The first dose record starts the repeated dosing interval. The second dose record ends the interval (because it's the last dose, not because these need to be paired).
Input Data:
ex_dat <- tibble::tribble( ~ID, ~TIME, ~TRT, ~AMT, ~FREQ, ~MEX, ~II, ~EVID, 1, "01/01/2017 10:00", "A", 100, "QD", FALSE, 24, 1, 1, "01/11/2017 10:00", "A", 100, "QD", FALSE, 24, 1 ) %>% dplyr::mutate( TIME = iso_to_posix(TIME) ) ex_dat %>% kable
Modified dosing sheet after ADDL computation. Note that the dose time is the same in both the starting and ending dose of the ADDL block. The first dose on 1/1 is followed by ADDL dosing starting on 1/2 @ 10am with 8 extra doses, which stop on 1/10 @ 10am. Then the final dose is on 1/11 @ 10am.
get_addl_dosing(ex_dat) %>% kable
We move the final dose back 5 hours.
Input Data:
ex_dat <- tibble::tribble( ~ID, ~TIME, ~TRT, ~AMT, ~FREQ, ~MEX, ~II, ~EVID, 1, "01/01/2017 10:00", "A", 100, "QD", FALSE, 24, 1, 1, "01/11/2017 15:00", "A", 100, "QD", FALSE, 24, 1 ) %>% dplyr::mutate( TIME = iso_to_posix(TIME) ) ex_dat %>% kable
Modified dosing sheet after ADDL computation. The first dose on 1/1 is followed by ADDL dosing starting on 1/2 @ 3pm with 8 extra doses, which stop on 1/10 @ 3pm. Then the final dose is on 1/11 @ 3pm.
get_addl_dosing(ex_dat) %>% kable
We move the final dose forward 5 hours.
Input Data:
ex_dat <- tibble::tribble( ~ID, ~TIME, ~TRT, ~AMT, ~FREQ, ~MEX, ~II, ~EVID, 1, "01/01/2017 10:00", "A", 100, "QD", FALSE, 24, 1, 1, "01/11/2017 05:00", "A", 100, "QD", FALSE, 24, 1 ) %>% dplyr::mutate( TIME = iso_to_posix(TIME) ) ex_dat %>% kable
Modified dosing sheet after ADDL computation. Backing up from 1/11 @ 5am, we land on 1/2 @ 5am as the next dose time. This is acceptable because it is 19 hours from the previous dose, a time interval of less than 1/2 of the II (24 hours).
get_addl_dosing(ex_dat) %>% kable
Both dose times are modified, so dose times are only 10 hours apart.
Input Data:
ex_dat <- tibble::tribble( ~ID, ~TIME, ~TRT, ~AMT, ~FREQ, ~MEX, ~II, ~EVID, 1, "01/01/2017 22:00", "A", 100, "QD", FALSE, 24, 1, 1, "01/11/2017 06:00", "A", 100, "QD", FALSE, 24, 1 ) %>% dplyr::mutate( TIME = iso_to_posix(TIME) ) ex_dat %>% kable
A 6am dose on 1/2 is only 10 hours from the initial dose, so the 1/2 dose is skipped and the ADDL sequence starts on 1/3. This reduces ADDL to 7, since skipping the small partial period means we take a whole II to set the next dose.
get_addl_dosing(ex_dat) %>% kable
Same dose times at start and end, exactly two II apart.
Input Data:
ex_dat <- tibble::tribble( ~ID, ~TIME, ~TRT, ~AMT, ~FREQ, ~MEX, ~II, ~EVID, 1, "01/01/2017 10:00", "A", 100, "QD", FALSE, 24, 1, 1, "01/03/2017 10:00", "A", 100, "QD", FALSE, 24, 1 ) %>% dplyr::mutate( TIME = iso_to_posix(TIME) ) ex_dat %>% kable
There should be one ADDL record on 1/2, but with ADDL set to zero because the ADDL sequence only has one dose.
get_addl_dosing(ex_dat) %>% kable
Same dose times at start and end, exactly 1.5 II apart.
Input Data:
ex_dat <- tibble::tribble( ~ID, ~TIME, ~TRT, ~AMT, ~FREQ, ~MEX, ~II, ~EVID, 1, "01/01/2017 22:00", "A", 100, "QD", FALSE, 24, 1, 1, "01/03/2017 10:00", "A", 100, "QD", FALSE, 24, 1 ) %>% dplyr::mutate( TIME = iso_to_posix(TIME) ) ex_dat %>% kable
There should be one ADDL record on 1/2, but with ADDL set to zero because the ADDL sequence only has one dose. This is the limit of our tolerance for the extra dose.
get_addl_dosing(ex_dat) %>% kable
Duplicate previous example, but ID=1 is just above the the II tolerance, ID=2 is just below.
Input Data:
ex_dat <- tibble::tribble( ~ID, ~TIME, ~TRT, ~AMT, ~FREQ, ~MEX, ~II, ~EVID, 1, "01/01/2017 21:59", "A", 100, "QD", FALSE, 24, 1, 1, "01/03/2017 10:00", "A", 100, "QD", FALSE, 24, 1, 2, "01/01/2017 22:01", "A", 100, "QD", FALSE, 24, 1, 2, "01/03/2017 10:00", "A", 100, "QD", FALSE, 24, 1 ) %>% dplyr::mutate( TIME = iso_to_posix(TIME) ) ex_dat %>% kable
ID=1 gets an ADDL dose. ID=2 does not. This is probably the most concerning edge case, and an example of why we should record the 3 previous dose times leading up to a PK day. If we have actual doses before a PK day then this ADDL algorithm will have minimal effect.
NOTE: we ask for QD dosing, but for ID=2 the 1/2 dose is skipped due to the II tolerance (currently set at 50%). We can't give a dose at 10am because it is within 12 hours of the previous dose, so in order to start the ADDL dosing at the correct time we have to skip forward an entire day, which puts us at the final dose anyway.
get_addl_dosing(ex_dat) %>% arrange(ID, TIME) %>% kable
Change the II tolerance from 0.5 (default) to 0.375 (9 hours for QD). Now the second subject gets the ADDL dose at 10 am.
get_addl_dosing(ex_dat, .tolII = 0.375) %>% arrange(ID, TIME) %>% kable
The first dose record starts the repeated dosing interval. Then we have 3 additional doses leading up to the PK day. We should see ADDL dosing starting on 1/2@9:15am and running for 8 additional doses. Then the individual doses should show up. It doesn't matter that they are still marked with II=24... unless there is a large enough gap to restart ADDL sequencing.
Input Data:
ex_dat <- tibble::tribble( ~ID, ~TIME, ~TRT, ~AMT, ~FREQ, ~MEX, ~II, ~EVID, 1, "01/01/2017 10:00", "A", 100, "QD", FALSE, 24, 1, 1, "01/11/2017 09:15", "A", 100, "QD", FALSE, 24, 1, 1, "01/12/2017 10:21", "A", 100, "QD", FALSE, 24, 1, 1, "01/13/2017 08:37", "A", 100, "QD", FALSE, 24, 1 ) %>% dplyr::mutate( TIME = iso_to_posix(TIME) ) ex_dat %>% kable
As expected, the ADDL dosing fills in between 1/2 and 1/10 only and lines up qith 1/11 dose time.
get_addl_dosing(ex_dat) %>% kable
The first dose record starts the repeated dosing interval. Then we have 3 additional doses leading up to the PK day. We should see ADDL dosing starting on 1/2@9:15am and running for 8 additional doses. Then the individual doses should show up. I doesn't matter that they are still marked with II=24... unless there is a large enough gap to restart ADDL sequencing.
Input Data:
ex_dat <- tibble::tribble( ~ID, ~TIME, ~TRT, ~AMT, ~FREQ, ~MEX, ~II, ~EVID, 1, "01/01/2017 10:00", "A", 100, "QD", FALSE, 24, 1, 1, "01/11/2017 09:15", "A", 100, "QD", FALSE, 24, 1, 1, "01/12/2017 05:21", "A", 100, "QD", FALSE, 24, 1, 1, "01/13/2017 17:37", "A", 100, "QD", FALSE, 24, 1 ) %>% dplyr::mutate( TIME = iso_to_posix(TIME) ) ex_dat %>% kable
BUT THERE IS A GAP HERE, the dosing period from 1/12 to 1/13 is over 36 hours so we get an ADDL dose filling in on 1/12!
get_addl_dosing(ex_dat) %>% kable
The first dose record starts the repeated dosing interval. Then we have 3 additional doses leading up to the PK day. We should see ADDL dosing starting on 1/2@9:15am and running for 8 additional doses. Then the individual doses should show up. Now the final dose is marked with FREQ=ONCE (which get's translated in mappings to II=0) so it won't allow ADDL sequencing running up to it.
Input Data:
ex_dat <- tibble::tribble( ~ID, ~TIME, ~TRT, ~AMT, ~FREQ, ~MEX, ~II, ~EVID, 1, "01/01/2017 10:00", "A", 100, "QD", FALSE, 24, 1, 1, "01/11/2017 09:15", "A", 100, "QD", FALSE, 24, 1, 1, "01/12/2017 05:21", "A", 100, "QD", FALSE, 24, 1, 1, "01/13/2017 17:37", "A", 100, "ONCE", FALSE, 0, 1 ) %>% dplyr::mutate( TIME = iso_to_posix(TIME) ) ex_dat %>% kable
ADDL sequencing runs between doses marked with II>0. A dose with II==0 is a single dose and ADDL sequencing won't run to it - even if the previous dose is marked with II>0.
NOTE: this may be something we want to change. It doesn't affect timing of ADDL, but it does affect how we tag the EX data II values. It may be difficult to figure out the FREQ/II values.
get_addl_dosing(ex_dat) %>% kable
The first dose record starts the repeated dosing interval. Then we have 3 additional doses leading up to the PK day. We should see ADDL dosing starting on 1/2@9:15am and running for 8 additional doses. Then we have the missed dose recorded on 1/12 at the same clock time as the previous dose (this is determined in mappings, since the missed dose is probably missing a time in EXSTDTC). Note that we have to enter AMT=0 for the missed dose.
Input Data:
ex_dat <- tibble::tribble( ~ID, ~TIME, ~TRT, ~AMT, ~FREQ, ~MEX, ~II, ~EVID, 1, "01/01/2017 10:00", "A", 100, "QD", FALSE, 24, 1, 1, "01/11/2017 09:15", "A", 100, "QD", FALSE, 24, 1, 1, "01/12/2017 09:15", "A", 0, "QD", TRUE, 24, 1, 1, "01/13/2017 08:37", "A", 100, "QD", FALSE, 24, 1 ) %>% dplyr::mutate( TIME = iso_to_posix(TIME) ) ex_dat %>% kable
As expected, the ADDL dosing fills in between 1/2 and 1/10 only and lines up with 1/11 dose time. Missed dose on 1/12 is backfilled by ADDL from 1/13 but is AMT 0.
get_addl_dosing(ex_dat) %>% kable
Starting in CYCLE1 with QD dosing until day 11. Then restart in CYCLE2 on 2/1 until 2/13.
Input Data:
ex_dat <- tibble::tribble( ~ID, ~TIME, ~CYCLE, ~AMT, ~FREQ, ~MEX, ~II, ~EVID, 1, "01/01/2017 10:00", "CYCLE1", 100, "QD", FALSE, 24, 1, 1, "01/11/2017 09:15", "CYCLE1", 100, "QD", FALSE, 24, 1, 1, "02/01/2017 09:15", "CYCLE2", 100, "QD", FALSE, 24, 1, 1, "02/13/2017 08:37", "CYCLE2", 100, "QD", FALSE, 24, 1 ) %>% dplyr::mutate( TIME = iso_to_posix(TIME) ) ex_dat %>% kable
Output:
ex_dat %>% group_by(ID,CYCLE) %>% get_addl_dosing() %>% kable
The first dose record starts the repeated dosing interval for 31 days. But we have 2 missing doses. We should see ADDL dosing starting on 1/2@8:37am and running for 8 additional doses. Then we have the missed dose recorded on 1/12 at the same clock time as the previous dose (this is determined in mappings, since the missed dose is probably missing a time in EXSTDTC). Note that we have to enter AMT=0 for the missed dose. After last missed dose, ADDL is restarted with 17 additional doses to arrive at 1/30.
Input Data:
ex_dat <- tibble::tribble( ~ID, ~TIME, ~TRT, ~AMT, ~FREQ, ~MEX, ~II, ~EVID, 1, "01/01/2017 10:00", "A", 100, "QD", FALSE, 24, 1, 1, "01/11/2017 09:15", "A", 0, "QD", TRUE, 24, 1, 1, "01/12/2017 09:15", "A", 0, "QD", TRUE, 24, 1, 1, "01/31/2017 08:37", "A", 100, "QD", FALSE, 24, 1 ) %>% dplyr::mutate( TIME = iso_to_posix(TIME) ) ex_dat %>% kable
get_addl_dosing(ex_dat) %>% kable
The first dose record starts the repeated dosing interval for 31 days. But we have 2 missing doses. We should see ADDL dosing starting on 1/1@8:37pm (the eveing dose) and running for 18 additional doses. Then we have the missed doses recorded on 1/11, at the expected dose times for morning and evening dosing (8am/8pm). Note that we have to enter AMT=0 for the missed dose.
Input Data:
ex_dat <- tibble::tribble( ~ID, ~TIME, ~TRT, ~AMT, ~FREQ, ~MEX, ~II, ~EVID, 1, "01/01/2017 10:00", "A", 100, "BID", FALSE, 12, 1, 1, "01/11/2017 08:00", "A", 0, "BID", TRUE, 12, 1, 1, "01/11/2017 20:00", "A", 0, "BID", TRUE, 12, 1, 1, "01/31/2017 08:37", "A", 100, "BID", FALSE, 12, 1 ) %>% dplyr::mutate( TIME = iso_to_posix(TIME) ) ex_dat %>% kable
Output:
get_addl_dosing(ex_dat) %>% kable
In compartment 1, the first dose record starts the repeated dosing interval. Then we have 3 additional doses leading up to the PK day. We should see ADDL dosing starting on 1/2@9:15am and running for 8 additional doses. Then the individual doses should show up. It doesn't matter that they are still marked with II=24... unless there is a large enough gap to restart ADDL sequencing. The second compartment dose starts later in the day on 1/1 and runs BID through the end of the month.
Input Data:
ex_dat <- tibble::tribble( ~ID, ~TIME, ~CMT, ~AMT, ~FREQ, ~MEX, ~II, ~EVID, 1, "01/01/2017 10:00", 1, 100, "QD", FALSE, 24, 1, 1, "01/01/2017 15:55", 2, 50, "BID", FALSE, 12, 1, 1, "01/11/2017 09:15", 1, 100, "QD", FALSE, 24, 1, 1, "01/12/2017 10:21", 1, 100, "QD", FALSE, 24, 1, 1, "01/13/2017 08:37", 1, 100, "QD", FALSE, 24, 1, 1, "01/31/2017 12:43", 2, 50, "BID", FALSE, 12, 1 ) %>% dplyr::mutate( TIME = iso_to_posix(TIME) ) ex_dat %>% kable
As expected, the ADDL dosing fills in between 1/2 and 1/10 only and lines up with 1/11 dose time. For compartment two we get BID dosing ending on 12:43. The sequences compute separately.
ex_dat %>% group_by(CMT) %>% get_addl_dosing() %>% kable
Expand ADDL requires an ID column.
ex1 = data_frame(ID=1, TIME=c("2018-01-01T08:15","2018-01-10T10:45"), AMT=100, EVID=1, II=24, MEX=FALSE) %>% mutate(TIME=iso_to_posix(TIME)) %>% get_addl_dosing()
Starting with ADDL dosing records:
ex1 %>% kable
we can expand ADDL:
ex1 %>% expand_addl() %>% kable
The expanded records have ADDL set to -1. When using these records with NONMEM be sure to drop II and ADDL or set them to zero.
The time_after_dose function takes ADDL into account. With the following data, we expect the TAD for the observation on 1/4 to be 2 hours after the 1/4 dose and not 38 hours after the 1/1 dose.
input <- tibble::tribble( ~ID, ~TIME, ~TRT, ~AMT, ~II, ~EVID, ~ADDL, ~CRE, 1, "01/01/2017 10:00", "A", 100, 0, 1, 0, 0.3, 1, "01/01/2017 18:00", "A", 0 , 0, 0, 0, 0.3, 1, "01/02/2017 10:00", "A", 100, 24, 1, 8, 0.2, 1, "01/04/2017 12:00", "A", 0 , 0, 0, 0, 0.2, 1, "01/11/2017 10:00", "A", 100, 0, 1, 0, 0.5, 1, "01/11/2017 12:00", "A", 0 , 0, 0, 0, 0.5, 1, "01/11/2017 14:00", "A", 0 , 0, 0, 0, 0.5 ) %>% dplyr::mutate( TIME = iso_to_posix(TIME) ) input %>% time_after_dose() %>% select(-DOSENUM__) %>% kable
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.