Skip to content

Commit fbbe9e2

Browse files
committed
MODIFIED FOR CRAN
1 parent 501a00f commit fbbe9e2

43 files changed

Lines changed: 877 additions & 1151 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.DS_Store

0 Bytes
Binary file not shown.

.Rhistory

Lines changed: 509 additions & 509 deletions
Large diffs are not rendered by default.

DESCRIPTION

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
Package: BayesianPlatformDesignTimeTrend
2-
Title: Simulate and analyse Bayesian Platform Trial with time trend
3-
Version: 1.0.0
2+
Title: Simulate and Analyse Bayesian Platform Trial with Time Trend
3+
Version: 1.0.1
44
Author: Ziyan Wang [aut, cre]
55
Maintainer: Ziyan Wang <zw7g20@soton.ac.uk>
66
Authors@R:
77
person(given = "Ziyan",
88
family = "Wang",
99
role = c("aut", "cre"),
1010
email = "zw7g20@soton.ac.uk")
11-
Description: Simulating the multi-arm multi-stage or platform trial with Bayesian approach using the 'rstan' package, which provides the R interface for to the Stan.
12-
The randomisation approach in this package are fix ratio and Bayesian adaptive randomisation.
13-
In addition, the time trend problem of platform trial can be studied in this package.
14-
There is a demo for multi-arm multi-stage trial with two different null scenario and a demo for Bayesian trial cutoff screening.
11+
Description: Simulating the multi-arm multi-stage or platform trial with Bayesian approach using the 'rstan' package, which provides the R interface for the Stan.
12+
This package supports fixed ratio and Bayesian adaptive randomization approaches for randomization.
13+
Additionally, it allows for the study of time trend problems in platform trials.
14+
There are demos available for a multi-arm multi-stage trial with two different null scenarios, as well as for Bayesian trial cutoff screening.
1515
The Bayesian adaptive randomisation approaches are described in:
1616
Trippa et al. (2012) <doi:10.1200/JCO.2011.39.8420> and
17-
Wathen et al. (2017) <doi:10.1177/1740774517692302>
18-
The randomisation algorithm is described in
19-
Zhao W <doi:10.1016/j.cct.2015.06.008>
17+
Wathen et al. (2017) <doi:10.1177/1740774517692302>.
18+
The randomisation algorithm is described in:
19+
Zhao W <doi:10.1016/j.cct.2015.06.008>.
2020
The analysis methods of time trend effect in platform trial are described in:
2121
Saville et al. (2022) <doi:10.1177/17407745221112013> and
22-
Bofill Roig et al. (2022) <doi:10.1186/s12874-022-01683-w>
22+
Bofill Roig et al. (2022) <doi:10.1186/s12874-022-01683-w>.
2323
URL: https://github.com/ZXW834/PlatFormDesignTime
2424
Encoding: UTF-8
2525
Roxygen: list(markdown = TRUE)
@@ -41,8 +41,7 @@ Imports:
4141
foreach (>= 1.5.1),
4242
iterators (>= 1.0.13),
4343
reshape (>= 0.8.8),
44-
BiocManager (>= 1.30.19),
45-
rjags
44+
BiocManager (>= 1.30.19)
4645
LinkingTo:
4746
BH (>= 1.66.0),
4847
Rcpp (>= 0.12.0),

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
YEAR: 2023
2-
COPYRIGHT HOLDER: PlatFormDesign authors
2+
COPYRIGHT HOLDER: BayesianPlatformDesignTimeTrend authors

NAMESPACE

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ export(Boundaryconstruction)
66
export(FWER_disconjunctivepowerfunc)
77
export(Initializetrialparameter)
88
export(Meanfunc)
9-
export(Mixeffect_analysis)
10-
export(Mixeffect_modelling)
119
export(Nfunc)
1210
export(OutputStats.initialising)
1311
export(Randomisation.inf)
@@ -57,6 +55,5 @@ importFrom(stats,pbeta)
5755
importFrom(stats,pnorm)
5856
importFrom(stats,predict)
5957
importFrom(stats,rbinom)
60-
importFrom(stats,update)
6158
importFrom(stats,var)
6259
useDynLib(BayesianPlatformDesignTimeTrend, .registration = TRUE)

