|
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 |
|