Calculate optimal design parameters for a single-stage gold-standard design
Source:R/optimization_methods.R
optimize_design_onestage.Rd
Calculate optimal design parameters for a single-stage gold-standard design
Usage
optimize_design_onestage(
cP1 = NULL,
cC1 = NULL,
alpha = 0.025,
beta = 0.2,
alternative_TP = 0.4,
alternative_TC = 0,
Delta = 0.2,
varT = 1,
varP = 1,
varC = 1,
round_n = TRUE,
kappa = 0,
objective = quote(sum(unlist(n)) + kappa * n[[1]][["P"]]),
inner_tol_objective = 1e-07,
mvnorm_algorithm = mvtnorm::Miwa(steps = 4097, checkCorr = FALSE, maxval = 1000),
nloptr_x0 = NULL,
nloptr_lb = NULL,
nloptr_ub = NULL,
nloptr_opts = list(algorithm = "NLOPT_LN_SBPLX", ftol_rel = 1e-09, xtol_abs = 1e-08,
xtol_rel = 1e-07, maxeval = 1000, print_level = 0),
print_progress = TRUE,
...
)
Arguments
- cP1
(numeric) allocation ratio nP1 / nT1. Parameter to be optimized if left unspecified.
- cC1
(numeric) allocation ratio nC1 / nT1. Parameter to be optimized if left unspecified.
- alpha
type I error rate.
- beta
type II error rate.
- alternative_TP
assumed difference between T and P under H1. Positive values favor T.
- alternative_TC
assumed difference between T and C under H1. Positive values favor T.
- Delta
non-inferiority margin for the test \(X_T - X_C \leq - \Delta\) vs. \(X_T - X_C > - \Delta\).
- varT
variance of treatment group.
- varP
variance of placebo group.
- varC
variance of control group.
- round_n
(logical) if TRUE, a design with integer valued sample sizes is returned.
- kappa
(numeric) penalty factor for placebo patients in the default objective function.
- objective
(expression) objective criterion.
- inner_tol_objective
(numeric) used to determine the tolerances for integrals and nuisance optimization problems inside the objective function.
- mvnorm_algorithm
algorithm for multivariate integration passed to
pmvnorm
.- nloptr_x0
(numeric vector) starting point for optimization.
- nloptr_lb
(numeric vector) lower bound box for box constrained optimization.
- nloptr_ub
(numeric vector) upper bound box for box constrained optimization.
- nloptr_opts
(list) nloptr options. See
nloptr
.- print_progress
(logical) controls whether optimization progress should be visualized during the calculation.
- ...
additional arguments passed along.
Details
This function calculates optimal design parameters for a two-stage three-arm gold-standard
non-inferiority trial. Run vignette("Introduction", package = "OptimalGoldstandardDesigns")
to see some examples related to the associated paper (Meis et al. 2023)
.
Parameters which can be optimized are the allocation ratios for all groups and stages and the futility and efficacy boundaries of the first stage. The allocation ratios are cT2 = nT2 / nT1, cP1 = nP1 / nT1, cP2 = nP2 / nT1, cC1 = nC1 / nT1 and cC2 = nC2 / nT1. Here, nT1 denotes the sample size of the treatment group in the first stage, nP2 the sample size of the placebo group in the second stage, etc. The first stage efficacy boundaries are bTP1e for the treatment vs placebo testing problem, and bTC1e for the treatment vs control non-inferiority testing problem. The futility boundaries are denoted by bTP1f and bTC1f.
If these parameters are left unspecified or set to NULL, they will be included into the
optimization process, otherwise they will be considered boundary constraints.
You may also supply quoted expressions as arguments for these
parameters to solve a constrained optimization problem. For example, you can supply
cT2 = 1, cP2 = quote(cP1), cC2 = quote(cC1)
to ensure that the first and second
stage allocation ratios are equal.
The design is optimized with respect to the objective criterion given by the parameter
objective
. By default, this is the overall sample size plus an optional
penalty for the placebo group sample size, controlled by the parameter kappa
.
Designs are calculated to fulfill the following constraints: the family-wise type I error
rate is controlled at alpha
under any combination of the two null hypotheses
muT - muP = 0
and muT - muC + Delta = 0
.
The power to reject both hypothesis given both alternative
hypotheses muT - muP = alternative_TP
and muT - muC + Delta = alternative_TC + Delta
is at least 1 - beta
. Variances are assumed to be given by varT, varP
and varC
.
If binding_futility
is TRUE
, type I error recycling is used.
If always_both_futility_tests
is TRUE
, it is assumed that futility tests for both
hypotheses are performed at interim, regardless of whether the treatment vs placebo null hypothesis
was successfully rejected. If always_both_futility_tests
is FALSE
, the futility
test for the treatment vs. control testing problem only needs to be done if the null for the
treatment vs. placebo testing problem was rejected in the first stage.
References
Meis J, Pilz M, Herrmann C, Bokelmann B, Rauch G, Kieser M (2023). “Optimization of the two-stage group sequential three-arm gold-standard design for non-inferiority trials.” Statistics in Medicine, 42(4), 536-558. doi:10.1002/sim.9630 .
Examples
# Should take about 2 second with the chosen accuracy
optimize_design_onestage(
alpha = .025,
beta = .2,
alternative_TP = .4,
alternative_TC = 0,
Delta = .2,
mvnorm_algorithm = mvtnorm::Miwa(steps = 512, checkCorr = FALSE, maxval = 1000),
nloptr_opts = list(algorithm = "NLOPT_LN_SBPLX", ftol_rel = 1e-03, xtol_abs = 1e-08,
xtol_rel = 1e-07, maxeval = 1000, print_level = 0)
)
#>
iteration: 1/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.25, 1.00) f(x) = 946.9105
iteration: 2/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.25, 1.00) f(x) = 946.9105
iteration: 3/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.25, 1.00) f(x) = 946.9105
iteration: 4/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.428125, 1.000000) f(x) = 961.2598
iteration: 5/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.2500, 1.7125) f(x) = 1056.666
iteration: 6/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.428125, 0.287500) f(x) = 1507.581
iteration: 7/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.2945313, 1.3562500) f(x) = 968.3002
iteration: 8/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3835937, 0.6437500) f(x) = 1018.988
iteration: 9/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3167969, 1.1781250) f(x) = 945.7473
iteration: 10/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.1386719, 1.1781250) f(x) = 1142.114
iteration: 11/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3557617, 1.0445312) f(x) = 942.7458
iteration: 12/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.400293, 1.044531) f(x) = 951.7809
iteration: 13/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3557617, 1.2226562) f(x) = 948.9537
iteration: 14/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3112305, 1.2226562) f(x) = 949.9056
iteration: 15/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3334961, 1.1781250) f(x) = 945.294
iteration: 16/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3334961, 1.0000000) f(x) = 940.0275
iteration: 17/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3223633, 0.8886719) f(x) = 943.0804
iteration: 18/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3557617, 0.8664062) f(x) = 952.3089
iteration: 19/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3390625, 1.1001953) f(x) = 941.7243
iteration: 20/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3167969, 1.0556641) f(x) = 939.3978
iteration: 21/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.2973145, 1.0612305) f(x) = 940.1934
iteration: 22/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3112305, 0.9554688) f(x) = 938.7124
iteration: 23/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.2973145, 0.8831055) f(x) = 940.6196
iteration: 24/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.2945313, 1.0111328) f(x) = 938.7033
iteration: 25/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.2750488, 1.0166992) f(x) = 941.122
iteration: 26/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.2889648, 0.9109375) f(x) = 939.1165
iteration: 27/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.2959229, 0.9471191) f(x) = 938.3272
iteration: 28/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.2792236, 1.0027832) f(x) = 939.952
iteration: 29/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3032288, 0.9672974) f(x) = 938.202
iteration: 30/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3046204, 0.9032837) f(x) = 940.0546
iteration: 31/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.2970535, 0.9841705) f(x) = 938.2006
iteration: 32/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3043594, 1.0043488) f(x) = 938.299
iteration: 33/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3022503, 0.9900414) f(x) = 938.1766
iteration: 34/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.2960751, 1.0069145) f(x) = 938.5352
iteration: 35/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3014403, 0.9772017) f(x) = 938.1401
iteration: 36/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.3066371, 0.9830725) f(x) = 938.2095
iteration: 37/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.2994494, 0.9838960) f(x) = 938.1602
iteration: 38/1000 cP1 <- x[1L] cC1 <- x[2L] x = c(0.2986395, 0.9710563) f(x) = 938.1456
#> Optimization finished. Calculating final design with greater accuracy...
#> Sample sizes (stage 1): T: 412, P: 125, C: 403
#> Efficacy boundaries (stage 1): Z_TP_e: 1.95996, Z_TC_e: 1.95996
#> Maximum overall sample size: 940
#> Placebo penalty at optimum (kappa * nP): 0.0
#> Objective function value: 940.0
#> Type I error for TP testing: 2.5%
#> Type I error for TC testing: 2.5%
#> Power: 80.1%