Working with dose selectors

Travis build status Codecov test coverage cran version

The escalation package by Kristian Brock. Documentation is hosted at https://brockk.github.io/escalation/

Introduction

To provide dose selection decisions, the escalation package daisy-chains together objects that support a common interface, each deriving from type selector. This vignette demonstrates the entire interface supported by selector objects. For the purpose of illustratration, we use a BOIN selector but the same functions will work on every type of dose selector in escalation.

library(escalation)
model <- get_boin(num_doses = 5, target = 0.3)
fit <- model %>% fit('1NN 2NN 3NT 2NT')

Supported Interface

Target toxicity rate:

tox_target(fit)
#> [1] 0.3

The number of patients treated:

num_patients(fit)
#> [1] 8

Cohort IDs for the treated patients:

cohort(fit)
#> [1] 1 1 2 2 3 3 4 4

The code infers from the spaces in the outcome string that a dose-decision was made after the second, fourth , and sixth patients.

Integers representing the dose-levels given:

doses_given(fit)
#> [1] 1 1 2 2 3 3 2 2

Bits representing whether toxicity event was observed:

tox(fit)
#> [1] 0 0 0 0 0 1 0 1

The total number of toxicities seen at all doses combined:

num_tox(fit)
#> [1] 2

A data-frame containing the above information:

model_frame(fit)
#> # A tibble: 8 x 4
#>   patient cohort  dose   tox
#>     <int>  <int> <int> <int>
#> 1       1      1     1     0
#> 2       2      1     1     0
#> 3       3      2     2     0
#> 4       4      2     2     0
#> 5       5      3     3     0
#> 6       6      3     3     1
#> 7       7      4     2     0
#> 8       8      4     2     1

The number of doses under investigation:

num_doses(fit)
#> [1] 5

The indices of the dose-levels under investigation:

dose_indices(fit)
#> [1] 1 2 3 4 5

The dose-level recommended for the next patient:

recommended_dose(fit)
#> [1] 2

After seeing some toxicity at doses 2 and 3, the design sensibly sticks at dose 2 for the time being.

A logical value for whether accrual should continue:

continue(fit)
#> [1] TRUE

We infer from this that no stopping condition has yet been triggered.

The number of patients treated at each dose:

n_at_dose(fit)
#> [1] 2 4 2 0 0

The number of patients treated at the recommended dose:

n_at_recommended_dose(fit)
#> [1] 4

The proportion of patients treated at each dose:

prob_administer(fit)
#>    1    2    3    4    5 
#> 0.25 0.50 0.25 0.00 0.00

The total number of toxicities seen at each dose:

tox_at_dose(fit)
#> [1] 0 1 1 0 0

The empirical toxicity rate, i.e. the number of toxicities divided by the number of patients:

empiric_tox_rate(fit)
#> [1] 0.00 0.25 0.50  NaN  NaN

The model-derived expected toxicity rate at each dose:

mean_prob_tox(fit)
#> [1] 0.02 0.26 0.50   NA   NA

The BOIN design makes no estimate for doses it has not yet administered.

The model-derived median toxicity rate at each dose:

median_prob_tox(fit)
#>    1    2    3    4    5 
#> 0.01 0.21 0.50   NA   NA

BOIN does not actually calculate posterior median estimates. Sometimes it will be necessary to return missing values if functionality is not supported by a model. Median estimates could be added to the BOIN class in due course.

The model-derived quantile of the toxicity rate at each dose:

prob_tox_quantile(fit, 0.9)
#>    1    2    3    4    5 
#> 0.05 0.54 0.89   NA   NA

BOIN does not calculate this either. It could also be added.

The posterior probability that the toxicity rate exceeds some threshold value, here 50%:

prob_tox_exceeds(fit, 0.5)
#> [1] 0.009391185 0.129051871 0.500000000          NA          NA

Once again, no estimate is made for non-administered doses. We see that the model estimates a trivial chance that the toxicity rate at the lowest dose exceeds 50%.

Learn if this model supports sampling from the posterior:

supports_sampling(fit)
#> [1] FALSE

The BOIN model does not support sampling. If it did, we could run prob_tox_samples(fit).

We can also call some standard generic functions:

print(fit)
#> Patient-level data:
#> # A tibble: 8 x 4
#>   Patient Cohort  Dose   Tox
#>     <int>  <int> <int> <int>
#> 1       1      1     1     0
#> 2       2      1     1     0
#> 3       3      2     2     0
#> 4       4      2     2     0
#> 5       5      3     3     0
#> 6       6      3     3     1
#> 7       7      4     2     0
#> 8       8      4     2     1
#> 
#> Dose-level data:
#> # A tibble: 5 x 6
#>    Dose     N   Tox EmpiricToxRate MeanProbTox MedianProbTox
#>   <int> <int> <int>          <dbl>       <dbl>         <dbl>
#> 1     1     2     0           0           0.02          0.01
#> 2     2     4     1           0.25        0.26          0.21
#> 3     3     2     1           0.5         0.5           0.5 
#> 4     4     0     0         NaN          NA            NA   
#> 5     5     0     0         NaN          NA            NA   
#> 
#> The model targets a toxicity level of 0.3.
#> The model advocates continuing at dose 2.
summary(fit)
#> # A tibble: 5 x 6
#>    Dose     N   Tox EmpiricToxRate MeanProbTox MedianProbTox
#>   <int> <int> <int>          <dbl>       <dbl>         <dbl>
#> 1     1     2     0           0           0.02          0.01
#> 2     2     4     1           0.25        0.26          0.21
#> 3     3     2     1           0.5         0.5           0.5 
#> 4     4     0     0         NaN          NA            NA   
#> 5     5     0     0         NaN          NA            NA

and cast it to a tidyverse tibble:

library(tibble)

as_tibble(fit)
#> # A tibble: 6 x 7
#>   dose     tox     n empiric_tox_rate mean_prob_tox median_prob_tox recommended
#>   <ord>  <dbl> <dbl>            <dbl>         <dbl>           <dbl> <lgl>      
#> 1 NoDose     0     0             0             0               0    FALSE      
#> 2 1          0     2             0             0.02            0.01 FALSE      
#> 3 2          1     4             0.25          0.26            0.21 TRUE       
#> 4 3          1     2             0.5           0.5             0.5  FALSE      
#> 5 4          0     0           NaN            NA              NA    FALSE      
#> 6 5          0     0           NaN            NA              NA    FALSE