Skip to contents

A unified function that generates random samples of oncology endpoints with flexible configurations. This function supports seven different patterns:

  1. OS only

  2. PFS only

  3. Response only

  4. OS + Response (correlated)

  5. PFS + Response (correlated)

  6. OS + PFS (correlated, with PFS <= OS constraint)

  7. OS + PFS + Response (all correlated, with PFS <= OS constraint)

This function is designed specifically for oncology clinical trial simulations, particularly for generating objective response (Response), progression-free survival (PFS), and overall survival (OS) data with appropriate correlation structure.

Usage

rOncoEndpoints(
  nsim,
  group = NULL,
  n,
  p = NULL,
  hazard_OS = NULL,
  hazard_PFS = NULL,
  rho_tte_resp = NULL,
  copula = NULL
)

Arguments

nsim

Integer. The number of simulations to perform. Must be a positive integer.

group

Character vector. Names of the treatment groups. If NULL (default), groups will be named "Group1", "Group2", etc. Length must match the lengths of other vector parameters.

n

Integer vector. Sample sizes for each group. All elements must be positive integers. Length must match the number of groups.

p

Numeric vector or NULL. Marginal probabilities of objective response for each group. If NULL, no Response endpoint is generated. When provided, all elements must be between 0 and 1 (exclusive). Length must match the number of groups. Default is NULL.

hazard_OS

Numeric vector or NULL. Hazard rates for OS for each group. If NULL, no OS endpoint is generated. When provided, all elements must be positive. Length must match the number of groups. Default is NULL.

hazard_PFS

Numeric vector or NULL. Hazard rates for PFS for each group. If NULL, no PFS endpoint is generated. When provided, all elements must be positive. If both hazard_OS and hazard_PFS are provided, hazard_PFS must be strictly greater than hazard_OS to ensure PFS <= OS. Length must match the number of groups. Default is NULL.

rho_tte_resp

Numeric vector or NULL. Desired correlation coefficients between a time-to-event endpoint and Response. Required when both a TTE endpoint (OS or PFS) and p are provided. All elements must be within the feasible range determined by Fréchet-Hoeffding bounds (which depend only on p, not on hazard rates). Length must match the number of groups. Default is NULL.

copula

Character or NULL. The copula family to use for modeling the dependence between TTE and Response. Options are "Clayton" or "Frank". Required when p and at least one TTE endpoint are provided (defaults to "Clayton" if not specified). Default is NULL.

Value

A data frame with nsim * sum(n) rows and columns depending on the configuration:

  • OS only: simID, Group, OS

  • PFS only: simID, Group, PFS

  • Response only: simID, Group, Response

  • OS + Response: simID, Group, OS, Response

  • PFS + Response: simID, Group, PFS, Response

  • OS + PFS: simID, Group, OS, PFS

  • OS + PFS + Response: simID, Group, OS, PFS, Response

Details

This function provides seven modes of operation based on which parameters are provided:

Single endpoint modes:

  • OS only (hazard_OS provided)

  • PFS only (hazard_PFS provided)

  • Response only (p provided)

Two endpoint modes:

  • OS + Response (hazard_OS + p): Correlated via copula specified by rho_tte_resp. The copula parameter is determined solely by p and rho_tte_resp, independent of hazard_OS.

  • PFS + Response (hazard_PFS + p): Correlated via copula specified by rho_tte_resp. The copula parameter is determined solely by p and rho_tte_resp, independent of hazard_PFS.

  • OS + PFS (hazard_OS + hazard_PFS): Correlated using the Fleischer model, ensuring PFS <= OS. The correlation is directly determined by the hazard ratio: Corr(OS, PFS) = hazard_OS / hazard_PFS.

Three endpoint mode:

  • OS + PFS + Response (all three provided): The PFS <= OS constraint is maintained using the Fleischer model. The Response endpoint is correlated with OS (not PFS) via the copula specified by rho_tte_resp. The copula parameter depends only on p and rho_tte_resp.

Note

CRITICAL: Correlation structure in three-endpoint mode (OS + PFS + Response):

  • Response is correlated with OS via rho_tte_resp (user-specified)

  • Response is NOT directly correlated with PFS

  • The correlation between PFS and Response emerges automatically from the model structure and is NOT user-specified

  • To predict the resulting PFS-Response correlation, use CorResponsePFS with your specified parameters

  • This design reflects the biological assumption that response and survival are linked through the underlying disease process

Important implementation details:

  • The correlation between a binary Response endpoint and an exponentially distributed TTE endpoint depends only on the response probability (p) and the copula parameter, not on the TTE hazard rate. This is a key theoretical property that simplifies the correlation structure.

  • The feasible range of correlations between Response and TTE endpoints is determined by Fréchet-Hoeffding bounds, which depend only on p.

  • For the OS-PFS relationship (Fleischer model), the correlation is directly determined by the ratio of hazard rates.

Copula selection: The function uses copula-based methods to model dependencies:

  • Clayton copula: Suitable for lower tail dependence (strong correlation at low values). Cannot model negative dependence.

  • Frank copula: Flexible for both positive and negative dependence with symmetric tail behavior.

References

Fleischer, F., Gaschler-Markefski, B., & Bluhmki, E. (2009). A statistical model for the dependence between progression-free survival and overall survival. Statistics in Medicine, 28(21), 2669-2686.

