[f2e496]: / R / fromDataSimInternal.R

Download this file

203 lines (160 with data), 8.5 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#This file contains the private functions
#for the predict from data "simulate" part of the package
# Validate the arguments to the simulate procedure
# @param accrualGenerator An AccrualGenerator object used for recruiting additional subjects
# @param Naccrual The number of additional subjects to be recruited
# @param Nsim Number of simulations to run
# @param limit Limit for the percentiles, default is 0.05 which corresponds
# to [0.05, 0.95]
# @param seed Integer for random number generator (for reproducability).
# @param longlagsettings A LongLagSettings object to control the behaviour of the algorithm for subjects whos last date
# is a long time from the analysis date - see vignette for further details
# @param HR The hazard ratio: an advanced option which allows two arm trials to be simulated. This replicates the
# Predict from parameters functionality but uses the recruitment times found in \code{data}. See the vignette for
# further details
# @param r The allocation ratio: see \code{HR} argument.
# @param data The EventData object for the simulation
validate.simulate.arguments <-function(accrualGenerator,Naccrual,Nsim,seed,limit,
longlagsettings,HR,r,data){
if(xor(is.null(HR),is.null(r)))
stop("It is not possible for only one of HR and r to be NULL")
if(!is.null(HR)){
if(!is.numeric(HR) || HR <= 0 || length(HR) != 1){
stop("Invalid HR")
}
}
if(!is.null(r)){
if(!is.numeric(r) || r <= 0 || length(r) != 1){
stop("Invalid r")
}
}
if(!is.null(HR) && ( nrow(data@subject.data)!= 0 && any(!is.na(data@subject.data$time) & data@subject.data$time != 0 ))){
stop("If the argument HR is used then the time on the study for each subject must be 0
(only recruitment times are used when this option is used)")
}
if(!is.numeric(limit) || limit < 0 || limit > 0.5 || length(limit) > 1)
stop("invalid limit argument")
if(!is.null(longlagsettings) && class(longlagsettings)!= "LongLagSettings"){
stop("longlagsettings must be of class LongLagSettings")
}
if(Naccrual < 0 || length(Naccrual)>1) stop("invalid Naccrual argument")
if(Naccrual==0){
if(!is.null(accrualGenerator)) warning("using an accrual generator but Naccrual = 0")
}
else{
if(is.null(accrualGenerator) || class(accrualGenerator)!="AccrualGenerator"){
stop("accrual generator must be an AccrualGenerator object if Naccrual > 0")
}
}
if(!is.null(seed) && !is.numeric(seed)) warning("invalid seed")
if(!is.numeric(Nsim) || Nsim < 0) stop("invalid Nsim argument")
if(Naccrual+nrow(data@subject.data)==0) stop("No subjects!")
}
# Generate which subjects are to have HR=1 (i.e. to be on the control arm)
# and which are to be on the active arm
# @param HR The hazard ratio
# @param r The allocation ratio
# @param N The number of subjects whose events are being simulated
# @return A vector of length N containing 2 different numbers: The given
# hazard ratio and the number 1 (for subjects on control arm)
# The number of each element is set by \code{r}
# and the elements are randomly permuted
GetHRs <- function(HR,r,N){
Ns <- getNs(singleArm=FALSE,r,N)
HRs <- c(rep(1,Ns[1]),rep(HR,Ns[2]))
sample(HRs,size=N,replace=FALSE)
}
# Accrual times for the existing and simulated subjects
# @inheritParams validate.simulate.arguments
# @param rand.dates The dates existing subjects have been randomized
# @return A (unsorted) matrix of recruitment dates as numerics (1 row per simulated trial)
# for subjects
CalculateAccrualTimes <- function(Naccrual,Nsim,rand.dates,accrualGenerator){
rs <-t(replicate(Nsim,rand.dates,simplify = "matrix"))
if(length(rand.dates)==1) rs <- matrix(rs,nrow=Nsim)
if(Naccrual==0){
return(rs)
}
newrecs <- if(Naccrual==1) matrix(replicate(Nsim, accrualGenerator@f(Naccrual)),ncol=1)
else t(replicate(Nsim, accrualGenerator@f(Naccrual)))
if(length(rand.dates)==0) return(newrecs)
if(min(newrecs) < max(rand.dates)){
warning("Some new recruited subjects have rand.date earlier than some existing subjects")
}
return(cbind(rs,newrecs))
}
# Output Inf Date
#
# @return A Inf Date
WithdrawnEventDate <- function(){
as.Date(Inf,origin="1970-01-01")
}
# Function to perform a single simulation
#
# @param row A vector containing 3 elements first the rate for events hazard,
# second the shape for the event hazard and third the index of the simulation
# @param number.subjects The number of existing subjects in the data frame
# @param Naccrual The number of additional subjects recruited
# @param indat The subject.data slot of the EventData object (after the long lagsettings have been applied)
# @param newrecs A matrix of recruitment times newrecs[row[[3]],] is a vector of recruitment times
# needed for simulated subjects for the single simulation
# @param HR The hazard ratio: an advanced option which allows two arm trials to be simulated. This replicates the
# Predict from parameters functionality but uses the recruitment times found in \code{data}. See the vignette for
# further details
# @param r The allocation ratio: see \code{HR} argument.
# @param dropout.rate Weibull rate parameter for subject drop out
# @param dropout.shape Weibull shape parameter for subject drop out
# @param followup The subject follow up time (Inf if followed until event/withdrawn)
# @param conditionalFunction The conditionalFunction slot of a \code{FromDataSimParam} object
# @return A list with two elements both vectors of length
# Naccrual+number.subjects. event.type which contains 0 if event occurs
# 1 if subject dropped out or 2 if subject completed follow up period
# event.times the dates (as numeric) of subjects leaving the trial due to follow up
PerformOneSimulation <- function(row,number.subjects,Naccrual,
indat, newrecs,HR,r, dropout.rate,
dropout.shape, followup,conditionalFunction){
#first set all subjects to having an event
#0 = event, 1 = dropout, 2 = follow up
event.type <- rep(0,number.subjects+Naccrual)
#And the structure for the time of leaving the study
retVal <- structure(rep(NA_real_, number.subjects+Naccrual), class="Date")
#subjects who have already left the trial
existing.events.index=which(indat$has.event==1 | indat$withdrawn==1 | indat$censored.at.follow.up==1)
#set their date and event type correct
retVal[existing.events.index] <- LastDate(indat)[existing.events.index]
event.type[existing.events.index] <- ifelse(indat$has.event[existing.events.index]==1, 0,
ifelse(indat$censored.at.follow.up[existing.events.index]==1,2,1))
#get subjects who have not had an event/withdrawn
w <- which(indat$has.event==0 & indat$withdrawn==0 & indat$censored.at.follow.up==0)
lower.bounds <- indat$time[w]
rand.date <- indat$rand.date[w]
#add to them accrued subjects
if(Naccrual > 0){
lower.bounds <- c(lower.bounds,rep(0,Naccrual))
rand.date <- if(Naccrual > 1) c(rand.date,as.Date(newrecs[row[names(row)=="Id"],],origin="1970-01-01"))
else c(rand.date,as.Date(newrecs[row[names(row)=="Id"]],origin="1970-01-01"))
w <- c(w,(number.subjects+1):(number.subjects+Naccrual))
}
#create a vector of HRs 1 for each subject. If subject is on control arm
#(or HR is null) then HR=1 otherwise HR is the given HR
HRs <- if(is.null(HR)) rep(1,length(lower.bounds)) else GetHRs(HR,r,length(lower.bounds))
#generate the time on trial
times <- conditionalFunction(t.conditional=lower.bounds,params=row,HR=HRs)
#if competing risks dropout then deal with this
if(dropout.rate != 0){
dropout.times <- rcweibull(lower.bounds,params=list(shape=dropout.shape,rate=dropout.rate),
HR=rep(1,length(lower.bounds)))
event.type[w] <- ifelse(times < dropout.times,0,1)
times <- pmin(times,dropout.times)
}
#if anytimes are > followup then set them as followup
lost.to.followup <- which(times > followup)
times[lost.to.followup] <- followup
event.type[w[lost.to.followup]] <- 2
#and the event times
tmp <- internal.Date(pmax(1,round(times)),rand.date)
#put the times into the return vector
retVal[w] <- tmp
return(list(event.type=event.type,
event.times=retVal))
}