From a6428507cbbcc8907fcc578f3d99f618e18e0d2c Mon Sep 17 00:00:00 2001 From: Thomas Debray <117118104+tdebray123@users.noreply.github.com> Date: Mon, 18 Nov 2024 21:01:48 +0100 Subject: [PATCH] Update vignettes and documentation --- R/SampleSize.R | 26 +++++++++++++---------- man/sampleSize.Rd | 20 +++++++++++------- vignettes/sampleSize_crossover.Rmd | 5 +---- vignettes/sampleSize_parallel.Rmd | 34 ++++++++++++++++++------------ 4 files changed, 48 insertions(+), 37 deletions(-) diff --git a/R/SampleSize.R b/R/SampleSize.R index 5d76007..f10be22 100644 --- a/R/SampleSize.R +++ b/R/SampleSize.R @@ -71,22 +71,26 @@ #' lequi.tol <- c(AUCinf = 0.8, AUClast = 0.8, Cmax = 0.8) #' uequi.tol <- c(AUCinf = 1.25, AUClast = 1.25, Cmax = 1.25) #' -#' # arms to be compared +#' # Arms to be compared #' list_comparator <- list(EMA = c("SB2", "EUREF"), #' FDA = c("SB2", "USREF")) #' -#'# Endpoints to be compared -#'list_y_comparator <- list(EMA = c("AUCinf", "Cmax"), -#' FDA = c("AUClast", "Cmax")) +#' # Endpoints to be compared +#' list_y_comparator <- list(EMA = c("AUCinf", "Cmax"), +#' FDA = c("AUClast", "Cmax")) #' -#'# Run the simulation -#'sampleSize(power = 0.9, alpha = 0.05, mu_list = mu_list, -#' sigma_list = sigma_list, lequi.tol = lequi.tol, -#' uequi.tol = uequi.tol, list_comparator = list_comparator, -#' list_y_comparator = list_y_comparator, adjust = "no", -#' dtype = "parallel", ctype = "ROM", vareq = FALSE, -#' lognorm = TRUE, ncores = 1, nsim = 50, seed = 1234) +#' # Equivalence boundaries for each comparison +#' lequi_lower <- c(AUCinf = 0.80, AUClast = 0.80, Cmax = 0.80) +#' lequi_upper <- c(AUCinf = 1.25, AUClast = 1.25, Cmax = 1.25) #' +#'# Run the simulation +#' sampleSize(power = 0.9, alpha = 0.05, mu_list = mu_list, +#' sigma_list = sigma_list, list_comparator = list_comparator, +#' list_y_comparator = list_y_comparator, +#' list_lequi.tol = list("EMA" = lequi_lower, "FDA" = lequi_lower), +#' list_uequi.tol = list("EMA" = lequi_upper, "FDA" = lequi_upper), +#' adjust = "no", dtype = "parallel", ctype = "ROM", vareq = FALSE, +#' lognorm = TRUE, ncores = 1, nsim = 50, seed = 1234) #' @export sampleSize <- function(mu_list, varcov_list = NA, sigma_list = NA, cor_mat = NA, sigmaB =NA, Eper, Eco, rho = 0, TAR = NULL, diff --git a/man/sampleSize.Rd b/man/sampleSize.Rd index 0cb79f0..ff93132 100644 --- a/man/sampleSize.Rd +++ b/man/sampleSize.Rd @@ -150,22 +150,26 @@ sigma_list <- list(SB2 = c(AUCinf = 11114, AUClast = 9133, Cmax = 16.9), lequi.tol <- c(AUCinf = 0.8, AUClast = 0.8, Cmax = 0.8) uequi.tol <- c(AUCinf = 1.25, AUClast = 1.25, Cmax = 1.25) -# arms to be compared +# Arms to be compared list_comparator <- list(EMA = c("SB2", "EUREF"), FDA = c("SB2", "USREF")) # Endpoints to be compared list_y_comparator <- list(EMA = c("AUCinf", "Cmax"), - FDA = c("AUClast", "Cmax")) + FDA = c("AUClast", "Cmax")) + +# Equivalence boundaries for each comparison +lequi_lower <- c(AUCinf = 0.80, AUClast = 0.80, Cmax = 0.80) +lequi_upper <- c(AUCinf = 1.25, AUClast = 1.25, Cmax = 1.25) # Run the simulation sampleSize(power = 0.9, alpha = 0.05, mu_list = mu_list, - sigma_list = sigma_list, lequi.tol = lequi.tol, - uequi.tol = uequi.tol, list_comparator = list_comparator, - list_y_comparator = list_y_comparator, adjust = "no", - dtype = "parallel", ctype = "ROM", vareq = FALSE, - lognorm = TRUE, ncores = 1, nsim = 50, seed = 1234) - + sigma_list = sigma_list, list_comparator = list_comparator, + list_y_comparator = list_y_comparator, + list_lequi.tol = list("EMA" = lequi_lower, "FDA" = lequi_lower), + list_uequi.tol = list("EMA" = lequi_upper, "FDA" = lequi_upper), + adjust = "no", dtype = "parallel", ctype = "ROM", vareq = FALSE, + lognorm = TRUE, ncores = 1, nsim = 50, seed = 1234) } \references{ Mielke, J., Jones, B., Jilma, B., & König, F. (2018). Sample size for multiple hypothesis testing in biosimilar development. Statistics in Biopharmaceutical Research, 10(1), 39-49. diff --git a/vignettes/sampleSize_crossover.Rmd b/vignettes/sampleSize_crossover.Rmd index 1b90df4..f27ad44 100644 --- a/vignettes/sampleSize_crossover.Rmd +++ b/vignettes/sampleSize_crossover.Rmd @@ -20,8 +20,6 @@ knitr::opts_chunk$set(echo = TRUE) knitr::opts_chunk$set(comment = "#>", collapse = TRUE) options(rmarkdown.html_vignette.check_title = FALSE) #title of doc does not match vignette title doc.cache <- T #for cran; change to F - -library(dplyr) ``` @@ -43,7 +41,6 @@ sigma <- c(AUC = 0.25, Cmax = 0.3) lequi_lower <- c(AUC = log(0.80), Cmax = log(0.80)) lequi_upper <- c(AUC = log(1.25), Cmax = log(1.25)) - ss <- sampleSize(power = 0.8, alpha = 0.05, mu_list = list("R" = mu_r, "T" = mu_t), sigma_list = list("R" = sigma, "T" = sigma), @@ -55,7 +52,7 @@ ss <- sampleSize(power = 0.8, alpha = 0.05, adjust = "no", ncores = 1, nsim = 10000, seed = 1234) ss ``` -The total sample size is `r ss$response %>% pull(n_total)` subjects. +The total sample size is `r ss$response$n_total` subjects. diff --git a/vignettes/sampleSize_parallel.Rmd b/vignettes/sampleSize_parallel.Rmd index 88a2065..4bbfa6a 100644 --- a/vignettes/sampleSize_parallel.Rmd +++ b/vignettes/sampleSize_parallel.Rmd @@ -20,8 +20,6 @@ knitr::opts_chunk$set(echo = TRUE) knitr::opts_chunk$set(comment = "#>", collapse = TRUE) options(rmarkdown.html_vignette.check_title = FALSE) #title of doc does not match vignette title doc.cache <- T #for cran; change to F - -library(dplyr) ``` @@ -69,11 +67,14 @@ ss <- sampleSize(power = 0.8, alpha = 0.05, adjust = "no", ncores = 1, nsim = 10000, seed = 1234) ss ``` -For 80\% power, a total of `r ss$response %>% pull(n_total)` would be required. +For 80\% power, a total of `r ss$response$n_total` would be required. # Multiple Correlated Co-Primary Endpoints -In the second example, we have $k=m=5$, $\sigma = 0.3$ and $\rho = 0.8$. Again, we can estimate the sample size using the functions provided by @mielke_sample_2018: +In the second example, we have $k=m=5$, $\sigma = 0.3$ and $\rho = 0.8$. This example is also adapted from @mielke_sample_2018, who employed a difference-of-means test on the log scale. The sample size calculation can again be conducted using two approaches, both of which are illustrated below. + +## Approach 1: Using sampleSize_Mielke +In the first approach, we calculate the required sample size for 80% power using the [sampleSize_Mielke()](../reference/sampleSize_Mielke.html) function. This method directly follows the approach described in @mielke_sample_2018, assuming a difference-of-means test on the log-transformed scale with specified parameters. ```{r, eval = TRUE} ssMielke <- sampleSize_Mielke(power = 0.8, Nmax = 1000, m = 5, k = 5, rho = 0.8, @@ -83,20 +84,25 @@ ssMielke <- sampleSize_Mielke(power = 0.8, Nmax = 1000, m = 5, k = 5, rho = 0.8, nsim = 10000) ssMielke ``` -For 80\% power, `r ssMielke["SS"]` subjects per sequence (`r ssMielke["SS"] * 2` in total) would have been required. +For 80\% power, `r ssMielke["SS"]` subjects per sequence (`r ssMielke["SS"] * 2` in total) would be been required. -We can perform the same analysis using [sampleSize()](../reference/sampleSize.html). In this case, we provide estimates for $\mu$ and $\sigma$ on the original scale, assuming they follow a normal distribution on the log scale (`lognorm = TRUE`). Instead of testing the difference of log-transformed means, we now test the ratio of the (untransformed) means. +## Approach 2: Using sampleSize +Alternatively, the sample size calculation can be performed using the [sampleSize()](../reference/sampleSize.html) function. This method assumes that effect sizes are normally distributed on the log scale and uses a difference-of-means test (`ctype = "DOM"`) with user-specified values for `mu_list`, `sigma_list`, and the correlation `rho`. + +```{r} +mu_r <- c(AUC = log(1.00), Cmax = log(1.00)) +mu_t <- c(AUC = log(1.02), Cmax = log(1.03)) +sigma <- c(AUC = 0.25, Cmax = 0.3) +lequi_lower <- c(AUC = log(0.80), Cmax = log(0.80)) +lequi_upper <- c(AUC = log(1.25), Cmax = log(1.25)) -```{r, eval = TRUE} ss <- sampleSize(power = 0.8, alpha = 0.05, - mu_list = list("R" = rep(1.00, 5), - "T" = rep(1.05, 5)), - sigma_list = list("R" = rep(0.3, 5), - "T" = rep(0.3, 5)), + mu_list = list("R" = mu_r, "T" = mu_t), + sigma_list = list("R" = sigma, "T" = sigma), rho = 0.8, # high correlation between the endpoints - lequi.tol = rep(0.8, 5), - uequi.tol = rep(1.25, 5), - dtype = "parallel", ctype = "ROM", lognorm = TRUE, + list_lequi.tol = list("T_vs_R" = lequi_lower), + list_uequi.tol = list("T_vs_R" = lequi_upper), + dtype = "parallel", ctype = "DOM", lognorm = FALSE, adjust = "no", ncores = 1, k = 5, nsim = 10000, seed = 1234) ss ```