Skip to content

Commit aa48743

Browse files
author
NightlordTW
committed
Moved construction of varcov_list to dedicated function
1 parent 20a437b commit aa48743

File tree

3 files changed

+128
-44
lines changed

3 files changed

+128
-44
lines changed

R/SampleSize.R

Lines changed: 79 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -165,50 +165,14 @@ sampleSize <- function(mu_list, varcov_list = NA, sigma_list = NA, cor_mat = NA,
165165
mu_list[[i]] <- mu
166166
}
167167

168+
# Derive the list of covariance matrices
169+
varcov_list <- derive_varcov_list(mu_list = mu_list, sigma_list = sigma_list,
170+
ynames_list = ynames_list,
171+
varcov_list = varcov_list, cor_mat = cor_mat,
172+
rho = rho)
168173

169174

170175

171-
# Varcov specfication
172-
if (any(is.na(varcov_list))) {
173-
if (any(is.na(sigma_list))) {
174-
stop("No variance-covariance matrix provided, and a standard deviation list is also missing. Either a variance-covariance matrix or a standard deviation list is required.")
175-
}
176-
177-
# length in terms of endpoints
178-
len_mu <- sapply(mu_list,length)
179-
len_sd <- sapply(sigma_list,length)
180-
len_y <- sapply(ynames_list,length) # number of endpoints
181-
182-
if (any((len_mu != len_sd) | (len_mu != len_y))) {
183-
stop("In each arm, 'mu', 'sigma', and 'y_name' must have the same length.")
184-
}
185-
186-
varcov_list <- NULL
187-
188-
for (i in 1:n) {
189-
m <- length(sigma_list[[i]]) # number of endpoints
190-
191-
if (m == 1) {
192-
varcov <- as.matrix(sigma_list[[i]]^2)
193-
194-
} else {
195-
R <- matrix(rho, m, m)
196-
diag(R) <- 1 # correlation matrix
197-
198-
if (any(!is.na(cor_mat))) {
199-
if ((nrow(cor_mat) == m) & (ncol(cor_mat) == m)) {
200-
R <- as.matrix(cor_mat)
201-
} else {
202-
warning("An uncorrelated matrix will be used as the provided matrix does not have the expected dimensions.")
203-
}
204-
}
205-
206-
varcov <- diag(sigma_list[[i]]) %*% R %*% diag(sigma_list[[i]])
207-
}
208-
209-
varcov_list[[i]] <- varcov
210-
}
211-
}
212176

