gsDesign
First, we import the library gsDesign
into R.
################################################
### Sequential monitoring of clinical trials ###
################################################
library(gsDesign)
The function gsDesign
can carry out lots of analyses. Here we focus on the definition of a user-specified spending fuction.
The CAST study had a function that spent half the alpha level (of 2.5%) during the interim analyses prior to the final analysis, and half of the alpha level during the final analysis.
We first define the spending function:
sfcast <- function(alpha, t, param)
{
# set spending using constant alpha/2 until last interim then alpha/2 at final
x <- list(name="CAST example", param=param, parname=NULL,
sf=sfcast, spend=cumsum(c(rep(alpha/(2*(length(t)-1)),length(t)-1), alpha/2)))
class(x) <- "spendfn"
x
}
Notice that the object that is being created (\(x\)) has a number of attributes, such as name
, param
and it must be of class spendfn
to be recognized by the package.
Now let’s try it out!
First we will plot the spending fuunction to see hwo the alpha level is being spent
t<-0:20/20
plot(t, sfcast(0.025, t, NULL)$spend, type="l",
xlab="Proportion of information",
ylab="Cumulative proportion of total spending")
sfcast
in the CAST trial exampleNow, let’s define the CAST trial bounds:
x <- gsDesign(k=length(t), test.type=2, sfu=sfcast, alpha=0.025)
plot(x$timing, x$upper$bound, type="l", ylim=c(-3.5,3.5) ,
ylab="Z(t)", xlab="Trial fraction")
lines(x$timing, x$lower$bound)
Now recall that the first DSMB review of the CAST study was after 32/425 events were observed (i.e., \(t=0.075\)) and the log-rank test statistic was \(Z(t)=-2.82\). During the second DSMB meeting, 42/300 events were observed (\(t=14\%\)) after the expected number of total events was revised to 300 from 425. During that time, \(Z(t)=-3.20\).
To see whether we have crossed a boundary in either case, we simply plot these two points on the previous plot.
x <- gsDesign(k=length(t), test.type=2, sfu=sfcast, alpha=0.025)
plot(x$timing, x$upper$bound, type="l", ylim=c(-3.5,3.5) ,
ylab="Z(t)", xlab="Trial fraction")
lines(x$timing, x$lower$bound)
text(32/425, -2.82, "X")
text(42/300, -3.2, "X", col="red")