NEWS.md

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,48 @@
1-
# BayesianPlatformDesignTimeTrend 1.0.0
2-
* Added a `NEWS.md` file to track changes to the package.
1+
# Apr 25, 2023, BayesianPlatformDesignTimeTrend version 1.0.1
2+
## Major changes
3+
- I added a check command for max.ar which is the upper boundary for randomisation ratio for each arm. The command is added in the MainFunction.R. Details are shown below.
4+
- #-max.ar check
5+
if (1 - max.ar > 1/K){
6+
stop("Error: The lower allocation ratio should be at least 1/K. Please check the number of arm at the beginning and the max.ar")
7+
}
8+
9+
- Another change is the randomisation ratio adjustment in the Simulation_AdaptiveRandomisationmethodRatioCalc.R.
10+
11+
- I modified the randomisation ratio adjustment command for Thall's approach.
12+
13+
- ##----Original code------ (This code only protects the control arm's allocation ratio)
14+
- rpk = matrix(rep(0, armleft), ncol = armleft)
15+
- randomprob = matrix(rep(0, K), ncol = K)
16+
- colnames(rpk) = c(1, treatmentindex + 1)
17+
- colnames(randomprob) = seq(1, K)
18+
- rpk[1] = alloc.prob.best[1]
19+
- rpk[-1] = alloc.prob.best[-1][treatmentindex]
20+
- rpk = rpk / sum(rpk)
21+
- lower = ifelse(rpk[1] < (1 - max.ar), 1 - max.ar, rpk[1])
22+
- rpk[1] = lower
23+
- upper = ifelse(rpk[1] > max.ar, max.ar, rpk[1])
24+
- rpk[1] = upper
25+
- rpk[-1] = (1 - rpk[1]) * rpk[-1] / sum(rpk[-1])
26+
- randomprob[as.numeric(colnames(rpk))] = randomprob[as.numeric(colnames(rpk))] + rpk
27+
28+
- ##----New code------ (This code protects all arms' allocation ratio. Also, this code work together with max.ar check code)
29+
- rpk = matrix(rep(0,armleft),ncol = armleft)
30+
- randomprob = matrix(rep(0,K),ncol = K)
31+
- colnames(rpk) = c(1,treatmentindex+1)
32+
- colnames(randomprob) = seq(1,K)
33+
- rpk[1] = alloc.prob.best[1]
34+
- rpk[-1] = alloc.prob.best[-1][treatmentindex]
35+
- rpk = rpk/sum(rpk)
36+
- lower = ifelse(rpk<(1-max.ar),1-max.ar,rpk)
37+
- rpk = lower
38+
- upper = ifelse(rpk>max.ar,max.ar,rpk)
39+
- rpk = upper
40+
- rpk[!(rpk==(1-max.ar))]=(1-sum(rpk[rpk==1-max.ar]))*(rpk[!(rpk==1-max.ar)]/sum(rpk[!(rpk==1-max.ar)]))
41+
- randomprob[as.numeric(colnames(rpk))] = randomprob[as.numeric(colnames(rpk))]+rpk
42+
43+
# May 1, 2023, BayesianPlatformDesignTimeTrend version 1.0.1
44+
## Major changes
45+
- I fixed a bug where the fix ratio allocation method code is not suitable for the multi-arm trial
46+
47+
- Old code: rpk[-1] = rep((armleft - 1) / (armleft - 1 + Fixratiocontrol), armleft - 1)
48+
- New code: rpk[-1] = rep(1 / (armleft - 1 + Fixratiocontrol), armleft - 1)