213177
weight_seq <- NA
214178
param.u <- list(mu = mu_list, varcov = varcov_list, TAR_list = TAR_list,
@@ -697,4 +661,78 @@ derive_allocation_rate <- function(TAR = NULL, arm_names, verbose = FALSE) {
697661
return(TAR_list)
698662
}
699663

664+
#' Derive Variance-Covariance Matrix List
665+
#'
666+
#' Constructs a list of variance-covariance matrices for multiple treatment arms based on provided standard deviations,
667+
#' means, and correlation structures.
668+
#'
669+
#' @param mu_list A list of numeric vectors representing the means (\eqn{\mu}) for each treatment arm. Each element corresponds to one arm.
670+
#' @param sigma_list A list of numeric vectors representing the standard deviations (\eqn{\sigma}) for each treatment arm. Each element corresponds to one arm.
671+
#' @param ynames_list A list of character vectors specifying the names of the endpoints for each arm. Each element corresponds to one arm.
672+
#' @param varcov_list (Optional) A pre-specified list of variance-covariance matrices for each arm. If provided, it will override the construction of variance-covariance matrices.
673+
#' @param cor_mat (Optional) A correlation matrix to be used for constructing the variance-covariance matrices when there are multiple endpoints. If dimensions do not match the number of endpoints, a warning is issued.
674+
#' @param rho (Optional) A numeric value specifying the constant correlation coefficient to be used between all pairs of endpoints if no correlation matrix is provided. Default is 0 (uncorrelated endpoints).
675+
#'
676+
#' @details
677+
#' This function creates a list of variance-covariance matrices for multiple treatment arms. If the \code{varcov_list} is not provided,
678+
#' the function uses the \code{sigma_list} to compute the matrices. For single endpoints, the variance is simply the square of the standard deviation.
679+
#' For multiple endpoints, the function constructs the matrices using either a provided \code{cor_mat} or the constant correlation coefficient \code{rho}.
680+
#'
681+
#' The function ensures that the lengths of \code{mu_list}, \code{sigma_list}, and \code{ynames_list} match for each arm. If dimensions mismatch,
682+
#' or if neither a variance-covariance matrix (\code{varcov_list}) nor a standard deviation list (\code{sigma_list}) is provided, an error is raised.
683+
#'
684+
#' @return A list of variance-covariance matrices, one for each treatment arm.
685+
#'
686+
#' @author Thomas Debray \email{[email protected]}
687+
derive_varcov_list <- function(mu_list, sigma_list, ynames_list, varcov_list = NULL, cor_mat = NULL, rho = 0) {
688+
# Check if variance-covariance matrix is missing
689+
if (any(is.na(varcov_list))) {
690+
if (any(is.na(sigma_list))) {
691+
stop("No variance-covariance matrix provided, and a standard deviation list is also missing. Either a variance-covariance matrix or a standard deviation list is required.")
692+
}
693+
694+
# Validate lengths of inputs
695+
len_mu <- sapply(mu_list, length)
696+
len_sd <- sapply(sigma_list, length)
697+
len_y <- sapply(ynames_list, length) # Number of endpoints
698+
699+
if (any((len_mu != len_sd) | (len_mu != len_y))) {
700+
stop("In each arm, 'mu', 'sigma', and 'y_name' must have the same length.")
701+
}
702+
703+
# Initialize the varcov_list
704+
varcov_list <- vector("list", length(mu_list))
705+
706+
# Loop through each arm to construct the variance-covariance matrices
707+
for (i in seq_along(sigma_list)) {
708+
m <- length(sigma_list[[i]]) # Number of endpoints
709+
710+
if (m == 1) {
711+
# Single endpoint: variance is the square of the standard deviation
712+
varcov <- as.matrix(sigma_list[[i]]^2)
713+
} else {
714+
# Multiple endpoints: construct the correlation matrix
715+
R <- matrix(rho, m, m)
716+
diag(R) <- 1 # Set diagonal to 1 (self-correlation)
717+
718+
# Use the provided correlation matrix if dimensions match
719+
if (any(!is.na(cor_mat))) {
720+
if ((nrow(cor_mat) == m) & (ncol(cor_mat) == m)) {
721+
R <- as.matrix(cor_mat)
722+
} else {
723+
warning("An uncorrelated matrix will be used as the provided matrix does not have the expected dimensions.")
724+
}
725+
}
726+
727+
# Construct the variance-covariance matrix
728+
varcov <- diag(sigma_list[[i]]) %*% R %*% diag(sigma_list[[i]])
729+
}
730+
731+
# Add the matrix to the list
732+
varcov_list[[i]] <- varcov
733+
}
734+
}
735+
736+
return(varcov_list)
737+
}
700738

man/derive_varcov_list.Rd

Lines changed: 46 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vignettes/sampleSize_parallel_2A3E.Rmd

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,10 @@ library(SimTOST)
9191
))
9292
```
9393

94-
When testing each PK measure independently, the total sample size is `r sim_AUCinf$response$n_total` for AUCinf, `r sim_AUClast$response$n_total` for AUClast, and `r sim_Cmax$response$n_total` for Cmax. This means that we would have to enroll `r sim_AUCinf$response$n_total` + `r sim_AUClast$response$n_total` + `r sim_Cmax$response$n_total` = `r sim_AUCinf$response$n_total + sim_AUClast$response$n_total + sim_Cmax$response$n_total` patients in order to reject $H_0$ at a significance level of 5\%. For context, the original trial was a randomized, single-blind, three-arm, parallel-group study conducted in 159 healthy subjects, slightly more than the `r sim_AUCinf$response$n_total + sim_AUClast$response$n_total + sim_Cmax$response$n_total` patients estimated to be necessary. This suggests that the original trial had a small buffer above the calculated sample size requirements.
94+
When testing each PK measure independently, the total sample size is `r sim_AUCinf$response$n_total` for AUCinf, `r sim_AUClast$response$n_total` for AUClast, and `r sim_Cmax$response$n_total` for Cmax. This means that we would have to enroll `r sim_AUCinf$response$n_total` + `r sim_AUClast$response$n_total` + `r sim_Cmax$response$n_total` = `r sim_AUCinf$response$n_total + sim_AUClast$response$n_total + sim_Cmax$response$n_total` patients in order to reject $H_0$. Note that the significance level of this combined test is then $0.05^3$. For context, the original trial was a randomized, single-blind, three-arm, parallel-group study conducted in 159 healthy subjects, slightly more than the `r sim_AUCinf$response$n_total + sim_AUClast$response$n_total + sim_Cmax$response$n_total` patients estimated to be necessary.
9595

9696
# Simultaneous Testing of Independent Co-Primary Endpoints
97-
This approach focuses on simultaneous testing of PK measures while assuming independence between endpoints. Unlike the previous approach, which tested each PK measure independently, this method integrates comparisons across multiple endpoints, accounting for correlations (or lack thereof) between them, thus enabling simultaneous testing for equivalence without inflating the overall Type I error rate.
97+
This approach focuses on simultaneous testing of PK measures while assuming independence between endpoints. Unlike the previous approach, which tested each PK measure independently, this approach integrates comparisons across multiple endpoints while directly controlling the overall Type I error rate at a pre-specified level.
9898

9999
## Key Assumptions
100100
In the calculations below, the following assumptions are made:
@@ -213,7 +213,7 @@ Imagine that we are interested in demonstrating equivalence for at least $k=1$ o
213213
seed = 1234 # Random seed for reproducibility
214214
))
215215
```
216-
As mentioned in [the Introduction](../articles/intopkg.html), Bonferroni adjustment is often overly conservative, especially in scenarios with correlated tests. A less restrictive alternative is the *k*-adjustment, which specifically accounts for the number of tests and the number of endpoints required for equivalence.
216+
As mentioned in [the Introduction](../articles/intropkg.html), Bonferroni adjustment is often overly conservative, especially in scenarios with correlated tests. A less restrictive alternative is the *k*-adjustment, which specifically accounts for the number of tests and the number of endpoints required for equivalence.
217217

218218
```{r}
219219
(N_mp_k <- sampleSize(

0 commit comments

Comments
 (0)