|
a |
|
b/R/common.R |
|
|
1 |
#Some miscellaneous functions used by both |
|
|
2 |
#predict form parameters and predict from data |
|
|
3 |
|
|
|
4 |
##' @importFrom stats uniroot |
|
|
5 |
NULL |
|
|
6 |
|
|
|
7 |
##' Return the number of days in the year |
|
|
8 |
##' |
|
|
9 |
##' This allows the user control over |
|
|
10 |
##' whether the package uses 365.25, 365 (or any other number) of days |
|
|
11 |
##' in a year. |
|
|
12 |
##' |
|
|
13 |
##' The number of days in a month is then set as daysinyear()/12 |
|
|
14 |
##' |
|
|
15 |
##' @return The number of days in the year |
|
|
16 |
##' @export |
|
|
17 |
standarddaysinyear <- function() { |
|
|
18 |
getOption('eventPrediction.daysinyear', |
|
|
19 |
365.25) |
|
|
20 |
} |
|
|
21 |
|
|
|
22 |
|
|
|
23 |
# Round a number and force trailing zeros to be output |
|
|
24 |
# @param number The number to be output |
|
|
25 |
# @param dp The number of digits to display after the decimal point |
|
|
26 |
# @return A string (e.g. "43.400") |
|
|
27 |
roundForceOutputZeros <- function(number,dp){ |
|
|
28 |
if(dp < 1) { |
|
|
29 |
stop("Invalid argument dp must be positive") |
|
|
30 |
} |
|
|
31 |
roundnumber <- as.character(round(number,digits=dp)) |
|
|
32 |
outputdp <- nchar(strsplit(as.character(roundnumber),"\\.")[[1]][2]) |
|
|
33 |
zeros <- rep("0",dp-outputdp) |
|
|
34 |
return(paste(roundnumber,paste(zeros,collapse=""),sep="")) |
|
|
35 |
|
|
|
36 |
} |
|
|
37 |
|
|
|
38 |
# Calculate the number of subjects on each arm |
|
|
39 |
# |
|
|
40 |
# \code{floor((r/(r+1))*N)} are allocated to the experimental arm |
|
|
41 |
# the rest are allocated ot the control arm |
|
|
42 |
# |
|
|
43 |
# @param singleArm logical TRUE if study is a single arm |
|
|
44 |
# @param r Allocation ratio, see Study object |
|
|
45 |
# @param N Total number of subjects on the trial |
|
|
46 |
# @return A vector (N_control,N_experimental) |
|
|
47 |
getNs <- function(singleArm,r,N){ |
|
|
48 |
if (singleArm){ |
|
|
49 |
return(c(N,0)) |
|
|
50 |
} |
|
|
51 |
|
|
|
52 |
is.wholenumber <- function(x, tol = .Machine$double.eps^0.5) abs(x - round(x)) < tol |
|
|
53 |
|
|
|
54 |
oldres <- (r/(r+1))*N |
|
|
55 |
res <- if(!is.wholenumber(oldres)) floor(oldres) else oldres |
|
|
56 |
res <- c(N-res,res) |
|
|
57 |
|
|
|
58 |
if(any(res==0)){ |
|
|
59 |
stop("Too few subjects recruited for given randomization balance |
|
|
60 |
All subjects would be recruited onto the same arm.") |
|
|
61 |
} |
|
|
62 |
|
|
|
63 |
return(res) |
|
|
64 |
} |
|
|
65 |
|
|
|
66 |
# Add line breaks to a string |
|
|
67 |
# @param title text to add line breaks to |
|
|
68 |
# @param text.width Target number of characters per row |
|
|
69 |
# @return text with line breaks |
|
|
70 |
AddLineBreaks <- function( title, text.width ) { |
|
|
71 |
wrapper <- function(x, ... ) paste(strwrap(x, ... ) ) |
|
|
72 |
wtext <- wrapper(title, width = text.width ) |
|
|
73 |
return(paste(wtext,collapse="\n")) |
|
|
74 |
} |
|
|
75 |
|
|
|
76 |
##' Function which attempts to read in a csv file |
|
|
77 |
##' picking a delimiter from a given set of options |
|
|
78 |
##' |
|
|
79 |
##' The function works by counting the number of occurences |
|
|
80 |
##' of each delimiter on each line and for exactly one |
|
|
81 |
##' of the delimiter options all lines contain the same number |
|
|
82 |
##' of occurences (>0) then this delimiter is used |
|
|
83 |
##' |
|
|
84 |
##' @param path The path to the csv file to be read |
|
|
85 |
##' @param delim_options A vector of characters from which the |
|
|
86 |
##' delimiter should be chosen |
|
|
87 |
##' @return If successful a data frame containing the csv file |
|
|
88 |
##' if unsuccessful an error is thrown |
|
|
89 |
##' @export |
|
|
90 |
csvSniffer <- function(path,delim_options=c(',',';','\t')){ |
|
|
91 |
#currently reading file twice ought to be improved |
|
|
92 |
vec <- readLines(con=path) |
|
|
93 |
#remove empty lines |
|
|
94 |
vec <- vec[sapply(vec, nchar) > 0] |
|
|
95 |
ans <- sapply(delim_options,function(x){ |
|
|
96 |
a <- unlist(lapply(vec,function(y)sum(unlist(strsplit(y,split=""))==x))) |
|
|
97 |
if(all(a==a[1]) && a[1] != 0) TRUE else FALSE |
|
|
98 |
}) |
|
|
99 |
if(sum(ans) != 1){ |
|
|
100 |
stop("Cannot determine delimiter") |
|
|
101 |
} |
|
|
102 |
read.csv(path,sep=names(ans[ans==TRUE])) |
|
|
103 |
} |
|
|
104 |
|
|
|
105 |
|
|
|
106 |
##' Given trial assumptions describing an exponential model |
|
|
107 |
##' Use the method of moments to fit a single Weibull distribution |
|
|
108 |
##' |
|
|
109 |
##' See, for example, Lei, Y. Evaluation of three methods for estimating the Weibull distribution |
|
|
110 |
##' parameters of Chinese pine (Pinus tabulaeformis). Journal of Forest Science 54.12 (2008): 566-571. |
|
|
111 |
##' |
|
|
112 |
##' @param HR Hazard ratio |
|
|
113 |
##' @param r Randomization balance |
|
|
114 |
##' @param M control arm median |
|
|
115 |
##' @export |
|
|
116 |
FitMixtureModel <- function(HR,r,M){ |
|
|
117 |
|
|
|
118 |
lapply(list(HR=HR,r=r,M=M),function(x){ |
|
|
119 |
if(!is.numeric(x) || x <= 0 || length(x)!=1){ |
|
|
120 |
stop("All arguments to FitMixtureModel must be numeric, positive and of length 1") |
|
|
121 |
} |
|
|
122 |
}) |
|
|
123 |
|
|
|
124 |
ml2 <- M/log(2) |
|
|
125 |
mu <- (ml2*(1+r/HR))/(r+1) # = E(control)/(r+1) + rE(active)/r+1 |
|
|
126 |
sigma <- (ml2/(1+r)) * sqrt(1+2*r-2*r/HR + (r*(r+2))/(HR*HR)) |
|
|
127 |
|
|
|
128 |
return(RootFindRateShape(mu,sigma)) |
|
|
129 |
} |
|
|
130 |
|
|
|
131 |
|
|
|
132 |
# Fit shape and rate given mean and sd of Weibull |
|
|
133 |
# distribution |
|
|
134 |
# |
|
|
135 |
# @param mu mean of Weibull |
|
|
136 |
# @param sigma sd of distribution |
|
|
137 |
RootFindRateShape <- function(mu,sigma){ |
|
|
138 |
f <- function(x){ |
|
|
139 |
sigma/mu - sqrt(gamma(1+2/x) - gamma(1+1/x)^2)/gamma(1+1/x) |
|
|
140 |
} |
|
|
141 |
|
|
|
142 |
shape <- tryCatch({ |
|
|
143 |
uniroot(f,c(0.1,10))$root |
|
|
144 |
},error=function(cond){ |
|
|
145 |
warning(paste("Error fitting shape:",cond,"Returning NA")) |
|
|
146 |
return(list(rate=NA,shape=NA)) |
|
|
147 |
} |
|
|
148 |
) |
|
|
149 |
|
|
|
150 |
rate <- gamma(1+1/shape)/mu |
|
|
151 |
return(list(rate=rate,shape=shape)) |
|
|
152 |
} |