R/Demo_CutoffScreening.R

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ demo_Cutoffscreening = function(ntrials = 1000,
3131
response.probs = c(0.4, 0.4),
3232
ns = c(30, 60, 90, 120, 150),
3333
max.ar = 0.75,
34-
rand.type = "Urn",
34+
rand.algo = "Urn",
3535
max.deviation = 3,
3636
model.inf = list(
3737
model = "tlr",
@@ -67,6 +67,7 @@ demo_Cutoffscreening = function(ntrials = 1000,
6767
),
6868
cl = 2) {
6969
old <- options()# code line i
70+
on.exit(options(old))
7071
#Set start grid of screening
7172
startgrid <-
7273
data.frame(tpIE = rep(NA, length(grid.inf$start)), cutoff = grid.inf$start)
@@ -94,7 +95,7 @@ demo_Cutoffscreening = function(ntrials = 1000,
9495
response.probs = input.info$response.probs,
9596
ns = input.info$ns,
9697
max.ar = input.info$max.ar,
97-
rand.type = input.info$rand.type,
98+
rand.algo = input.info$rand.algo,
9899
max.deviation = input.info$max.deviation,
99100
model.inf = input.info$model.inf,
100101
Stopbound.inf = Stopbound.inf,
@@ -138,7 +139,7 @@ demo_Cutoffscreening = function(ntrials = 1000,
138139
response.probs = input.info$response.probs,
139140
ns = input.info$ns,
140141
max.ar = input.info$max.ar,
141-
rand.type = input.info$rand.type,
142+
rand.algo = input.info$rand.algo,
142143
max.deviation = input.info$max.deviation,
143144
model.inf = input.info$model.inf,
144145
Stopbound.inf = Stopbound.inf,
@@ -178,7 +179,6 @@ demo_Cutoffscreening = function(ntrials = 1000,
178179
predict(quadratic.model,
179180
list(cutoff = cutoffgrid, cutoff2 = cutoffgrid ^ 2))
180181
doParallel::stopImplicitCluster()
181-
on.exit(options(old))
182182
return(
183183
list(
184184
detailsforgrid = dataloginformd,

R/Demo_multiplescenariotrialsimulation.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ demo_multscenario = function(ntrials = 1000,
6666
response.probs = scenario[i,],
6767
ns = ns[[z]],
6868
max.ar = 0.75,
69-
rand.type = "Urn",
69+
rand.algo = "Urn",
7070
max.deviation = 3,
7171
model.inf = list(
7272
model = "tlr",

R/MainFunction.R

Lines changed: 13 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
#' @param ii Meaning less parameter but required for foreach function in doParallel package
44
#' @param response.probs A vector of true response probability for each arm. Default response.probs = c(0.4, 0.4).
55
#' @param ns A vector of accumulated number of patient at each stage. Default is ns = c(30, 60, 90, 120, 150).
6-
#' @param max.ar The upper boundary for randomisation ratio for each arm. Default is 0.75 for a two arm trial.
7-
#' @param rand.type The method of applying patient allocation with a given randomisation probability vector. Default is "Urn".
6+
#' @param max.ar The upper boundary for randomisation ratio for each arm. Default is 0.75 for a two arm trial. The minimum value depends on K where 1 - max.ar <= 1/K
7+
#' @param rand.algo The method of applying patient allocation with a given randomisation probability vector. Default is "Urn".
88
#' @param max.deviation The tuning parameter for Urn randomisation method. Default is 3.
99
#' @param Stopbound.inf The list of stop boundary information for more see \code{\link{Stopboundinf}}
1010
#' @param Random.inf The list of Adaptive randomisation information for more see \code{\link{Randomisation.inf}}
@@ -19,7 +19,7 @@
1919
#' simulatetrial(response.probs = c(0.4, 0.4),
2020
#' ns = c(30, 60, 90, 120, 150),
2121
#' max.ar = 0.75,
22-
#' rand.type = "Urn",
22+
#' rand.algo = "Urn",
2323
#' max.deviation = 3,
2424
#' model.inf = list(
2525
#' model = "tlr",
@@ -60,7 +60,7 @@ simulatetrial <- function(ii,
6060
response.probs = c(0.4, 0.4),
6161
ns = c(30, 60, 90, 120, 150),
6262
max.ar = 0.75,
63-
rand.type = "Urn",
63+
rand.algo = "Urn",
6464
max.deviation = 3,
6565
model.inf = list(
6666
model = "tlr",
@@ -113,9 +113,14 @@ simulatetrial <- function(ii,
113113
randomprob = initialised.par$randomprob
114114
z = initialised.par$z
115115
y = initialised.par$y
116-
117116
group_indicator = initialised.par$group_indicator
118117
post.prob.best.mat = initialised.par$post.prob.best.mat
118+
119+
#-max.ar check
120+
if (1 - max.ar > 1/K){
121+
stop("Error: The lower allocation ratio should be at least 1/K. Please check the number of arm at the beginning and the max.ar")
122+
}
123+
119124
#Initialize the output data frame: stats
120125
stats = OutputStats.initialising(model.inf$tlr.inf$variable.inf,
121126
model.inf$tlr.inf$reg.inf,
@@ -139,10 +144,10 @@ simulatetrial <- function(ii,
139144

140145
# Patient randomisation based on given randomization ratio
141146
# Parameter checking
142-
if (rand.type %in% c("Coin", "Urn")) {
147+
if (rand.algo %in% c("Coin", "Urn")) {
143148
random.output = AdaptiveRandomisation(
144149
Fixratio,
145-
rand.type,
150+
rand.algo,
146151
K,
147152
n.new,
148153
randomprob,
@@ -159,7 +164,7 @@ simulatetrial <- function(ii,
159164
)
160165
}
161166
else {
162-
stop("Error randomisation type wrong")
167+
stop("Error: randomisation type wrong")
163168
}
164169

165170
# Extract the output list
@@ -491,66 +496,6 @@ simulatetrial <- function(ii,
491496
treatmentindex = treatmentindex[is.na(match(treatmentindex, treatmentdrop))]
492497
}
493498
}
494-
else if (model.inf$tlr.inf$variable.inf == "Mixeffect.jag") {
495-
jagmodel<-" model {
496-
for(i in 1:armleft){
497-
for(j in 1:stage){
498-
Y[i,j] ~ dbin(p[i,j],N[i,j])
499-
logit(p[i,j]) = beta0 + alpha[stage-(j-1)] + beta1[i]
500-
}
501-
}
502-
alpha[1] = 0
503-
alpha[2] ~ dnorm(0, tau2)
504-
for(k in 3:stage ) {
505-
alpha[k] ~ dnorm(2*alpha[k-1] - alpha[k-2],tau2)
506-
}
507-
beta1[1] <- 0
508-
for(i in 2:armleft){
509-
beta1[i] ~ dnorm(0,0.31)
510-
}
511-
tau2 ~ dgamma(0.1, 0.01)
512-
beta0 ~ dnorm(0, 0.31)
513-
}"
514-
postsamp.list = Mixeffect_modelling(ytemp=ytemp, treatmentindex=treatmentindex, group=group, ntemp=ntemp, armleft=armleft, jagmodel=jagmodel)
515-
analysis = Mixeffect_analysis(postsamp.list=postsamp.list, group=group, treatmentindex=treatmentindex, ns = ns, K = K)
516-
stats1 = analysis$stats1
517-
statsbeta0 = analysis$statsbeta0
518-
stats4 = analysis$stats4
519-
stats5 = analysis$stats5
520-
stats6 = analysis$stats6
521-
stats7 = analysis$stats7
522-
sampoutcome = analysis$sampoutcome
523-
sampefftotal = analysis$sampefftotal
524-
post.prob.btcontrol = analysis$post.prob.btcontrol
525-
#-Calculating posterior probability of each arm (including control) to be the best arm-
526-
# post.prob.best: The posterior probability of each arm (including control) to be the best arm
527-
# This is required for Thall's randomisation approach
528-
for (q in 1:armleft) {
529-
post.prob.best.mat[group, zlevel[q]] = (sum(max.col(sampefftotal) == q)) /
530-
2500
531-
}
532-
post.prob.best = post.prob.best.mat[group,]
533-
#Normalizing in case any value equals zero
534-
post.prob.best = post.prob.best + 1e-7
535-
post.prob.best = post.prob.best / sum(post.prob.best)
536-
#----Justify if type I error was made for each arm----
537-
# post.prob.btcontrol>cutoffeff[group]: Efficacy boundary is hit at this stage
538-
# post.prob.btcontrol<cutoffful[group]: Fultility boundary is hit at this stage
539-
Justify = post.prob.btcontrol > cutoffeff[group] |
540-
post.prob.btcontrol < cutoffful[group]
541-
#Identify which active arm should be dropped at current stage
542-
treatmentdrop = treatmentindex[post.prob.btcontrol > cutoffeff[group] |
543-
post.prob.btcontrol < cutoffful[group]]
544-
stats3 = rep(NA, K - 1)
545-
names(stats3) = seq(1, K - 1)
546-
stats3[treatmentindex] = Justify
547-
if (sum(Justify) > 0) {
548-
armleft = armleft - sum(Justify)
549-
#Debugged for K arm by Ziyan Wang on 12:00 26/07/2022 for three arm. Used to be treatmentindex = treatmentindex[-treatmentdrop]
550-
#Debugged for K arm by Ziyan Wang on 18:58 26/07/2022 for more than 3 arm. Used to be treatmentindex = treatmentindex[!(treatmentindex==treatmentdrop)]
551-
treatmentindex = treatmentindex[is.na(match(treatmentindex, treatmentdrop))]
552-
}
553-
}
554499

555500
#-Adjust the posterior randomisation ratio-
556501
randomprob = ARmethod(

R/Simulation_AdaptiveRandomisationmethodRatioCalc.R

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ ARmethod = function(Fixratio,
5252
max.ar,
5353
armleft,
5454
treatmentindex) {
55+
# Validate inputs
56+
if (!is.logical(Fixratio)) stop("Error: Fixratio should be a logical value (TRUE/FALSE)")
57+
if (!is.character(BARmethod)) stop("Error: BARmethod should be a character value")
58+
if (!is.numeric(group) || group <= 0) stop("Error: group should be a positive numeric value")
59+
if (!is.numeric(max.ar) || max.ar <= 0 || max.ar >= 1) stop("Error: max.ar should be a numeric value between 0 and 1")
60+
if (K < 2) stop("Error: K should be an integer value greater than or equal to 2")
61+
5562
#---------------------Trippa's approach---------------------
5663
if (Fixratio == F & BARmethod == "Trippa") {
5764
##Tuning the paprameter using method mentioned in Trippa's paper (2014)
@@ -97,20 +104,19 @@ ARmethod = function(Fixratio,
97104
}
98105
#-------------------Allocation bounds restriction (K arm: restriction on control)---------------
99106
else if (K > 2) {
100-
rpk = matrix(rep(0, armleft), ncol = armleft)
101-
randomprob = matrix(rep(0, K), ncol = K)
102-
colnames(rpk) = c(1, treatmentindex + 1)
103-
colnames(randomprob) = seq(1, K)
107+
rpk = matrix(rep(0,armleft),ncol = armleft)
108+
randomprob = matrix(rep(0,K),ncol = K)
109+
colnames(rpk) = c(1,treatmentindex+1)
110+
colnames(randomprob) = seq(1,K)
104111
rpk[1] = alloc.prob.best[1]
105112
rpk[-1] = alloc.prob.best[-1][treatmentindex]
106-
rpk = rpk / sum(rpk)
107-
lower = ifelse(rpk[1] < (1 - max.ar), 1 - max.ar, rpk[1])
108-
rpk[1] = lower
109-
upper = ifelse(rpk[1] > max.ar, max.ar, rpk[1])
110-
rpk[1] = upper
111-
rpk[-1] = (1 - rpk[1]) * rpk[-1] / sum(rpk[-1])
112-
randomprob[as.numeric(colnames(rpk))] = randomprob[as.numeric(colnames(rpk))] +
113-
rpk
113+
rpk = rpk/sum(rpk)
114+
lower = ifelse(rpk<(1-max.ar),1-max.ar,rpk)
115+
rpk = lower
116+
upper = ifelse(rpk>max.ar,max.ar,rpk)
117+
rpk = upper
118+
rpk[!(rpk==(1-max.ar))]=(1-sum(rpk[rpk==1-max.ar]))*(rpk[!(rpk==1-max.ar)]/sum(rpk[!(rpk==1-max.ar)]))
119+
randomprob[as.numeric(colnames(rpk))] = randomprob[as.numeric(colnames(rpk))]+rpk
114120
}
115121

116122
}

0 commit comments

Comments
 (0)