Trivedi, P. K., & Zimmer, D. M. (2005). Copula modeling: an introduction for practitioners. Foundations and Trends in Econometrics, 1(1), 1-111.

Examples

# Example 1: OS only
set.seed(123)
data1 <- rOncoEndpoints(
  nsim = 100,
  group = c("Treatment", "Control"),
  n = c(100, 100),
  hazard_OS = c(0.05, 0.07)
)
head(data1)
#>   simID     Group         OS
#> 1     1 Treatment  6.7816835
#> 2     1 Treatment 31.0521872
#> 3     1 Treatment 10.5180043
#> 4     1 Treatment 42.9146021
#> 5     1 Treatment 56.4245855
#> 6     1 Treatment  0.9325366

# Example 2: Response only
set.seed(456)
data2 <- rOncoEndpoints(
  nsim = 100,
  group = c("Treatment", "Control"),
  n = c(100, 100),
  p = c(0.4, 0.3)
)
head(data2)
#>   simID     Group Response
#> 1     1 Treatment        0
#> 2     1 Treatment        0
#> 3     1 Treatment        1
#> 4     1 Treatment        1
#> 5     1 Treatment        1
#> 6     1 Treatment        0

# Example 3: OS and Response with Clayton copula
set.seed(789)
data3 <- rOncoEndpoints(
  nsim = 1000,
  group = c("Treatment", "Control"),
  n = c(100, 100),
  p = c(0.4, 0.3),
  hazard_OS = c(0.05, 0.07),
  rho_tte_resp = c(0.3, 0.2),
  copula = "Clayton"
)
head(data3)
#>   simID     Group         OS Response
#> 1     1 Treatment 24.0724149        0
#> 2     1 Treatment  1.9632601        0
#> 3     1 Treatment  0.2391606        0
#> 4     1 Treatment 17.9104750        1
#> 5     1 Treatment 13.5513608        0
#> 6     1 Treatment  0.4073927        0

# Example 4: PFS and Response with Frank copula
set.seed(101)
data4 <- rOncoEndpoints(
  nsim = 1000,
  group = c("Treatment", "Control"),
  n = c(100, 100),
  p = c(0.5, 0.4),
  hazard_PFS = c(0.08, 0.10),
  rho_tte_resp = c(0.25, 0.15),
  copula = "Frank"
)
head(data4)
#>   simID     Group        PFS Response
#> 1     1 Treatment  5.8191381        1
#> 2     1 Treatment  0.5601767        0
#> 3     1 Treatment 15.4598170        0
#> 4     1 Treatment 13.4004960        1
#> 5     1 Treatment  3.5936215        0
#> 6     1 Treatment  4.4594160        1

# Example 5: OS and PFS (Fleischer model)
# Correlation between OS and PFS = hazard_OS / hazard_PFS
set.seed(112)
data5 <- rOncoEndpoints(
  nsim = 1000,
  group = c("Treatment", "Control"),
  n = c(100, 100),
  hazard_OS = c(log(2) / 20, log(2) / 16),
  hazard_PFS = c(log(2) / 14, log(2) / 10)
)
head(data5)
#>   simID     Group         OS        PFS
#> 1     1 Treatment  13.638756  13.638756
#> 2     1 Treatment  73.614834  73.614834
#> 3     1 Treatment 138.878055 138.878055
#> 4     1 Treatment 109.142065 109.142065
#> 5     1 Treatment   7.778338   7.778338
#> 6     1 Treatment   3.267516   3.267516
# Verify correlation
with(subset(data5, Group == "Treatment"), cor(OS, PFS))
#> [1] 0.6970372

# Example 6: All three endpoints with Frank copula
# IMPORTANT: Response is correlated with OS, not PFS!
set.seed(131)
data6 <- rOncoEndpoints(
  nsim = 1000,
  group = "Experimental",
  n = 150,
  p = 0.5,
  hazard_OS = 0.04,
  hazard_PFS = 0.06,
  rho_tte_resp = 0.3,  # This is the correlation between OS and Response
  copula = "Frank"
)
head(data6)
#>   simID        Group        OS       PFS Response
#> 1     1 Experimental  5.780558  5.780558        0
#> 2     1 Experimental  3.336632  3.336632        0
#> 3     1 Experimental  8.677777  8.677777        1
#> 4     1 Experimental 11.781298 11.781298        0
#> 5     1 Experimental 46.826435 46.448680        1
#> 6     1 Experimental 18.833300 18.833300        0

# Verify correlations
cat("OS-Response correlation:", cor(data6$OS, data6$Response), "\n")
#> OS-Response correlation: 0.2976105 
cat("PFS-Response correlation:", cor(data6$PFS, data6$Response), "\n")
#> PFS-Response correlation: 0.2403529 

# Predict PFS-Response correlation using CorResponsePFS
predicted_cor <- CorResponsePFS(
  p = 0.5,
  hazard_OS = 0.04,
  hazard_PFS = 0.06,
  rho_OS_Response = 0.3,
  copula = "Frank"
)
cat("Predicted PFS-Response correlation:", predicted_cor, "\n")
#> Predicted PFS-Response correlation: 0.2414616