Diff of /R/accrual.R [000000] .. [f2e496]

Switch to unified view

a b/R/accrual.R
1
#This file contains the generator functions for recruiting extra subjects 
2
#into a predict from data simulation. It also contains the code for
3
#estimating k in the accrual cdf G(t) t^k/B^k from recruitment data.
4
5
##' @include eventData.R fromDataInternal.R
6
NULL
7
8
##' A class to allow additional subjects 
9
##' to be recruited onto the study
10
##' @slot f A function with 1 argument (the number of subjects to be recruited)
11
##' which returns a vector of recruitment times (of the required length)
12
##' @slot model A string, name of the accrual procedure used  
13
##' @slot text The summary text to be output when printing the accrual procedure
14
##' for example "a poisson process with rate..."
15
##' @seealso \code{\link{show,AccrualGenerator-method}}
16
##' @export
17
setClass("AccrualGenerator",
18
         slots=list(f="function",
19
                    model="character",
20
                    text="character"
21
         )
22
)
23
24
##' @name show
25
##' @rdname show-methods
26
##' @aliases show,AccrualGenerator-method
27
##' @export
28
setMethod("show","AccrualGenerator",function(object){
29
  cat(paste("Accrual model:",object@model,"\n"))
30
  cat(paste("Model Description:\n"))
31
  cat(object@text)  
32
})
33
34
##' Create A Poisson process accrual generator
35
##' @param start.date The start date for the recruitment process
36
##' @param rate The rate of the required Poisson process.
37
##' @return An \code{AccrualGenerator} object which can 
38
##' be used when recruiting subjects with a Possion process
39
##' with given \code{start.date} and \code{rate}
40
##' @export 
41
Generate.PoissonAccrual <- function(start.date,rate){
42
  if(rate <= 0) stop("rate must be positive")
43
  start.date <- FixDates(start.date)
44
  f <- function(N){
45
    start.date + ceiling( cumsum( rexp( N, rate=rate ) ) )
46
  }
47
  
48
  r <- if(rate < 0.01) r else round(rate,2)
49
  
50
  text <- paste("a poisson process with rate=", 
51
                 r, " and start date=", start.date,".",sep="")
52
  
53
  new("AccrualGenerator",f=f,
54
      model="Poisson process",text=text)    
55
    
56
}
57
58
##' Create An AccrualGenerator using a power law recruitment
59
##' 
60
##' Subjects are accrued according to the c.d.f 
61
##' \code{G(t)=t^k/B^k} where \code{k} is a parameter, 
62
##' \code{t} is the time and \code{B} is the recruitment period. 
63
##'  
64
##' See the predict from data vignette for further details  
65
##' @param start.date The start of the subject accrual period
66
##' @param end.date The date the last subject is accrued so \code{B} = 
67
##' \code{end.date} - \code{start.date} unless \code{rec.start.date} is used see 
68
##' below
69
##' @param k The non-uniformity accrual parameter
70
##' @param deterministic Logical, if FALSE then the recruitment times 
71
##' are non-stochastically chosen so that their cumulative distribution function is \code{G(t)}
72
##' otherwise they are generated by sampling random variables with a cdf \code{G(t)}
73
##' @param rec.start.date If this argument is used the subjects are still recruited between 
74
##' start.date and end.date but they follow the cdf \code{G(t)=(t^k-L^k)/(B^k-L^k)} where
75
##' \code{t} is in \code{[L,B]} and \code{B = end.date - rec.start.date} and \code{L = start.date- rec.start.date}.
76
##' @return An AccrualGenerator object which generates the required subject accruals
77
##' @export
78
Generate.Accrual <- function(start.date,end.date,k,deterministic=FALSE,rec.start.date=NULL){
79
  start.date <- FixDates(start.date)
80
  end.date <- FixDates(end.date)
81
  rec.start.date <- if(is.null(rec.start.date)) start.date else FixDates(rec.start.date)
82
  
83
  # Length of recruitment period
84
  B <- as.integer(end.date - rec.start.date)
85
  L <- as.integer(start.date - rec.start.date)
86
  
87
  if(L < 0 || k <= 0|| B <= L){
88
    stop("Invalid arguments")
89
  }
90
  
91
  if(deterministic){
92
    f <- function(N){
93
      as.Date(((1:N/N)*(B^k-L^k) + L^k)^(1/k)-L,origin=start.date)
94
    }
95
    stext <- "non-stochastic"
96
  }
97
  else{
98
    f <- function(N){
99
      ans <- ((B^k-L^k)*runif(N) + L^k)^(1/k)-L
100
      ans[order(ans)]
101
      as.Date(ans,origin=start.date)
102
    }
103
    stext <- "stochastic"
104
  }  
105
  
106
  text <- paste("a ",stext  ," allocation following G(t)=t^k/B^k, where k=", 
107
  round(k,2), " and B=",B," days is the recruitment period [", rec.start.date, ", ", end.date, "].",sep="")
108
  
109
  if(L!=0){
110
    text <- paste(text," New subjects will be recruited after ",start.date,".",sep="") 
111
  }
112
  
113
  new("AccrualGenerator",f=f,
114
      model="Power law allocation",text=text) 
115
  
116
} 
117
118
##' Generic function to estimate non-uniformity accrual 
119
##' parameter \code{k}
120
##' 
121
##' Note The estimate produced assumes recruitment has completed.
122
##' @docType methods
123
##' @param object An \code{EventData} object
124
##' @param ... Additional arguments to be passed to specific method
125
##' @rdname estimateAccrualParameter-methods  
126
##' @export
127
setGeneric("estimateAccrualParameter",function(object,...) standardGeneric("estimateAccrualParameter"))
128
129
130
131
##' @param start.date The startdate for recruitment, by default the date 
132
##' the first subject is recruited. If subjects are recruited on start.date, it is
133
##' assumed they are recruited on the following day to avoid log(0) in the 
134
##' maximum likelihood estimate.
135
##' @param end.date The end date for recruitment, by default the date 
136
##' the last subject is recruited. 
137
##' @return A maximum likelihood estimate for k, see vignette 
138
##' for further details    
139
##' @rdname estimateAccrualParameter-methods 
140
##' @aliases estimateAccrualParameter,EventData-method
141
##' @export
142
setMethod("estimateAccrualParameter", "EventData",
143
  function(object, start.date=min(object@subject.data$rand.date),
144
           end.date=max(object@subject.data$rand.date)){
145
    message("Note this estimate assumes recruitment has completed")          
146
    
147
    start.date <- FixDates(start.date)
148
    end.date <- FixDates(end.date)
149
    
150
    B <- as.numeric(end.date-start.date)
151
    if(B <= 0) stop("end.date must be after start.date")
152
    
153
    recs <- (object@subject.data$rand.date-start.date)
154
    recs <- ifelse(recs==0,0.5,recs)
155
    
156
    if(any(recs< 0 | recs > B)) stop("Subjects recruited outside of recruitment period")
157
    
158
    return(MLestimateK(B,as.numeric(recs)))
159
    
160
  }
161
)
162
163
164