Type: | Package |
Title: | Clinical Trial Simulator |
Version: | 1.0.0 |
Description: | Simulate phase II and/or phase III clinical trials. It supports various types of endpoints and adaptive strategies. Tools for carrying out graphical testing procedure and combination test under group sequential design are also provided. |
License: | MIT + file LICENSE |
Encoding: | UTF-8 |
Imports: | base64enc, dplyr, emmeans, ggplot2, gMCPLite, htmltools, mvtnorm, R6, rlang, rpact, rstudioapi, survival, utils |
RoxygenNote: | 7.3.2 |
Suggests: | DoseFinding, graphicalMCP, kableExtra, knitr, rmarkdown, simdata, survminer, testthat (≥ 3.0.0) |
VignetteBuilder: | knitr |
URL: | https://zhangh12.github.io/TrialSimulator/ |
BugReports: | https://github.com/zhangh12/TrialSimulator/issues |
Depends: | R (≥ 4.1.0) |
Config/testthat/edition: | 3 |
NeedsCompilation: | no |
Packaged: | 2025-08-29 06:25:20 UTC; zhhan |
Author: | Han Zhang [cre, aut] |
Maintainer: | Han Zhang <zhangh.ustc@gmail.com> |
Repository: | CRAN |
Date/Publication: | 2025-09-03 20:50:13 UTC |
Class of Arm
Description
Create a class of arm.
Methods
Public methods
Method new()
initialize an arm
Usage
Arms$new(name, ...)
Arguments
name
name of arm, which is the arm's label in generated data
...
subset condition that is compatible with
dplyr::filter
. This can be used to specify inclusion criteria of an arm. By default it is not specified, i.e. all data generated by the generator specified in...
.
Method add_endpoints()
add a list of endpoints to the arm
Usage
Arms$add_endpoints(...)
Arguments
...
one or more objects of class
Endpoint
Method get_name()
return name of arm
Usage
Arms$get_name()
Method get_number_endpoints()
return number of endpoints in the arm
Usage
Arms$get_number_endpoints()
Method has_endpoint()
check if the arm has any endpoint. Return TRUE
or FALSE
.
Usage
Arms$has_endpoint()
Method get_endpoints()
return a list of endpoints in the arm
Usage
Arms$get_endpoints()
Method get_endpoints_name()
return name of endpoints registered to the arm
Usage
Arms$get_endpoints_name()
Method generate_data()
generate arm data
Usage
Arms$generate_data(n_patients_in_arm)
Arguments
n_patients_in_arm
integer. Number of patients randomized to the arm
Method print()
print an arm
Usage
Arms$print(categorical_vars = NULL)
Arguments
categorical_vars
categorical_vars character. Vector of categorical variables. This can be used to specify variables with limited distinct values as categorical variables in summary.
Method clone()
The objects of this class are cloneable with this method.
Usage
Arms$clone(deep = FALSE)
Arguments
deep
Whether to make a deep clone.
Examples
# Instead of using Arm$new, please use arm(), a user-friendly
# wrapper. See examples in ?arm
Class of Controller
Description
Create a class of controller to run a trial.
Methods
Public methods
Method new()
initialize a controller of the trial
Usage
Controllers$new(trial, listener)
Arguments
trial
a
Trials
object.listener
a
Listeners
object.
Method get_listener()
return listener
Usage
Controllers$get_listener()
Method get_trial()
return trial
Usage
Controllers$get_trial()
Method mute()
mute all messages (not including warnings)
Usage
Controllers$mute()
Arguments
silent
logical.
Method reset()
reset the trial and listener registered to the controller before running additional replicate of simulation.
Usage
Controllers$reset()
Method get_output()
return a data frame of all current outputs saved by calling save
.
Usage
Controllers$get_output(cols = NULL, simplify = TRUE)
Arguments
cols
columns to be returned from
Controller$output
. IfNULL
, all columns are returned.simplify
logical. Return value rather than a data frame of one column when
length(col) == 1
andsimplify == TRUE
.
Method run()
run a trial
Usage
Controllers$run(n = 1, plot_event = TRUE, silent = FALSE, dry_run = FALSE)
Arguments
n
number of replicates of simulation.
n = 1
by default. Simulation results can be accessed byController$get_output()
.plot_event
create event plot
silent
logical.
TRUE
if muting all messages during a trial. Note that warning messages are still displayed.dry_run
TRUE
if action function provided by users is ignored and a built-in default actiondefault_action
is called instead. This default function only locks data when the milestone is triggered. Milestone time and number of endpoints' events or sample sizes are saved. It is suggested to setdry_run = TRUE
to estimate distributions of triggering time and number of events before formally using custom action functions if a fixed design is in use. This helps determining planned maximum information for group sequential design and reasonable time of milestone of interest when planning a trial. Set it toFALSE
for formal simulations. However, for an adaptive design where arm(s) could possibly be added or removed, settingdry_run
toTRUE
is usually not helpful because adaption should be actually applied to estimate milestone time.
Method clone()
The objects of this class are cloneable with this method.
Usage
Controllers$clone(deep = FALSE)
Arguments
deep
Whether to make a deep clone.
Examples
##
Generate PFS and OS using the three-states model
Description
Generate PFS and OS using the three-states model
Usage
CorrelatedPfsAndOs3(n, h01, h02, h12, pfs_name = "pfs", os_name = "os")
Arguments
n |
integer. Number of observations. |
h01 |
constant transition hazard from state "stable" to state "progression". |
h02 |
constant transition hazard from state "stable" to state "death". |
h12 |
constant transition hazard from state "progression" to state "death". |
pfs_name |
column name of PFS in returned data frame. It must be consistent with 'name' in the function 'endpoint()'. |
os_name |
column name of OS in returned data frame. It must be consistent with 'name' in the function 'endpoint()'. |
Value
A data frame of four columns, including PFS, OS and their event indicators. The event indicators are all 1s.
Examples
pfs_and_os_trt <- CorrelatedPfsAndOs3(1e4, 0.06, 0.30, 0.30, 'PFS', 'OS')
pfs_and_os_pbo <- CorrelatedPfsAndOs3(1e4, 0.10, 0.40, 0.30, 'PFS', 'OS')
Generate PFS, OS and objective response using the four-states model
Description
Generate PFS, OS and objective response using the four-states model
Usage
CorrelatedPfsAndOs4(
n,
transition_probability,
duration,
death_name = "death",
progression_name = "progression",
response_name = "response"
)
Arguments
n |
integer. Number of observations. |
transition_probability |
a 4x4 matrix defining transition probabilities between stable (initial state, 1), response (2), progression (3) and death (absorbing, 4). |
duration |
integer. Duration of trial. Set it to a sufficient large integer in practice to cover the duration of the trial (potentially be extended). |
death_name |
column name of OS in returned data frame. It must be consistent with 'name' in the function 'endpoint()'. |
progression_name |
column name of PFS in returned data frame. It must be consistent with 'name' in the function 'endpoint()'. |
response_name |
column name of objective response in returned data frame. It must be consistent with 'name' in the function 'endpoint()'. |
Value
A data frame of n
rows and 6 columns (response, progression,
death, and their event indicators response_event, progression_event,
death_event with 1 means event and 0 means censored at duration).
Examples
m <- matrix(c(0.99, 0.0035, 0.0055, 0.0010,
0, 0.9900, 0.0052, 0.0048,
0, 0, 0.9960, 0.0040,
0, 0, 0, 1),
nrow = 4, byrow = TRUE)
pfs_and_os <- CorrelatedPfsAndOs4(1e4, m, 365 * 3)
A wrapper of random number generator.
Description
A wrapper of random number generator.
Usage
DynamicRNGFunction(fn, ...)
Arguments
fn |
random number generator, e.g., rnorm, rchisq, etc. It can be user-defined random number generator as well, e.g., PiecewiseConstantExponentialRNG |
... |
arguments for |
Value
a function to generate random number based on 'fn' and arguments in '...'. Specified arguments will be fixed and cannot be changed when invoking 'DynamicRNGFunction(fn, ...)()'. For example, if 'foo <- DynamicRNGFunction(rnorm, sd = 2)', then 'foo(n = 100)' will always generate data from normal distribution of variance 4. 'foo(n = 100, sd = 1)' will trigger an error. However, if an argument is not specified in 'DynamicRNGFunction', then it can be specified later. For example, 'foo(n = 100, mean = -1)' will generate data from N(-1, 4).
Examples
# example code
dfunc <- DynamicRNGFunction(rnorm, sd = 3.2)
x <- dfunc(1e3)
hist(x)
Class of Endpoint
Description
Create a class of endpoint to specify its name, type and assign a random number generator.
Methods
Public methods
Method new()
initialize an endpoint
Usage
Endpoints$new(name, type = c("tte", "non-tte"), readout = NULL, generator, ...)
Arguments
name
character vector. Name(s) of endpoint(s)
type
character vector. Type(s) of endpoint(s). It supports
"tte"
for time-to-event endpoints, and"non-tte"
for all other types of endpoints (e.g., continous, binary, categorical, or repeated measurement.TrialSimulator
will do some verification if an endpoint is of type"tte"
. However, no special manipulation is done for non-tte endpoints.readout
numeric vector with name to be the non-tte endpoint(s).
readout
should be specified for every non-tte endpoint. For example,c(endpoint1 = 6, endpoint2 = 3)
. If all endpoints are tte,readout
can beNULL
.generator
a RNG function. Its first argument must be 'n', number of patients. It must return a data frame of 'n' rows. It support all built-in random number generators in
stats
, e.g.,stats::rnorm
,stats::rexp
, etc. that withn
as the argument for number of observations.generator
could be any custom functions as long as (1) its first argument isn
; and (2) it returns a vector of lengthn
or a data frame ofn
rows. Custom random number generator can return data of more than one endpoint. This is useful when users need to simulate correlated endpoints. The column names of returned data frame should match toname
exactly. If an endpoint is of type"tte"
, the customgenerator
should also return a column as event indicator. For example, if"pfs"
is"tte"
, then customgenerator
should return at least two columns"pfs"
and"pfs_event"
. Usuallypfs_event
can be all 1s if no censoring. Censoring can be specified later when defining theTrial
through argumentdropout
. See?Trial
. Note that if covariates, e.g., biomarker, subgroup, are needed in generating and analyzing trial data, they can be defined asEndpoint
as well....
optional arguments for
generator
.
Method test_generator()
test random number generator of the endpoints. It returns an example dataset.
Usage
Endpoints$test_generator(n = 1000)
Arguments
n
integer. Number of random numbers generated from the generator.
Method get_generator()
return random number generator of an endpoint
Usage
Endpoints$get_generator()
Method get_readout()
return readout function
Usage
Endpoints$get_readout()
Method get_uid()
return uid
Usage
Endpoints$get_uid()
Method get_name()
return endpoints' name
Usage
Endpoints$get_name()
Method get_type()
return endpoints' type
Usage
Endpoints$get_type()
Method print()
print an endpoint object
Usage
Endpoints$print(categorical_vars = NULL)
Arguments
categorical_vars
categorical_vars character. Vector of categorical variables. This can be used to specify variables with limited distinct values as categorical variables in summary.
Method clone()
The objects of this class are cloneable with this method.
Usage
Endpoints$clone(deep = FALSE)
Arguments
deep
Whether to make a deep clone.
Examples
# Instead of using Endpoint$new, please use endpoint(), a user-friendly
# wrapper. See examples in ?endpoint.
Class of GraphicalTesting
Description
Perform graphical testing under group sequential design for one or multiple endpoints. See Maurer & Bretz (2013).
Methods
Public methods
Method new()
Initialize an object for graphical testing procedure. Group sequential design is also supported.
Usage
GraphicalTesting$new( alpha, transition, alpha_spending, planned_max_info, hypotheses = NULL, silent = FALSE )
Arguments
alpha
initial alpha allocated to each of the hypotheses.
transition
matrix of transition weights. Its diagonals should be all 0s. The row sums should be 1s (for better power) or 0s (if no outbound edge from a node).
alpha_spending
character vector of same length of
alpha
. Currently it supports'asP'
,'asOF'
, and'asUser'
.planned_max_info
vector of integers. Maximum numbers of events (tte endpoints) or patients (non-tte endpoints) at the final analysis of each hypothesis when planning a trial. The actual numbers could be different, which can be specified elsewhere.
hypotheses
vector of characters. Names of hypotheses.
silent
TRUE
if muting all messages and not generating plots.
Method reset()
reset an object of class GraphicalTesting
to original status
so that it can be reused.
Usage
GraphicalTesting$reset()
Method is_valid_hid()
determine if index of a hypothesis is valid
Usage
GraphicalTesting$is_valid_hid(hid)
Arguments
hid
an integer
Method get_hypothesis_name()
get name of a hypothesis given its index.
Usage
GraphicalTesting$get_hypothesis_name(hid)
Arguments
hid
an integer
Method get_weight()
return weight between two nodes
Usage
GraphicalTesting$get_weight(hid1, hid2)
Arguments
hid1
an integer
hid2
an integer
Method set_weight()
update weight between two nodes
Usage
GraphicalTesting$set_weight(hid1, hid2, value)
Arguments
hid1
an integer
hid2
an integer
value
numeric value to be set as a weight two nodes
Method get_alpha()
return alpha allocated to a hypothesis when calling this function.
Note that a function can be called several time with the graph is
updated dynamically. Thus, returned alpha can be different even for
the same hid
.
Usage
GraphicalTesting$get_alpha(hid)
Arguments
hid
an integer
Method set_alpha()
update alpha of a hypothesis
Usage
GraphicalTesting$set_alpha(hid, value)
Arguments
hid
integer. Index of a hypothesis
value
numeric value to be allocated
Method get_hypotheses_ids()
return all valid hid
Usage
GraphicalTesting$get_hypotheses_ids()
Method get_number_hypotheses()
return number of hypotheses, including those been rejected.
Usage
GraphicalTesting$get_number_hypotheses()
Method get_hids_not_in_graph()
return index of hypotheses that are rejected.
Usage
GraphicalTesting$get_hids_not_in_graph()
Method get_testable_hypotheses()
return index of hypotheses with non-zero alphas, thus can be tested at the current stage.
Usage
GraphicalTesting$get_testable_hypotheses()
Method has_testable_hypotheses()
determine whether at least one hypothesis is testable.
If return FALSE
, the testing procedure is completed.
Usage
GraphicalTesting$has_testable_hypotheses()
Method is_in_graph()
determine whether a hypothesis is not yet rejected (in graph).
Usage
GraphicalTesting$is_in_graph(hid)
Arguments
hid
integer. Index of a hypothesis
Method is_testable()
determine whether a hypothesis has a non-zero alpha allocated.
Usage
GraphicalTesting$is_testable(hid)
Arguments
hid
integer. Index of a hypothesis
Method get_hid()
convert hypothesis's name into (unique) index.
Usage
GraphicalTesting$get_hid(hypothesis)
Arguments
hypothesis
character. Name of a hypothesis. It is different from
hid
, which is an index.
Method reject_a_hypothesis()
remove a node from graph when a hypothesis is rejected
Usage
GraphicalTesting$reject_a_hypothesis(hypothesis)
Arguments
hypothesis
name of a hypothesis. It is different from
hid
, which is an index.
Method set_trajectory()
save new testing results at current stage
Usage
GraphicalTesting$set_trajectory(result)
Arguments
result
a data frame of specific columns.
Method get_trajectory()
return testing results by the time this function is called. Note that graphical test is carried out in a sequential manner. Users may want to review the results anytime. Value returned by this function can possibly vary over time.
Usage
GraphicalTesting$get_trajectory()
Method test_hypotheses()
test hypotheses using p-values (and other information in stats
)
base on the current graph. All rows should have the same order
number.
Usage
GraphicalTesting$test_hypotheses(stats)
Arguments
stats
a data frame. It must contain the following columns:
order
integer. P-values (among others) of hypotheses that can be tested at the same time (e.g., an interim, or final analysis) should be labeled with the same order number. If a hypothesis is not tested at a stage, simply don't put it in
stats
with that order number.hypotheses
character. Name of hypotheses to be tested. They should be identical to those when calling
GraphicalTesting$new
.p
nominal p-values.
info
observed number of events or samples at test. These will be used to compute information fractions in group sequential design.
max_info
integers. Maximum information at test. At interim,
max_info
should be equal toplanned_max_info
when callingGraphicalTesting$new
. At the final stage of a hypothesis, one can update it with observed numbers.
Method test()
test hypotheses using p-values (and other information in stats
)
base on the current graph. Users can call this function multiple times.
P-values of the same order should be passed through stats
together. P-values of multiple orders can be passed together as well.
For example, if users only have p-values at current stage, they can call
this function and update the graph accordingly. In this case, column
order
in stats
is a constant. They can call this
function again when p-values of next stage is available, where
order
is another integer. In simulation, if p-values of all
stages are on hand, users can call this function to
test them all in a single pass. In this case, column order
in
stats
can have different values.
Usage
GraphicalTesting$test(stats)
Arguments
stats
a data frame. It must contain the following columns:
order
integer. P-values (among others) of hypotheses that can be tested at the same time (e.g., an interim, or final analysis) should be labeled with the same order number. If a hypothesis is not tested at a stage, simply don't put it in
stats
with that order number. If all p-values instats
are tested at the same stage,order
can be absent.hypotheses
character. Name of hypotheses to be tested. They should be identical to those when calling
GraphicalTesting$new
.p
nominal p-values.
info
observed number of events or samples at test. These will be used to compute information fractions in group sequential design.
max_info
integers. Maximum information at test. At interim,
max_info
should be equal toplanned_max_info
when callingGraphicalTesting$new
. At the final stage of a hypothesis, one can update it with observed numbers.alpha_spent
accumulative proportion of allocated alpha to be spent if
alpha_spending = "asUser"
. Set it toNA_real_
otherwise. If no hypothesis uses"asUser"
instats
, this column could be ignored.
Returns
a data frame returned by get_current_testing_results
.
It contains details of each of the testing steps.
Method get_current_testing_results()
return testing results with details by the time this function
is called. This function can be called by users by multiple
times, thus the returned value varies over time.
This function is called by GraphicalTesting::test
,
and returns a data frame consisting of columns
hypothesis
name of hypotheses.
obs_p_value
observed p-values.
max_allocated_alpha
maximum allocated alpha for the hypothesis.
decision
'reject'
or'accept'
the hypotheses.stages
stage of a hypothesis.
order
order number that this hypothesis is tested for the last time. It is different from
stages
.typeOfDesign
name of alpha spending functions.
Usage
GraphicalTesting$get_current_testing_results()
Method get_current_decision()
get current decisions for all hypotheses. Returned value could changes over time because it depends on the stages being tested already.
Usage
GraphicalTesting$get_current_decision()
Returns
a named vector of values "accept"
or "reject"
.
Note that if a hypothesis is not yet tested when calling this function,
the decision for that hypothesis would be "accept"
.
Method print()
generic function for print
Usage
GraphicalTesting$print(graph = TRUE, trajectory = TRUE, ...)
Arguments
graph
logic.
TRUE
if visualizing the current graph, which can vary over time.trajectory
logic.
TRUE
if print the current data frame of trajectory, which can vary over time....
other arguments supported in
gMCPLite::hGraph
, e.g.,trhw
andtrhh
to control the size of transition box, andtrdigits
to control the digits displayed for transition weights.
Method clone()
The objects of this class are cloneable with this method.
Usage
GraphicalTesting$clone(deep = FALSE)
Arguments
deep
Whether to make a deep clone.
Examples
## Example 1
## dry-run to study the behavior of a graph
## without group sequential design
if(interactive()){
eps <- .01
alpha <- c(.01, .04, 0, 0, 0)
transition <- matrix(c(
0, 0, 0, 0, 1,
0, 0, .75, 0, .25,
0, 1/2-eps/2, 0, eps, 1/2-eps/2,
0, 0, 0, 0, 0,
0, 1/2, 1/2, 0, 0
), nrow = 5, byrow = TRUE)
## dummy can be anything, we don't actually use it
asf <- rep('asOF', 5)
## dummy can be anything, we don't actually use it
max_info <- c(300, 1100, 1100, 1100, 500)
hs <- c('H1: UPCR IgA', 'H2: eGFR GN', 'H3: eGFR GN 10wk', 'H5: 2nd Endpoints', 'H4: eGFR IgA')
## initialize an object
gt <- GraphicalTesting$new(alpha, transition, asf, max_info, hs)
print(gt)
## reject hypotheses based on customized order
## to understand the behavior of a testing strategy
## Any other rejection order is possible
gt$reject_a_hypothesis('H1: UPCR IgA')
print(gt)
gt$reject_a_hypothesis('H2: eGFR GN')
print(gt)
gt$reject_a_hypothesis('H4: eGFR IgA')
print(gt)
gt$reject_a_hypothesis('H3: eGFR GN 10wk')
print(gt)
gt$reset()
}
## Example 2
## Example modified from vignettes in gMCPLite:
## Graphical testing for group sequential design
if(interactive()){
## initial alpha split to each of the hypotheses
alpha <- c(.01, .01, .004, .0, .0005, .0005)
## transition matrix of the initial graph
transition <- matrix(c(
0, 1, 0, 0, 0, 0,
0, 0, .5, .5, 0, 0,
0, 0, 0, 1, 0, 0,
0, 0, 0, 0, .5, .5,
0, 0, 0, 0, 0, 1,
.5, .5, 0, 0, 0, 0
), nrow = 6, byrow = TRUE)
## alpha spending functions per hypothesis
asf <- c('asUser', 'asOF', 'asUser', 'asOF', 'asOF', 'asOF')
## planned maximum number of events per hypothesis
max_info <- c(295, 800, 310, 750, 500, 1100)
## name of hypotheses
hs <- c('H1: OS sub',
'H2: OS all',
'H3: PFS sub',
'H4: PFS all',
'H5: ORR sub',
'H6: ORR all')
gt <- GraphicalTesting$new(alpha, transition, asf, max_info, hs)
## print initial graph
gt
## nominal p-values at each stage
## Note: p-values with same order are calculated with the same locked data
## Note: alpha_spent is only specified for hypotheses using custom alpha
## spending function "asUser"
stats <-
data.frame(
order = c(1:3, 1:3, 1:2, 1:2, 1, 1),
hypotheses = c(rep('H1: OS sub', 3), rep('H2: OS all', 3),
rep('H3: PFS sub', 2), rep('H4: PFS all', 2),
'H5: ORR sub', 'H6: ORR all'),
p = c(.03, .0001, .000001, .2, .15, .1, .2, .001, .3, .2, .00001, .1),
info = c(185, 245, 295, 529, 700, 800, 265, 310, 675, 750, 490, 990),
is_final = c(F, F, T, F, F, T, F, T, F, T, T, T),
max_info = c(rep(295, 3), rep(800, 3), rep(310, 2), rep(750, 2), 490, 990),
alpha_spent = c(c(.1, .4, 1), rep(NA, 3), c(.3, 1), rep(NA, 2), NA, NA)
)
## test the p-values from the first analysis, plot the updated graph
gt$test(stats %>% dplyr::filter(order==1))
## test the p-values from the second analysis, plot the updated graph
gt$test(stats %>% dplyr::filter(order==2))
## test the p-values from the third analysis, plot the updated graph
## because no futher test would be done, displayed results are final
gt$test(stats %>% dplyr::filter(order==3))
## plot the final status of the graph
print(gt, trajectory = FALSE)
## you can get final testing results as follow
gt$get_current_testing_results()
## if you want to see step-by-step details
print(gt$get_trajectory())
## equivalently, you can call gt$test(stats) for only once to get same results.
gt$reset()
gt$test(stats)
## if you only want to get the final testing results
gt$get_current_decision()
}
Class of GroupSequentialTest
Description
Perform group sequential test for a single endpoint based on sequential one-sided p-values at each stages. Selected alpha spending functions, including user-defined functions, are supported. Boundaries are calculated with 'rpact'. At the final analysis, adjustment can be applied for over-running or under-running trial where observed final information is greater or lower than the planned maximum information. See Wassmer & Brannath, 2016, p78f. The test is based on p-values not z statistics because it is easier to not handling direction of alternative hypothesis in current implementation. In addition, only one-sided test is supported which should be sufficient for common use in clinical design.
Methods
Public methods
Method new()
initialize a group sequential test. Now only support one-sided test based on p-values.
Usage
GroupSequentialTest$new( alpha = 0.025, alpha_spending = c("asP", "asOF", "asUser"), planned_max_info, name = "H0", silent = TRUE )
Arguments
alpha
familywise error rate
alpha_spending
alpha spending function. Use
"asUser"
if custom alpha spending schedule is used.planned_max_info
integer. Planned maximum number of patients for non-tte endpoints or number of events for tte endpoints
name
character. Name of the hypothesis, e.g. endpoint, subgroup, etc. Optional.
silent
TRUE
if muting all messages.
Method get_name()
get name of hypothesis
Usage
GroupSequentialTest$get_name()
Method get_alpha()
get overall alpha
Usage
GroupSequentialTest$get_alpha()
Method set_alpha_spending()
set alpha spending function. This is useful when set 'asUser' at the final stage to adjust for an under- or over-running trial.
Usage
GroupSequentialTest$set_alpha_spending(asf)
Arguments
asf
character of alpha spending function.
Method get_alpha_spending()
return character of alpha spending function
Usage
GroupSequentialTest$get_alpha_spending()
Method get_max_info()
return planned maximum information
Usage
GroupSequentialTest$get_max_info()
Method set_max_info()
set planned maximum information. This is used at the final stage to adjust for an under- or over-running trial.
Usage
GroupSequentialTest$set_max_info(obs_max_info)
Arguments
obs_max_info
integer. Maximum information, which could be observed number of patients or events at the final stage.
Method get_stage()
get current stage.
Usage
GroupSequentialTest$get_stage()
Method reset()
an object of class GroupSequentialTest
is designed to be used
sequentially by calling GroupSequentialTest$test
. When all
planned tests are performed, no further analysis could be done. In that
case keep calling GroupSequentialTest$test
will trigger an error.
To reuse the object for a new set of staged p-values, call this function
to reset the status to stage 1. See examples. This implementation can
prevent the error that more than the planned number of stages are tested.
Usage
GroupSequentialTest$reset()
Method set_trajectory()
save testing result at current stage
Usage
GroupSequentialTest$set_trajectory(result, is_final = FALSE)
Arguments
result
a data frame storing testing result at a stage.
is_final
logical.
TRUE
if final test for the hypothesis,FALSE
otherwise.
Method get_trajectory()
return testing trajectory until current stage. This function can be called at any stage. See examples.
Usage
GroupSequentialTest$get_trajectory()
Method get_stage_level()
compute boundaries given current (potentially updated) settings. It returns different values if settings are changed over time.
Usage
GroupSequentialTest$get_stage_level()
Method test_one()
test a hypothesis with the given p-value at current stage
Usage
GroupSequentialTest$test_one( p_value, is_final, observed_info, alpha_spent = NA_real_ )
Arguments
p_value
numeric. A p-value.
is_final
logical.
TRUE
if this test is carried out for the final analysis.observed_info
integer. Observed information at current stage. It can be the number of samples (non-tte) or number of events (tte) at test. If the current stage is final, observed_info will be used to update planned_max_info, the alpha spending function (
typeOfDesign
inrpact
) will be updated to'asUser'
, and the argumentuserAlphaSpending
will be used when callingrpact::getDesignGroupSequential
.alpha_spent
numeric if
alpha_spending = "asUser"
. It must be between 0 andalpha
, the overall alpha of the test.NA_real_
for other alpha spending functions"asOF"
and"asP"
.
Method test()
Carry out test based on group sequential design. If p_values
is NULL
, dummy values will be use and boundaries are calculated
for users to review.
Usage
GroupSequentialTest$test( observed_info, is_final, p_values = NULL, alpha_spent = NULL )
Arguments
observed_info
a vector of integers, observed information at stages.
is_final
logical vector.
TRUE
if the test is for the final analysis.p_values
a vector of p-values. If specified, its length should equal to the length of
observed_info
.alpha_spent
accumulative alpha spent at observed information. It is a numeric vector of values between 0 and 1, and of length that equals
length(observed_info)
if alpha-spending function is"asUser"
. OtherwiseNULL
.
Method print()
generic function for print
Usage
GroupSequentialTest$print()
Method clone()
The objects of this class are cloneable with this method.
Usage
GroupSequentialTest$clone(deep = FALSE)
Arguments
deep
Whether to make a deep clone.
Examples
## Note: examples showed here replicate the results from
## https://www.rpact.org/vignettes/planning/rpact_boundary_update_example/
## Example 1. Generate boundaries for a pre-fix group sequential design
gst <- GroupSequentialTest$new(
alpha = .025, alpha_spending = 'asOF',
planned_max_info = 387)
## without giving p-values, boundaries are returned without actual testing
gst$test(observed_info = c(205, 285, 393), is_final = c(FALSE, FALSE, TRUE))
gst
## Example 2. Calculate boundaries with observed information at stages
## No p-values are provided
## get an error without resetting an used object
try( gst$test(observed_info = 500, is_final = FALSE) )
## reset the object for re-use
gst$reset()
gst$test(observed_info = c(205, 285, 393), is_final = c(FALSE, FALSE, TRUE))
gst
## Example 3. Test stagewise p-values sequentially
gst$reset()
gst$test(observed_info = 205, is_final = FALSE, p_values = .09)
gst$test(285, FALSE, .006)
## print testing trajectory by now
gst
gst$test(393, TRUE, .002)
## print all testing trajectory
gst
## you can also test all stages at once
## the result is the same as calling test() for each of the stages
gst$reset()
gst$test(c(205, 285, 393), c(FALSE, FALSE, TRUE), c(.09, .006, .002))
gst
## Example 4. use user-define alpha spending
gst <- GroupSequentialTest$new(
alpha = .025, alpha_spending = 'asUser',
planned_max_info = 387)
gst$test(
observed_info = c(205, 285, 393),
is_final = c(FALSE, FALSE, TRUE),
alpha_spent = c(.005, .0125, .025))
gst
Class of Listener
Description
Create a class of listener. A listener monitors the trial while checking condition of pre-defined milestones. Actions are triggered and executed automatically.
Methods
Public methods
Method new()
initialize a listener
Usage
Listeners$new(silent = FALSE)
Arguments
silent
logical.
TRUE
to mute messages.
Method add_milestones()
register milestones with listener. Order in ...
matter
as they are scanned in that order. It is user's responsibility
to use reasonable order when calling this function, otherwise,
the result of Listener$monitor()
can be problematic.
Usage
Listeners$add_milestones(...)
Arguments
...
milestones
Method get_milestones()
return registered milestones
Usage
Listeners$get_milestones(milestone_name = NULL)
Arguments
milestone_name
return
Milestone
object with given name(s). IfNULL
, all registered milestones are returned.
Method get_milestone_names()
return names of registered milestones
Usage
Listeners$get_milestone_names()
Method monitor()
scan, check, and trigger registered milestones.
Milestones are triggered in the order when calling
Listener$add_milestones
.
Usage
Listeners$monitor(trial, dry_run)
Arguments
trial
a
Trial
object.dry_run
logical. See
Controller::run
for more information.
Method mute()
mute all messages (not including warnings)
Usage
Listeners$mute(silent)
Arguments
silent
logical.
Method reset()
reset all milestones registered to the listener. Usually, this is called before a controller can run additional replicates of simulation.
Usage
Listeners$reset()
Method clone()
The objects of this class are cloneable with this method.
Usage
Listeners$clone(deep = FALSE)
Arguments
deep
Whether to make a deep clone.
Examples
##
Class of Milestones
Description
Create a class of milestone. An milestone means the time point to take an action, e.g., carry out (futility, interim, final) analysis for add/remove arms, or stop a trial early. It can also be any more general time point where trial data is used in decision making or adaptation. For example, one can define a milestone for changing randomization scheme, sample size re-assessment, trial duration extension etc.
Methods
Public methods
Method new()
initialize milestone
Usage
Milestones$new(name, type = name, trigger_condition, action = doNothing)
Arguments
name
character. Name of milestone.
type
character vector. Milestone type(s) (futility, interim, final), a milestone can be of multiple types. This is for information purpose so can be any string.
trigger_condition
function to check if this milestone should trigger. See vignette
Condition System for Triggering Milestones in a Trial
.action
function to execute when the milestone triggers.
Method get_name()
return name of milestone
Usage
Milestones$get_name()
Method get_type()
return type(s) of milestone
Usage
Milestones$get_type()
Method get_trigger_condition()
return trigger_condition function
Usage
Milestones$get_trigger_condition()
Method get_action()
return action function
Usage
Milestones$get_action()
Method set_dry_run()
set if dry run should be carried out for the milestone. For more details,
refer to Controller::run
.
Usage
Milestones$set_dry_run(dry_run)
Arguments
dry_run
logical.
Method execute_action()
execute action function
Usage
Milestones$execute_action(trial)
Arguments
trial
a
Trial
object.
Method get_trigger_status()
return trigger status
Usage
Milestones$get_trigger_status()
Method reset()
reset an milestone so that it can be triggered again. Usually, this is called before the controller of a trial can run additional replicates of simulation.
Usage
Milestones$reset()
Method trigger_milestone()
trigger an milestone (always TRUE) and execute action accordingly. It calls Trial$get_data_lock_time() to lock data based on conditions implemented in Milestones$trigger_condition. If time that meets the condition cannot be found, Trial$get_data_lock_time() will throw an error and stop the program. This means that user needs to adjust their trigger_condition (e.g., target number of events (target_n_events) is impossible to reach).
Usage
Milestones$trigger_milestone(trial)
Arguments
trial
a
Trial
object.
Method mute()
mute all messages (not including warnings)
Usage
Milestones$mute(silent)
Arguments
silent
logical.
Method clone()
The objects of this class are cloneable with this method.
Usage
Milestones$clone(deep = FALSE)
Arguments
deep
Whether to make a deep clone.
Examples
##
Generate time-to-event endpoint from piecewise constant exponential distribution
Description
Implementation is based on this algorithm.
Usage
PiecewiseConstantExponentialRNG(n, risk, endpoint_name)
Arguments
n |
number of random numbers |
risk |
a data frame of columns
|
endpoint_name |
name of endpoint |
Examples
# example code
# In this example, absolute risk in [0, 1) and [26, 52] are 0.0181 and
# 0.0027, respectively.
risk <- data.frame(
end_time = c(1, 4.33, 26.0, 52.0),
piecewise_risk = c(1, 1.01, 0.381, 0.150) * exp(-4.01)
)
PiecewiseConstantExponentialRNG(10, risk, 'PFS')
Generate enrollment time from piecewise constant uniform distribution
Description
Accrual rate can be 10 patients/months for the first 2 months, 20 patients/ months for the second 2 months, and eventually 30 patients/months until the end of trial.
Usage
StaggeredRecruiter(n, accrual_rate)
Arguments
n |
number of random numbers |
accrual_rate |
a data frame of columns
|
Examples
accrual_rate <- data.frame(
end_time = c(12, 13:17, Inf),
piecewise_rate = c(15, 15 + 6 * (1:5), 45)
)
accrual_rate <- data.frame(
end_time = c(3, 4, 5, 8, Inf),
piecewise_rate = c(1, 2, 2, 3, 4)
)
StaggeredRecruiter(30, accrual_rate)
Class of Trial
Description
Create a class of trial.
Methods
Public methods
Method new()
initialize a trial
Usage
Trials$new( name, n_patients, duration, description = name, seed = NULL, enroller, dropout = NULL, silent = FALSE, ... )
Arguments
name
character. Name of trial.
n_patients
integer. Maximum number of patients could be enrolled to the trial.
duration
Numeric. Trial duration.
description
character. Optional for description of the trial. By default it is set to be trial's
name
.seed
random seed. If
NULL
,set.seed()
will not be called, which uses seed set outside.enroller
a function returning a vector enrollment time for patients. Its first argument is the number of enrolled patients.
dropout
a function returning a vector of dropout time for patients. Its first argument is the number of enrolled patients.
silent
logical.
TRUE
to mute messages....
arguments of
enroller
anddropout
.
Method get_trial_data()
return trial data of enrolled patients at the time of this function is called
Usage
Trials$get_trial_data()
Method get_duration()
return maximum duration of a trial
Usage
Trials$get_duration()
Method set_duration()
set trial duration in an adaptive designed trial. All patients enrolled before resetting the duration are truncated (non-tte endpoints) or censored (tte endpoints) at the original duration. Remaining patients are re-randomized. Now new duration must be longer than the old one.
Usage
Trials$set_duration(duration)
Arguments
duration
new duration of a trial. It must be longer than the current duration.
Method set_enroller()
set recruitment curve when initialize a trial.
Usage
Trials$set_enroller(func, ...)
Arguments
func
function to generate enrollment time. It can be built-in function like 'rexp' or customized functions like 'StaggeredRecruiter'.
...
arguments for
func
.
Method get_enroller()
get function of recruitment curve
Usage
Trials$get_enroller()
Method set_dropout()
set distribution of drop out time. This can be done when initialize a trial, or when updating a trial in adaptive design.
Usage
Trials$set_dropout(func, ...)
Arguments
func
function to generate dropout time. It can be built-in function like 'rexp' or customized functions.
...
arguments for
func
.
Method get_dropout()
get generator of dropout time
Usage
Trials$get_dropout()
Method roll_back()
roll back data to current time of trial. By doing so,
Trial$trial_data
will be cut at current time, and data after then
are deleted. However, Trial$enroll_time
after current time are
kept unchanged because that is planned enrollment curve.
Usage
Trials$roll_back()
Method remove_arms()
remove arms from a trial. enroll_patients()
will be always called
at the end to enroll all remaining patients after
Trial$get_current_time()
. This function may be used with futility
analysis, dose selection, enrichment analysis (sub-population) or
interim analysis (early stop for efficacy)
Usage
Trials$remove_arms(arms_name)
Arguments
arms_name
character vector. Name of arms to be removed.
Method update_sample_ratio()
update sample ratios of arms. This could happen after an arm is added or removed. Note that we may update sample ratios of unaffected arms as well. Once sample ratio is updated, trial data should be rolled back with updated randomization queue. Data of unenrolled patients should be re-sampled as well.
Usage
Trials$update_sample_ratio(arm_names, sample_ratios)
Arguments
arm_names
character vector. Name of arms.
sample_ratios
numeric vector. New sample ratios of arms. If sample ratio is a whole number, the permuted block randomization is adopted; otherwise,
sample()
will be used instead, which can cause imbalance between arms by chance. However, this is fine for simulation.
Method add_arms()
add one or more arms to the trial. enroll_patients()
will be
called at the end to enroll all remaining patients in
private$randomization_queue
. This function can be used in two
scenarios.
(1) add arms right after a trial is created (i.e., Trial$new(...)
).
sample_ratio
and arms added through ...
should be of same
length.
(2) add arms to a trial already with arm(s)
Usage
Trials$add_arms(sample_ratio, ...)
Arguments
sample_ratio
integer vector. Sample ratio for permuted block randomization. It will be appended to existing sample ratio in the trial.
...
one or more objects of class
Arm
. One exception in...
is an argumentenforce
. Whenenforce = TRUE
, sample ratio of newly added arm. It rolls back all patients afterTrial$get_current_time()
, i.e. redo randomization for those patients. This can be useful to add arms one by one when creating a trial. Note that we can runTrial$add_arm(sample_ratio1, arm1)
followed byTrial$add_arm(sample_ratio2, enforce = TRUE, arm2)
. We would expected similar result withTrial$add_arms(c(sample_ratio1, sample_ratio2), arm1, arm2)
. Note that these two method won't return exactly the same trial because randomization_queue were generated twice in the first approach but only once in the second approach. But statistically, they are equivalent and of the same distribution.
Method get_name()
return name of trial
Usage
Trials$get_name()
Method get_description()
return description of trial
Usage
Trials$get_description()
Method get_arms()
return a list of arms in the trial
Usage
Trials$get_arms()
Method get_arms_name()
return arms' name of trial
Usage
Trials$get_arms_name()
Method get_number_arms()
get number of arms in the trial
Usage
Trials$get_number_arms()
Method has_arm()
check if the trial has any arm. Return TRUE
or FALSE
.
Usage
Trials$has_arm()
Method get_an_arm()
return an arm
Usage
Trials$get_an_arm(arm_name)
Arguments
arm_name
character, name of arm to be extracted
Method get_sample_ratio()
return current sample ratio of the trial. The ratio can probably change during the trial (e.g., arm is removed or added)
Usage
Trials$get_sample_ratio(arm_names = NULL)
Arguments
arm_names
character vector of arms.
Method get_number_patients()
return number of patients when planning the trial
Usage
Trials$get_number_patients()
Method get_number_enrolled_patients()
return number of enrolled (randomized) patients
Usage
Trials$get_number_enrolled_patients()
Method get_number_unenrolled_patients()
return number of unenrolled patients
Usage
Trials$get_number_unenrolled_patients()
Method get_randomization_queue()
return randomization queue of planned but not yet enrolled patients. This function does not update randomization_queue, just return its value for debugging purpose.
Usage
Trials$get_randomization_queue(index = NULL)
Arguments
index
index to be extracted. Return all queue if
NULL
.
Method get_enroll_time()
return enrollment time of planned but not yet enrolled patients. This function does not update enroll_time, just return its value for debugging purpose.
Usage
Trials$get_enroll_time(index = NULL)
Arguments
index
index to extract. Return all enroll time if
NULL
.
Method enroll_patients()
assign new patients to pre-planned randomization queue at pre-specified enrollment time.
Usage
Trials$enroll_patients(n_patients = NULL)
Arguments
n_patients
number of new patients to be enrolled. If
NULL
, all remaining patients in plan are enrolled. Error may be triggered if n_patients is greater than remaining patients as planned.
Method set_current_time()
set current time of a trial. Any data collected before could not be changed. private$now should be set after a milestone is triggered (through Milestones class, futility, interim, etc), an arm is added or removed at a milestone
Usage
Trials$set_current_time(time)
Arguments
time
current calendar time of a trial.
Method get_current_time()
return current time of a trial
Usage
Trials$get_current_time()
Method get_event_tables()
count accumulative number of events (for TTE) or non-missing samples (otherwise) over calendar time (enroll time + tte for TTE, or enroll time + readout otherwise)
Usage
Trials$get_event_tables(arms = NULL, ...)
Arguments
arms
a vector of arms' name on which the event tables are created. if
NULL
, all arms in the trial will be used....
subset conditions compatible with
dplyr::filter
. Event tables will be counted on subset of trial data only.
Method get_data_lock_time_by_event_number()
given a set of endpoints and target number of events, determine the data lock time for a milestone (futility, interim, final, etc.). This function does not change trial object (e.g. rolling back not yet randomized patients after the found data lock time).
Usage
Trials$get_data_lock_time_by_event_number( endpoints, arms, target_n_events, type = c("all", "any"), ... )
Arguments
endpoints
character vector. Data lock time is determined by a set of endpoints.
arms
a vector of arms' name on which number of events will be counted.
target_n_events
target number of events for each of the
endpoints
.type
all
if all target number of events are reached.any
if the any target number of events is reached....
subset conditions compatible with
dplyr::filter
. Number Time of milestone is based on event counts on the subset of trial data.
Returns
data lock time
Method get_data_lock_time_by_calendar_time()
given the calendar time to lock the data, return it with event counts of each of the endpoints.
Usage
Trials$get_data_lock_time_by_calendar_time(calendar_time, arms)
Arguments
calendar_time
numeric. Calendar time to lock the data
arms
a vector of arms' name on which number of events will be counted.
Returns
data lock time
Method get_locked_data()
return locked data for a milestone
Usage
Trials$get_locked_data(milestone_name)
Arguments
milestone_name
character, milestone name of which the locked data to be extracted.
Method get_locked_data_name()
return names of locked data
Usage
Trials$get_locked_data_name()
Method get_event_number()
return number of events at lock time of milestones
Usage
Trials$get_event_number(milestone_name = NULL)
Arguments
milestone_name
names of triggered milestones. Use all triggered milestones if
NULL
.
Method save_milestone_time()
save time of a new milestone.
Usage
Trials$save_milestone_time(milestone_time, milestone_name)
Arguments
milestone_time
numeric. Time of new milestone.
milestone_name
character. Name of new milestone.
Method get_milestone_time()
return milestone time when triggering a given milestone
Usage
Trials$get_milestone_time(milestone_name = NULL)
Arguments
milestone_name
character. Name of milestone. If
NULL
, time of all triggered milestones are returned.
Method lock_data()
lock data at specific calendar time.
For time-to-event endpoints, their event indicator *_event
should be
updated accordingly. Locked data should be stored separately.
DO NOT OVERWRITE/UPDATE private$trial_data! which can lose actual
time-to-event information. For example, a patient may be censored at
the first data lock. However, he may have event being observed in a
later data lock.
Usage
Trials$lock_data(at_calendar_time, milestone_name)
Arguments
at_calendar_time
time point to lock trial data
milestone_name
assign milestone name as the name of locked data for future reference.
Method event_plot()
plot of cumulative number of events/samples over calendar time.
Usage
Trials$event_plot()
Method censor_trial_data()
censor trial data at calendar time
Usage
Trials$censor_trial_data( censor_at = NULL, selected_arms = NULL, enrolled_before = Inf )
Arguments
censor_at
time of censoring. It is set to trial duration if
NULL
.selected_arms
censoring is applied to selected arms (e.g., removed arms) only. If
NULL
, it will be set to all available arms in trial data. Otherwise, censoring is applied to user-specified arms only. This is necessary because number of events/sample size in removed arms should be fixed unchanged since corresponding milestone is triggered. In that case, one can update trial data by something likecensor_trial_data(censor_at = milestone_time, selected_arms = removed_arms)
.enrolled_before
censoring is applied to patients enrolled before specific time. This argument would be used when trial duration is updated by
set_duration
. Adaptation happens whenset_duration
is called so we fix duration for patients enrolled before adaptation to maintain independent increment. This should work when trial duration is updated for multiple times.
Method save()
save a single value or a one-row data frame to trial's output for further analysis/summary later.
Usage
Trials$save(value, name = "", overwrite = FALSE)
Arguments
value
value to be saved. It can be a vector (of length 1) or a data frame (of one row).
name
character to name the saved object. It will be used to name a column in trial's output if
value
is a vector. Ifvalue
is a data frame,name
will be the prefix pasted with the column name ofvalue
in trial's output. If user want to usevalue
's column name as is in trial's output, setname
to be''
as default. Otherwise, column name would be, e.g.,"{name}_<{names(value)}>"
.overwrite
logic.
TRUE
if overwriting existing entries with warning, otherwise, throwing an error and stop.
Method bind()
row bind a data frame to existing data frame. If name
is not
existing in Trial
, then it is equivalent to Trial$save
.
Extra columns in value
are ignored. Columns in
Trial$custom_data[[name]]
but not in value
are filled
with NA
.
Usage
Trials$bind(value, name)
Arguments
value
a data frame to be saved. It can consist of one or multiple rows.
name
character. Name of object to be saved.
Method save_custom_data()
save arbitrary (number of) objects into a trial so that users can use those to control the workflow. Most common use case is to store simulation parameters to be used in action functions.
Usage
Trials$save_custom_data(value, name, overwrite = FALSE)
Arguments
value
value to be saved. Any type.
name
character. Name of the value to be accessed later.
overwrite
logic.
TRUE
if overwriting existing entries with warning, otherwise, throwing an error and stop.
Method get_custom_data()
return saved custom data of specified name.
Usage
Trials$get_custom_data(name)
Arguments
name
character. Name of custom data to be accessed.
Method get()
alias of function get_custom_data
to make it short and cool.
Usage
Trials$get(name)
Arguments
name
character. Name of custom data to be accessed.
Method get_output()
return a data frame of all current outputs saved by calling save
.
Usage
Trials$get_output(cols = NULL, simplify = TRUE)
Arguments
cols
columns to be returned from
Trial$output
. IfNULL
, all columns are returned.simplify
logical. Return value rather than a data frame of one column when
length(col) == 1
andsimplify == TRUE
.
Method mute()
mute all messages (not including warnings)
Usage
Trials$mute(silent)
Arguments
silent
logical.
Method independentIncrement()
calculate independent increments from a given set of milestones
Usage
Trials$independentIncrement( formula, placebo, milestones, alternative, planned_info, ... )
Arguments
formula
An object of class
formula
that can be used withsurvival::coxph
. Must consistarm
and endpoint indata
. No covariate is allowed. Stratification variables are supported and can be added usingstrata(...)
.placebo
character. String of placebo in trial's locked data.
milestones
a character vector of milestone names in the trial, e.g.,
listener$get_milestone_names()
.alternative
a character string specifying the alternative hypothesis, must be one of
"greater"
or"less"
. No default value."greater"
means superiority of treatment over placebo is established by an hazard ratio greater than 1 when a log-rank test is used.planned_info
a vector of planned accumulative number of event of time-to-event endpoint. It is named by milestone names. Note:
planned_info
can also be a character"oracle"
so that planned number of events are set to be observed number of events, in that case inverse normal z statistics equal to one-sided logrank statistics. This is for the purpose of debugging only. In formal simulation,"oracle"
should not be used if adaptation is present. Pre-fixedplanned_info
should be used to create weights in combination test that controls the family-wise error rate in the strong sense....
subset condition that is compatible with
dplyr::filter
.survdiff
will be fitted on this subset only to compute one-sided logrank statistics. It could be useful when a trial consists of more than two arms. By default it is not specified, all data will be used to fit the model.
Returns
This function returns a data frame with columns:
p_inverse_normal
one-sided p-value for inverse normal test based on logrank test (alternative hypothesis: risk is higher in placebo arm). Accumulative data is used.
z_inverse_normal
z statistics of
p_inverse_normal
. Accumulative data is used.p_lr
one-sided p-value for logrank test (alternative hypothesis: risk is higher in placebo arm). Accumulative data is used.
z_lr
z statistics of
p_lr
. Accumulative data is used.info
observed accumulative event number.
planned_info
planned accumulative event number.
info_pbo
observed accumulative event number in placebo.
info_trt
observed accumulative event number in treatment arm.
wt
weights in
z_inverse_normal
.
Examples
\dontrun{ trial$independentIncrement(Surv(pfs, pfs_event) ~ arm, 'pbo', listener$get_milestone_names(), 'less', 'oracle') }
Method dunnettTest()
carry out closed test based on Dunnett method under group sequential design.
Usage
Trials$dunnettTest( formula, placebo, treatments, milestones, alternative, planned_info, ... )
Arguments
formula
An object of class
formula
that can be used withsurvival::coxph
. Must consistarm
and endpoint indata
. No covariate is allowed. Stratification variables are supported and can be added usingstrata(...)
.placebo
character. Name of placebo arm.
treatments
character vector. Name of treatment arms to be used in comparison.
milestones
character vector. Names of triggered milestones at which either adaptation is applied or statistical testing for endpoint is performed. Milestones in
milestones
does not need to be sorted by their triggering time.alternative
a character string specifying the alternative hypothesis, must be one of
"greater"
or"less"
. No default value."greater"
means superiority of treatment over placebo is established by an hazard ratio greater than 1 when a log-rank test is used.planned_info
a data frame of planned number of events of time-to-event endpoint in each stage and each arm. Milestone names, i.e.,
milestones
are row names ofplanned_info
, and arm names, i.e.,c(placebo, treatments)
are column names. Note that it is not the accumulative but stage-wise event numbers. It is usually not easy to determine these numbers in practice, simulation may be used to get estimates. Note:planned_info
can also be a character"default"
so thatplanned_info
are set to be number of newly randomized patients in the control arm in each of the stages. This assumes that event rate do not change over time and/or sample ratio between placebo and a treatment arm does not change as well, which may not be true. It is for the purpose of debugging or rapid implementation only. Using simulation to pickplanned_info
is recommended in formal simulation study. Another issue withplanned_info
set to be"default"
is that it is possible patient recruitment is done before a specific stage, as a result,planned_info
is zero which can crash the program....
subset condition that is compatible with
dplyr::filter
.survdiff
will be fitted on this subset only to compute one-sided logrank statistics. It could be useful when comparison is made on a subset of treatment arms. By default it is not specified, all data (placebo plus one treatment arm at a time) in the locked data are used to fit the model.
Details
This function computes stage-wise p-values for each of the intersection
hypotheses based on Dunnett test. If only one treatment arm is present,
it is equivalent to compute the stage-wise p-values of elemental
hypotheses. This function also computes inverse normal combination
test statistics at each of the stages.
The choice of planned_info
can affect the calculation of
stage-wise p-values. Specifically, it is used to compute
the columns observed_info
and p_inverse_normal
in returned
data frame, which will be used in Trial$closedTest()
.
The choice of planned_info
can affect the result of
Trial$closedTest()
so user should chose it with caution.
Note that in Trial$closedTest()
,
observed_info
, which is derived from planned_info
, will
lead to the same closed testing results up to a constant. This is because
the closed test uses information fraction
observed_info/sum(observed_info)
. As a result, setting
planned_info
to, e.g., 10 * planned_info
should give same
closed test results.
Based on numerical study, setting planned_info = "default"
leads
to a much higher power (roughly 10%) than setting planned_info
to
median of event numbers at stages, which can be determined by simulation.
I am not sure if regulator would support such practice. For example,
if a milestone (e.g., interim analysis) is triggered at a pre-specified
calendar time, the number of randomized patients is random and is unknown
when planning the trial. If I understand it correctly, regulator may want
the information fraction in closed test (combined with Dunnett test) to
be pre-fixed. In addition, this choice for planned_info
assumes
that the event rates does not change over time which is obviously not
true. It is recommended to always use pre-fixed planned_info
for
restrict control of family-wise error rate. It should be pointed out
that the choice of pre-fixed planned_info
can affect statistical
power significantly so fine-tuning may be required.
Returns
a list with element names like arm_name
,
arm1_name|arm2_name
, arm1_name|arm2_name|arm3_name
, etc.,
i.e., all possible combination of treatment arms in comparison. Each
element is a data frame, with its column names self-explained. Specifically,
the columns p_inverse_normal
, observed_info
,
is_final
can be used with GroupSequentialTest
to perform
significance test.
Examples
\dontrun{ trial$dunnettTest(Surv(pfs, pfs_event) ~ arm, 'pbo', c('high dose', 'low dose'), listener$get_milestone_names(), 'default') }
Method closedTest()
perform closed test based on Dunnett test
Usage
Trials$closedTest( dunnett_test, treatments, milestones, alpha, alpha_spending = c("asP", "asOF") )
Arguments
dunnett_test
object returned by
Trial$dunnettTest()
.treatments
character vector. Name of treatment arms to be used in comparison.
milestones
character vector. Names of triggered milestones at which significance testing for endpoint is performed in closed test. Milestones in
milestones
does not need to be sorted by their triggering time.alpha
numeric. Allocated alpha.
alpha_spending
alpha spending function. It can be
"asP"
or"asOF"
. Note that theoretically it can be"asUser"
, but it is not tested. It may be supported in the future.
Returns
a data frame of columns arm
, decision
(final decision on a hypothesis at the end of trial, "accept"
or "reject"
),
milestone_at_reject
, and reject_time
.
If a hypothesis is accepted at then end of a trial,
milestone_at_reject
is NA
, and reject_time
is Inf
.
Note that if a hypothesis is tested at multiple milestones, the final
decision
will be "accept"
if it is accepted at at least
one milestone. The decision
is "reject"
only if the hypothesis
is rejected at all milestones.
Examples
\dontrun{ dt <- trial$dunnettTest( Surv(pfs, pfs_event) ~ arm, placebo = 'pbo', treatments = c('high dose', 'low dose'), milestones = c('dose selection', 'interim', 'final'), data.frame(pbo = c(100, 160, 80), low = c(100, 160, 80), high = c(100, 160, 80), row.names = c('dose selection', 'interim', 'final')) trial$closedTest(dt, treatments = c('high dose', 'low dose'), milestones = c('interim', 'final'), alpha = 0.025, alpha_spending = 'asOF') }
Method get_seed()
return random seed
Usage
Trials$get_seed()
Method print()
print a trial
Usage
Trials$print()
Method get_snapshot_copy()
return a snapshot of a trial before it is executed.
Usage
Trials$get_snapshot_copy()
Method make_snapshot()
make a snapshot before running a trial. This can be useful when resetting a trial. This is only called when initializing a 'Trial' object, when arms have not been added yet.
Usage
Trials$make_snapshot()
Method make_arms_snapshot()
make a snapshot of arms
Usage
Trials$make_arms_snapshot()
Method reset()
reset a trial to its snapshot taken before it was executed. Seed will be reassigned with a new one. Enrollment time are re-generated. If the trial already have arms when this function is called, they are added back to recruit patients again.
Usage
Trials$reset()
Method set_arm_added_time()
save time when an arm is added to the trial
Usage
Trials$set_arm_added_time(arm, time)
Arguments
arm
name of added arm.
time
time when an arm is added.
Method get_arm_added_time()
get time when an arm is added to the trial
Usage
Trials$get_arm_added_time(arm)
Arguments
arm
arm name.
Method set_arm_removal_time()
save time when an arm is removed to the trial
Usage
Trials$set_arm_removal_time(arm, time)
Arguments
arm
name of removed arm.
time
time when an arm is removed.
Method get_arm_removal_time()
get time when an arm is removed from the trial
Usage
Trials$get_arm_removal_time(arm)
Arguments
arm
arm name.
Method clone()
The objects of this class are cloneable with this method.
Usage
Trials$clone(deep = FALSE)
Arguments
deep
Whether to make a deep clone.
Examples
# Instead of using Trial$new, please use trial(), a user-friendly
# wrapper. See examples in ?trial.
## ------------------------------------------------
## Method `Trials$independentIncrement`
## ------------------------------------------------
## Not run:
trial$independentIncrement(Surv(pfs, pfs_event) ~ arm, 'pbo',
listener$get_milestone_names(),
'less', 'oracle')
## End(Not run)
## ------------------------------------------------
## Method `Trials$dunnettTest`
## ------------------------------------------------
## Not run:
trial$dunnettTest(Surv(pfs, pfs_event) ~ arm, 'pbo', c('high dose', 'low dose'),
listener$get_milestone_names(), 'default')
## End(Not run)
## ------------------------------------------------
## Method `Trials$closedTest`
## ------------------------------------------------
## Not run:
dt <- trial$dunnettTest(
Surv(pfs, pfs_event) ~ arm,
placebo = 'pbo',
treatments = c('high dose', 'low dose'),
milestones = c('dose selection', 'interim', 'final'),
data.frame(pbo = c(100, 160, 80),
low = c(100, 160, 80),
high = c(100, 160, 80),
row.names = c('dose selection', 'interim', 'final'))
trial$closedTest(dt, treatments = c('high dose', 'low dose'),
milestones = c('interim', 'final'),
alpha = 0.025, alpha_spending = 'asOF')
## End(Not run)
Define an Arm
Description
Define an arm in a trial. This is a user-friendly wrapper for
the class constructor Arm$new
. Users who are not familiar with
the concept of classes may consider using this wrapper directly.
Usage
arm(name, ...)
Arguments
name |
name of arm, which is the arm's label in generated data |
... |
subset condition that is compatible with |
Examples
risk <- data.frame(
end_time = c(1, 10, 26.0, 52.0),
piecewise_risk = c(1, 1.01, 0.381, 0.150) * exp(-3.01)
)
pfs <- endpoint(name = 'pfs', type='tte',
generator = PiecewiseConstantExponentialRNG,
risk = risk, endpoint_name = 'pfs')
orr <- endpoint(
name = 'orr', type = 'non-tte',
readout = c(orr = 2), generator = rbinom,
size = 1, prob = .4)
placebo <- arm(name = 'pbo')
placebo$add_endpoints(pfs, orr)
placebo
head(placebo$get_endpoints()[[1]]$get_generator()(n = 1e3))
placebo$get_endpoints()[[2]]$get_name()
## print summary reports for endpoint objects in console
# placebo
Triggering condition by calendar time
Description
Define a condition to trigger trial milestone by calendar time. The milestone will be trigger when a trial has been running for at least the specified duration. It can be used combined with conditions specified by enrollment and eventNumber.
Usage
calendarTime(time)
Arguments
time |
numeric. Calendar time to trigger a milestone of a trial. |
Value
an object of class 'Condition'
Define a Controller
Description
Define a controller of a trial. This is a user-friendly wrapper for
the class constructor Controller$new
. Users who are not familiar with
the concept of classes may consider using this wrapper directly.
Usage
controller(trial, listener)
Arguments
trial |
a |
listener |
a |
Examples
# a minimum, meaningful, and executable example,
# where a randomized trial with two arms is simulated and analyzed.
control <- arm(name = 'control arm')
active <- arm(name = 'active arm')
pfs_in_control <- endpoint(name = 'PFS', type = 'tte', generator = rexp, rate = log(2) / 5)
control$add_endpoints(pfs_in_control)
pfs_in_active <- endpoint(name = 'PFS', type = 'tte', generator = rexp, rate = log(2) / 6)
active$add_endpoints(pfs_in_active)
accrual_rate <- data.frame(end_time = c(10, Inf), piecewise_rate = c(30, 50))
trial <- trial(name = 'trial',
n_patients = 1000,
duration = 40,
enroller = StaggeredRecruiter,
accrual_rate = accrual_rate,
dropout = rweibull, shape = 2, scale = 38)
trial$add_arms(sample_ratio = c(1, 1), control, active)
action_at_final <- function(trial, milestone_name){
locked_data <- trial$get_locked_data(milestone_name)
fitLogrank(Surv(PFS, PFS_event) ~ arm, placebo = 'control arm',
data = locked_data, alternative = 'less')
invisible(NULL)
}
final <- milestone(name = 'final analysis',
action = action_at_final,
when = calendarTime(time = 40))
listener <- listener()
listener$add_milestones(final)
controller <- controller(trial, listener)
controller$run(n = 1)
default action function for dry run of a trial
Description
default action function for dry run of a trial
Usage
default_action()
An action function that does nothing
Description
This is an action function that does nothing when the corresponding milestone
is triggered. When the listener is monitoring a trial and determining the
time to trigger a milestone, data is automatically locked with other necessary
data manipulation being executed. If the users have no intent to modify the
trial adaptively at the milestone, e.g., adding (add_arms()
) or
removing (remove_arms()
) arm(s),
changing sampling ratio(s) (update_sample_ratio()
),
modifying trial duration, carrying out statistical testing,
or saving intermediate results (save()
), then this function
can be used to set the argument action
when creating a new milestone.
Note that the triggering time of a milestone with action = doNothing
is still recorded in output automatically.
Usage
doNothing(trial, milestone_name)
Arguments
trial |
a |
milestone_name |
character. Name of milestone being triggered. |
Value
This function returns NULL
. Actually, nothing is done in this function.
Define endpoints
Description
Define one or multiple endpoints. This is a user-friendly wrapper for
the class constructor Endpoint$new
. Users who are not familiar with
the concept of classes may consider using this wrapper directly.
wrapper if
Usage
endpoint(name, type = c("tte", "non-tte"), readout = NULL, generator, ...)
Arguments
name |
character vector. Name(s) of endpoint(s) |
type |
character vector. Type(s) of endpoint(s). It supports
|
readout |
numeric vector with name to be the non-tte endpoint(s).
|
generator |
a RNG function. Its first argument must be 'n', number of
patients. It must return a data frame of 'n' rows. It support all
built-in random number generators in |
... |
optional arguments for |
Examples
set.seed(12345)
## Example 1. Generate a time-to-event endpoint.
## Two columns are returned, one for time, one for event (1/0, 0 for
## A built-in RNG function is used to handle piecewise constant exponential
## distribution
risk <- data.frame(
end_time = c(1, 10, 26.0, 52.0),
piecewise_risk = c(1, 1.01, 0.381, 0.150) * exp(-3.01)
)
pfs <- endpoint(name = 'pfs', type='tte',
generator = PiecewiseConstantExponentialRNG,
risk = risk, endpoint_name = 'pfs')
pfs$get_generator()
## Example 2. Generate continuous and binary endpoints using R's built-in
## RNG functions, e.g. rnorm, rexp, rbinom, etc.
ep1 <- endpoint(
name = 'cd4', type = 'non-tte', generator = rnorm, readout = c(cd4=1),
mean = 1.2)
ep2 <- endpoint(
name = 'resp_time', type = 'non-tte', generator = rexp, readout = c(resp_time=0),
rate = 4.5)
ep3 <- endpoint(
name = 'orr', type = 'non-tte', readout = c(orr=3), generator = rbinom,
size = 1, prob = .4)
mean(ep1$get_generator()(1e4)[, 1]) # compared to 1.2
sd(ep1$get_generator()(1e4)[, 1]) # compared to 1.0
log(2) / median(ep2$get_generator()(1e4)[, 1]) # compared to 4.5
mean(ep3$get_generator()(1e4)[, 1]) # compared to 0.4
## print summary reports for endpoint objects in console
# ep1
# ep2
# ep3
## An example of piecewise constant exponential random number generator
## Baseline hazards are piecewise constant
## Hazard ratios are piecewise constant, resulting a delayed effect.
run <- TRUE
if (!requireNamespace("survminer", quietly = TRUE)) {
run <- FALSE
message("Please install 'survminer' to run this example.")
}
if (!requireNamespace("survival", quietly = TRUE)) {
run <- FALSE
message("Please install 'survival' to run this example.")
}
if(run){
risk1 <- risk
ep1 <- endpoint(
name = 'pfs', type='tte',
generator = PiecewiseConstantExponentialRNG,
risk=risk1, endpoint_name = 'pfs')
risk2 <- risk1
risk2$hazard_ratio <- c(1, 1, .6, .4)
ep2 <- endpoint(
name = 'pfs', type='tte',
generator = PiecewiseConstantExponentialRNG,
risk=risk2, endpoint_name = 'pfs')
n <- 1000
tte <- rbind(ep1$get_generator()(n), ep2$get_generator()(n))
arm <- rep(0:1, each = n)
dat <- data.frame(tte, arm)
sfit <- survival::survfit(
survival::Surv(time = pfs, event = pfs_event) ~ arm, dat)
survminer::ggsurvplot(sfit,
data = dat,
pval = TRUE, # Show p-value
conf.int = TRUE, # Show confidence intervals
risk.table = TRUE, # Add risk table
palette = c("blue", "red"))
## print summary reports for endpoint objects in console
# ep1
# ep2
}
Triggering condition by number of randomized patients
Description
Define a condition to trigger trial milestone by the number of randomized patients. The milestone will be trigger when a trial has enrolled at least the specified number of patients. It can be used combined with conditions specified by calendarTime and eventNumber.
Usage
enrollment(n, ..., arms = NULL)
Arguments
n |
integer. Number of randomized patients. |
... |
subset conditions compatible with |
arms |
vector of character. Name of arms on which the number of patients
is counted. If |
Value
an object of class 'Condition'
Triggering condition by number of events or observations of an endpoint
Description
Define a condition to trigger trial milestone by the number of events of a time-to-event endpoint or the number of non-missing observations of a non-time-to-event endpoint. The milestone will be triggered when a trial has observed at least the specified number of endpoint events (or non-missing observations). It can be used combined with conditions specified by calendarTime and enrollment.
Number of events for a time-to-event endpoint can vary at different milestones as more patients are randomized into a trial, or more events onset over time.
Number of non-missing observations for a non-time-to-event endpoint can vary
at different milestones as more patients are randomized into a trial, or more
patients have been treated until their readout time (thus, NA
turns
to a value).
Usage
eventNumber(endpoint, n, ..., arms = NULL)
Arguments
endpoint |
character. Name of an endpoint. |
n |
integer. Targeted number of events. |
... |
subset conditions compatible with |
arms |
vector of character. Name of arms on which the number of events
is counted. If |
Value
an object of class 'Condition'
Fit Cox proportional hazard ratio model
Description
Fit Cox proportional hazards model on an time-to-event endpoint.
Usage
fitCoxph(formula, placebo, data, alternative, scale, ..., tidy = TRUE)
Arguments
formula |
An object of class |
placebo |
Character. String indicating the placebo in |
data |
Data frame. Usually it is a locked data set. |
alternative |
a character string specifying the alternative hypothesis,
must be one of |
scale |
character. The type of estimate in the output. Must be one
of |
... |
Subset conditions compatible with |
tidy |
logical. |
Value
a data frame with three columns:
arm
name of the treatment arm.
placebo
name of the placebo arm.
estimate
estimate of main effect of arm, depending on
scale
.p
one-sided p-value for log hazard ratio (treated vs placebo).
info
the number of events of the endpoint in the subset.
z
the z statistics of log hazard ratios.
Farrington-Manning test for rate difference
Description
Test rate difference by comparing it to a pre-specified value using the Farrington-Manning test
Usage
fitFarringtonManning(endpoint, placebo, data, alternative, ..., delta = 0)
Arguments
endpoint |
Character. Name of the endpoint in |
placebo |
Character. String indicating the placebo in |
data |
Data frame. Usually it is a locked data set. |
alternative |
a character string specifying the alternative hypothesis,
must be one of |
... |
Subset conditions compatible with |
delta |
the rate difference between a treatment arm and placebo under the null. 0 by default. |
Value
a data frame with three columns:
arm
name of the treatment arm.
placebo
name of the placebo arm.
estimate
estimate of rate difference.
p
one-sided p-value for log odds ratio (treated vs placebo).
info
sample size in the subset with
NA
being removed.z
the z statistics of log odds ratio (treated vs placebo).
References
Farrington, Conor P., and Godfrey Manning. "Test statistics and sample size formulae for comparative binomial trials with null hypothesis of non-zero risk difference or non-unity relative risk." Statistics in medicine 9.12 (1990): 1447-1454.
Fit linear regression model
Description
Fit linear regression model on a continuous endpoint.
Usage
fitLinear(formula, placebo, data, alternative, ...)
Arguments
formula |
an object of class |
placebo |
Character. String indicating the placebo arm in |
data |
Data frame. Usually it is a locked data set. |
alternative |
a character string specifying the alternative hypothesis,
must be one of |
... |
Subset conditions compatible with |
Value
a data frame with columns:
arm
name of the treatment arm.
placebo
name of the placebo arm.
estimate
estimate of average treatment effect of
arm
.p
one-sided p-value for between-arm difference (treated vs placebo).
info
sample size used in model with
NA
being removed.z
z statistics of between-arm difference (treated vs placebo).
Fit logistic regression model
Description
Fit logistic regression model on an binary endpoint.
Usage
fitLogistic(formula, placebo, data, alternative, scale, ...)
Arguments
formula |
An object of class |
placebo |
Character. String indicating the placebo in |
data |
Data frame. Usually it is a locked data set. |
alternative |
a character string specifying the alternative hypothesis,
must be one of |
scale |
character. The type of estimate in the output. Must be one
of |
... |
Subset conditions compatible with |
Value
a data frame with columns:
arm
name of the treatment arm.
placebo
name of the placebo arm.
estimate
estimate depending on
scale
.p
one-sided p-value for log odds ratio (treated vs placebo).
info
sample size used in model with
NA
being removed.z
z statistics of log odds ratio (treated vs placebo).
Carry out log rank test
Description
Compute log rank test statistic on an endpoint.
Usage
fitLogrank(formula, placebo, data, alternative, ..., tidy = TRUE)
Arguments
formula |
An object of class |
placebo |
character. String of placebo in |
data |
data frame. Usually it is a locked data. |
alternative |
a character string specifying the alternative hypothesis,
must be one of |
... |
subset condition that is compatible with |
tidy |
logical. |
Value
a data frame with three columns:
arm
name of the treatment arm.
placebo
name of the placebo arm.
p
one-sided p-value for log-rank test (treated vs placebo).
info
the number of events of the endpoint in the subset.
z
the z statistics of log hazard ratios.
Get simulation output in the vignette adaptiveDesign.Rmd
Description
Internal function that retrieves precomputed simulation results. Not meant for use by package users.
Usage
getAdaptiveDesignOutput()
Value
A data frame containing simulation results of 1000 replicates.
Get simulation output in the vignette fixedDesign.Rmd
Description
Internal function that retrieves precomputed simulation results. Not meant for use by package users.
Usage
getFixedDesignOutput()
Value
A data frame containing simulation results of 1000 replicates.
Define a Listener
Description
Define a listener. This is a user-friendly wrapper for
the class constructor Listener$new
. Users who are not familiar with
the concept of classes may consider using this wrapper directly.
Usage
listener(silent = FALSE)
Arguments
silent |
logical. |
Examples
listener <- listener()
Define a Milestone of a Trial
Description
Define a milestone of a trial. This is a user-friendly wrapper for
the class constructor Milestones$new
. Users who are not familiar with
the concept of classes may consider using this wrapper directly.
Usage
milestone(name, when, action = doNothing)
Arguments
name |
character. Name of milestone. |
when |
condition to check if this milestone should be triggered. |
action |
function to execute when the milestone triggers.
If no action to be executed but simply need to record triggering time of
a milestone, |
Plot Triggering Time of Milestones in Simulated Trials
Description
Plot Triggering Time of Milestones in Simulated Trials
Usage
## S3 method for class 'milestone_time_summary'
plot(x, ...)
Arguments
x |
an object returned by |
... |
currently not supported. |
Plot result of three-state ill-death model
Description
Plot result of three-state ill-death model
Usage
## S3 method for class 'three_state_model'
plot(x, ...)
Arguments
x |
an object returned by |
... |
currently not supported. |
Generate constant variable
Description
A random number generator returning only a constant. This can be used to set dropout time. Currently it is default value of dropout time, with 'value = Inf'.
Usage
rconst(n, value)
Arguments
n |
integer. Number of observations. |
value |
value of constant observations. |
Solve parameters in a mixture exponential distribution
Description
Assume that the overall population is a mixture of two exponential
distributions with medians median1
(m_1
) and
median2
(m_2
). Given the proportion of the first component
(p_1
) and the overall median m
, we have
p_1 (1 - e^{-\log(2)m/m_1}) + (1 - p_1) (1 - e^{-\log(2)m/m_2}) = 1/2
This function computes m_2
or m
given p_1
and m_1
.
Usage
solveMixtureExponentialDistribution(
weight1,
median1,
median2 = NULL,
overall_median = NULL
)
Arguments
weight1 |
numeric. The proportion of the first component. |
median1 |
numeric. Median of the first component. |
median2 |
numeric. Median of the second component. If |
overall_median |
numeric. Median of the overall population. If
|
Value
a named vector of median2
or overall_median
.
Examples
library(dplyr)
median2 <-
solveMixtureExponentialDistribution(
weight1 = .3,
median1 = 10,
overall_median = 8)
median2
n <- 1e6
ifelse(
runif(n) < .3,
rexp(n, rate=log(2)/10),
rexp(n, rate=log(2)/median2)) %>%
median() ## should be close to 8
overall_median <-
solveMixtureExponentialDistribution(
weight1 = .4,
median1 = 12,
median2 = 4)
overall_median
ifelse(
runif(n) < .4,
rexp(n, rate=log(2)/12),
rexp(n, rate=log(2)/4)) %>%
median() ## should be close to overall_median
Solve parameters in a three-state ill-death model
Description
The ill-death model consists of three states, stable
, progression
,
and death
. It can be used to model the progression-free survival (PFS)
and overall survival (OS) in clinical trial simulation. It models the
correlation PFS and OS without assumptions on latent status and copula.
Also, it does not assume PFS and OS satisfy the proportional hazard assumption
simultaneously. The three-state ill-death model ensure the nice property that
PFS <= OS with probability one. However, it requires three hazard parameters
under the homogeneous Markov assumption. In practice, hazard parameters are
hard to specify intuitively especially when no trial data is available at
the planning stage.
This function reparametrizes the ill-death model in term of three parameters,
i.e. median of PFS, median of OS, and correlation between PFS and OS. The
output of this function, which consists of the three hazard parameters, can
be used to generate PFS and OS with desired property. It can be used with
the built-in data generator CorrelatedPfsAndOs3()
when defining
endpoints in TrialSimulator
.
Usage
solveThreeStateModel(
median_pfs,
median_os,
corr,
h12 = seq(0.05, 0.2, length.out = 50)
)
Arguments
median_pfs |
numeric. Median of PFS. |
median_os |
numeric. Median of OS. |
corr |
numeric vector. Pearson correlation coefficients between PFS and OS. |
h12 |
numeric vector. A set of hazard from progression to
death that may induce the target correlation |
Value
a data frame with columns:
corr
target Peason's correlation coefficients.
h01
hazard from stable to progression.
h02
hazard from stable to death.
h12
hazard from progression to death.
error
absolute error between target correlation and correlation derived from
h01
,h02
, andh12
.
Examples
dat <- CorrelatedPfsAndOs3(1e6, h01 = .1, h02 = .05, h12 = .12)
cor(dat$pfs, dat$os) ## 0.65
median(dat$pfs) ## 4.62
median(dat$os) ## 9.61
## find h01, h02, h12 that can match to median_pfs, median_os and corr
## should be close to h01 = 0.10, h02 = 0.05, h12 = 0.12 when corr = 0.65
ret <- solveThreeStateModel(median_pfs = 4.6, median_os = 9.6,
corr = seq(.5, .7, length.out=5))
ret
Summarize A Data Frame
Description
A minimum alternative to summarytools::dfSummary
to avoid package dependency.
Usage
summarizeDataFrame(
data,
exclude_vars = NULL,
tte_vars = NULL,
event_vars = NULL,
categorical_vars = NULL,
title = "Summary",
sub_title = ""
)
Arguments
data |
a data frame. |
exclude_vars |
columns to be excluded from summary. |
tte_vars |
character. Vector of time-to-event variables. |
event_vars |
character. Vector of event indicators. Every time-to-event variable should be corresponding to an event indicator. |
categorical_vars |
character. Vector of categorical variables. This can be used to specify variables with limited distinct values as categorical variables in summary. |
title |
title of the summary report. |
sub_title |
sub-title. |
Value
a data frame of summary
Examples
set.seed(123)
n <- 1000
data <- data.frame(
age = rnorm(n, 65, 10),
gender = sample(c('M', 'F', NA), n, replace = TRUE, prob = c(.4, .4, .2)),
time_to_death = rexp(n, .01),
death = rbinom(n, 1, .6),
type = sample(LETTERS[1:8], n, replace = TRUE)
)
summarizeDataFrame(data, tte_vars = 'time_to_death', event_vars = 'death')
Summary of Milestone Time from Simulated Trials
Description
Summary of Milestone Time from Simulated Trials
Usage
summarizeMilestoneTime(output)
Arguments
output |
a data frame. It assumes that triggering time of milestones
are store in columns |
Value
A data frame of class milestone_time_summary
.
Examples
# a minimum, meaningful, and executable example,
# where a randomized trial with two arms is simulated and analyzed.
control <- arm(name = 'control arm')
active <- arm(name = 'active arm')
pfs_in_control <- endpoint(name = 'PFS', type = 'tte', generator = rexp, rate = log(2) / 5)
control$add_endpoints(pfs_in_control)
pfs_in_active <- endpoint(name = 'PFS', type = 'tte', generator = rexp, rate = log(2) / 6)
active$add_endpoints(pfs_in_active)
accrual_rate <- data.frame(end_time = c(10, Inf), piecewise_rate = c(30, 50))
trial <- trial(name = 'trial',
n_patients = 1000,
duration = 40,
enroller = StaggeredRecruiter,
accrual_rate = accrual_rate,
dropout = rweibull, shape = 2, scale = 38,
silent = TRUE)
trial$add_arms(sample_ratio = c(1, 1), control, active)
action_at_final <- function(trial, milestone_name){
locked_data <- trial$get_locked_data(milestone_name)
fitLogrank(Surv(PFS, PFS_event) ~ arm, placebo = 'control arm',
data = locked_data, alternative = 'less')
invisible(NULL)
}
final <- milestone(name = 'final analysis',
action = action_at_final,
when = eventNumber(endpoint = 'PFS', n = 300))
listener <- listener(silent = TRUE)
listener$add_milestones(final)
controller <- controller(trial, listener)
controller$run(n = 10, plot_event = FALSE, silent = TRUE)
output <- controller$get_output()
time <- summarizeMilestoneTime(output)
time
plot(time)
Define a Trial
Description
Define a trial. This is a user-friendly wrapper for
the class constructor Trial$new
. Users who are not familiar with
the concept of classes may consider using this wrapper directly.
Usage
trial(
name,
n_patients,
duration,
description = name,
seed = NULL,
enroller,
dropout = NULL,
silent = FALSE,
...
)
Arguments
name |
character. Name of trial. |
n_patients |
integer. Maximum number of patients could be enrolled to the trial. |
duration |
Numeric. Trial duration. |
description |
character. Optional for description of the trial. By
default it is set to be trial's |
seed |
random seed. If |
enroller |
a function returning a vector enrollment time for patients. Its first argument is the number of enrolled patients. |
dropout |
a function returning a vector of dropout time for patients. Its first argument is the number of enrolled patients. |
silent |
logical. |
... |
arguments of |
Examples
risk1 <- data.frame(
end_time = c(1, 10, 26.0, 52.0),
piecewise_risk = c(1, 1.01, 0.381, 0.150) * exp(-3.01)
)
pfs1 <- endpoint(name = 'pfs', type='tte',
generator = PiecewiseConstantExponentialRNG,
risk = risk1, endpoint_name = 'pfs')
orr1 <- endpoint(
name = 'orr', type = 'non-tte',
readout = c(orr=1), generator = rbinom,
size = 1, prob = .4)
placebo <- arm(name = 'pbo')
placebo$add_endpoints(pfs1, orr1)
risk2 <- risk1
risk2$hazard_ratio <- .8
pfs2 <- endpoint(name = 'pfs', type='tte',
generator = PiecewiseConstantExponentialRNG,
risk = risk2, endpoint_name = 'pfs')
orr2 <- endpoint(
name = 'orr', type = 'non-tte',
generator = rbinom, readout = c(orr=3),
size = 1, prob = .6)
active <- arm(name = 'ac')
active$add_endpoints(pfs2, orr2)
## Plan a trial, Trial-3415, of up to 100 patients.
## Enrollment time follows an exponential distribution, with median 5
trial <- trial(
name = 'Trial-3415', n_patients = 100,
seed = 31415926, duration = 100,
enroller = rexp, rate = log(2) / 5)
trial$add_arms(sample_ratio = c(1, 2), placebo, active)
trial
Calculate Parameters of Weibull Distribution as a Dropout Method
Description
Fit scale and shape parameters of the Weibull distribution to match dropout rates at two specified time points.
Usage
weibullDropout(time, dropout_rate)
Arguments
time |
a numeric vector of two time points at which dropout rates are specified. |
dropout_rate |
a numeric vector of dropout rates at |
Value
a named vector for scale and shape parameters.