Nothing
#' Define endpoints
#'
#' @description
#' Define one or multiple endpoints. This is a user-friendly wrapper for
#' the class constructor \code{Endpoint$new}. Users who are not familiar with
#' the concept of classes may consider using this wrapper directly.
#' wrapper if
#' @param name character vector. Name(s) of endpoint(s)
#' @param type character vector. Type(s) of endpoint(s). It supports
#' \code{"tte"} for time-to-event endpoints, and \code{"non-tte"} for
#' all other types of endpoints (e.g., continous, binary, categorical,
#' or repeated measurement. \code{TrialSimulator} will do some verification if
#' an endpoint is of type \code{"tte"}. However, no special
#' manipulation is done for non-tte endpoints.
#' @param 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 \code{stats}, e.g., \code{stats::rnorm},
#' \code{stats::rexp}, etc. that with \code{n} as the argument for number of
#' observations. \code{generator} could be any custom functions as long as
#' (1) its first argument is \code{n}; and (2) it returns a vector of
#' length \code{n} or a data frame of \code{n} 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 to \code{name} exactly. If an endpoint
#' is of type \code{"tte"}, the custom \code{generator} should also return
#' a column as event indicator. For example, if \code{"pfs"} is \code{"tte"},
#' then custom \code{generator} should return at least two columns
#' \code{"pfs"} and \code{"pfs_event"}. Usually \code{pfs_event} can be
#' all 1s if no censoring. Censoring can be specified later when defining
#' the \code{Trial} through argument \code{dropout}. See \code{?Trial}.
#' Note that if covariates, e.g., biomarker, subgroup, are needed in
#' generating and analyzing trial data, they can be defined as
#' \code{Endpoint} as well.
#' @param readout numeric vector with name to be the non-tte endpoint(s).
#' \code{readout} should be specified for every non-tte endpoint. For
#' example, \code{c(endpoint1 = 6, endpoint2 = 3)}. If all
#' endpoints are tte, \code{readout} can be \code{NULL}.
#' @param ... optional arguments for \code{generator}.
#'
#' @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
# ## censoring)
#' ## 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
#'
#' }
#'
#' @export
endpoint = function(
name,
type = c('tte', 'non-tte'),
readout = NULL,
generator,
...
){
Endpoints$new(
name = name,
type = type,
readout = readout,
generator = generator,
...
)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.