Description Usage Arguments Value Author(s) References See Also Examples
Here we have implemented a simple and direct approach to utilize BART in survival analysis that is very flexible, and is akin to discrete-time survival analysis. Following the capabilities of BART, we allow for maximum flexibility in modeling the dependence of survival times on covariates. In particular, we do not impose proportional hazards.
To elaborate, consider data in the usual form: (t, delta, x) where t is the event time, delta is an indicator distinguishing events (delta=1) from right-censoring (delta=0), x is a vector of covariates, and i=1, ..., N (i suppressed for convenience) indexes subjects.
We denote the K distinct event/censoring times by 0<t(1)<...< t(K)<infinity thus taking t(j) to be the j'th order statistic among distinct observation times and, for convenience, t(0)=0. Now consider event indicators y(j) for each subject i at each distinct time t(j) up to and including the subject's observation time t=t(n) with n=sum I[t(j)<=t]. This means y(j)=0 if j<n and y(n)=delta.
We then denote by p(j) the probability of an event at time t(j) conditional on no previous event. We now write the model for y(j) as a nonparametric probit regression of y(j) on the time t(j) and the covariates x, and then utilize BART for binary responses. Specifically, y(j) = delta I[t=t(j)], j=1, ..., n ; we have p(j) = F(mu(j)), mu(j) = mu0+f(t(j), x) where F denotes the standard normal cdf (probit link). As in the binary response case, f is the sum of many tree models.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | recur.bart(x.train, y.train=NULL, times=NULL, delta=NULL, x.test=matrix(0.0,0,0),
x.test.nogrid=FALSE, keepcall=FALSE,
k=2.0, power=2.0, base=.95, binaryOffset=NULL,
ntree=50, ndpost=10000, nskip=250, printevery=100, keepevery=10,
keeptrainfits=TRUE, usequants=FALSE, numcut=100, printcutoffs=0,
verbose=TRUE,
seed=99, ## mc.recur.bart only
mc.cores=2, ## mc.recur.bart only
nice=19L ## mc.recur.bart only
)
mc.recur.bart(x.train, y.train=NULL, times=NULL, delta=NULL, x.test=matrix(0.0,0,0),
x.test.nogrid=FALSE, keepcall=FALSE,
k=2.0, power=2.0, base=.95, binaryOffset=NULL,
ntree=50, ndpost=10000, nskip=250, printevery=100, keepevery=10,
keeptrainfits=TRUE, usequants=FALSE, numcut=100, printcutoffs=0,
verbose=TRUE,
seed=99, ## mc.recur.bart only
mc.cores=2, ## mc.recur.bart only
nice=19L ## mc.recur.bart only
)
|
x.train |
Explanatory variables for training (in sample)
data. |
y.train |
Binary response dependent variable for training (in sample) data. |
times |
The time of event or right-censoring. |
delta |
The event indicator: 1 is an event while 0 is censored. |
x.test |
Explanatory variables for test (out of sample) data. |
x.test.nogrid |
Occasionally, you do not need the entire time grid for
|
keepcall |
Logical; if |
k |
k is the number of prior standard deviations f(t, x) is away from +/-3. The bigger k is, the more conservative the fitting will be. |
power |
Power parameter for tree prior. |
base |
Base parameter for tree prior. |
binaryOffset |
The model is P(Y=1 | t, x) = F(f(t, x) + mu0)
where mu0 is specified by |
ntree |
The number of trees in the sum. |
ndpost |
The number of posterior draws after burn in, ndpost/keepevery will actually be returned. |
nskip |
Number of MCMC iterations to be treated as burn in. |
printevery |
As the MCMC runs, a message is printed every printevery draws. |
keepevery |
Every keepevery draw is kept to be returned to the user. |
keeptrainfits |
If true the draws of f(t, x) for x = rows of x.train are returned. |
usequants |
Decision rules in the tree are of the form x <= c vs. x > c for each variable corresponding to a column of x.train. usequants determines how the set of possible c is determined. If usequants is true, then the c are a subset of the values (xs[i]+xs[i+1])/2 where xs is unique sorted values obtained from the corresponding column of x.train. If usequants is false, the cutoffs are equally spaced across the range of values taken on by the corresponding column of x.train. |
numcut |
The number of possible values of c (see usequants). If a single number if given, this is used for all variables. Otherwise a vector with length equal to ncol(x.train) is required, where the i^th element gives the number of c used for the i^th variable in x.train. If usequants is false, numcut equally spaced cutoffs are used covering the range of values in the corresponding column of x.train. If usequants is true, then min(numcut, the number of unique values in the corresponding columns of x.train - 1) c values are used. |
printcutoffs |
The number of cutoff rules c to printed to screen before the MCMC is run. Give a single integer, the same value will be used for all variables. If 0, nothing is printed. |
verbose |
Logical, if FALSE supress printing. |
seed |
|
mc.cores |
|
nice |
|
recur.bart
returns a list.
Besides the items listed below,
the list has a binaryOffset
component giving the value used,
a times
component giving the unique times and K
which is the number of
unique times.
yhat.train |
A matrix with (ndpost/keepevery) rows and nrow(x.train) columns.
Each row corresponds to a draw f* from the posterior of f
and each column corresponds to a row of x.train.
The (i,j) value is f*(t, x) for the i\^th kept draw of f
and the j\^th row of x.train. |
haz.train |
The hazard function, h(t|x), where x's are the rows of the training data. |
cum.train |
The cumulative hazard function, h(t|x), where x's are the rows of the training data. |
yhat.test |
Same as yhat.train but now the x's are the rows of the test data. |
haz.test |
The hazard function, h(t|x), where x's are the rows of the test data. |
cum.test |
The cumulative hazard function, h(t|x), where x's are the rows of the test data. |
varcount |
a matrix with (ndpost/keepevery) rows and nrow(x.train) columns. Each row is for a draw. For each variable (corresponding to the columns), the total count of the number of times that variable is used in a tree decision rule (over all trees) is given. |
Note that yhat.train and yhat.test are
f(t, x) + binaryOffset
. If you want draws of the probability
P(Y=1 | t, x) you need to apply the normal cdf (pnorm
)
to these values.
Rodney Sparapani: rsparapa@mcw.edu
Sparapani R., Rein L., Tarima S., Jackson T., Meurer J. (2017) Nonparametric recurrent events analysis with BART and an application to the hospital admissions of patients with diabetes. Biostatistics manuscript submitted.
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 | ## Not run:
data(x.train)
data(x.test)
data(y.train)
set.seed(99)
post <- recur.bart(x.train=x.train, y.train=y.train, x.test=x.test)
## larger data sets such as these can take some time
## if parallel processing is available, uncomment this block
## post <- mc.recur.bart(x.train=x.train, y.train=y.train,
## x.test=x.test, mc.cores=5, seed=99)
dss <- rpart(post$yhat.train.mean~x.train)
require(rpart.plot)
rpart.plot(dss)
## notice that all splits in the tree
## (except 1 at the bottom involving a small group)
## involve ca, cci_pud, cci_pvd, ins270 and n
## compare patients treated with insulin vs not
N.train <- 235
N.test <- 253
K <- post$K ## 798 unique time points
## only testing set, i.e., remove training set
x.test. <- x.test[N.train*K+(1:(N.test*K)), ]
x.test. <- rbind(x.test., x.test.)
x.test.[ , 'ins270'] <- rep(0:1, each=N.test*K)
## with timebart we can't predict x.test without also training
## we are working on enhancing this in the near future
set.seed(99)
post. <- recur.bart(x.train=x.train, y.train=y.train, x.test=x.test.)
## larger data sets such as these can take some time
## if parallel processing is available, uncomment this block
## post. <- mc.recur.bart(x.train=x.train, y.train=y.train,
## x.test=x.test., mc.cores=5, seed=99)
## create Friedman's partial dependence function for the
## intensity/hazard by time and ins270
NK.test <- N.test*K
M <- nrow(post$haz.test) ## number of MCMC samples, typically 1000
RI <- matrix(0, M, K)
for(i in 1:N.test)
RI <- RI+(post.$haz.test[ , (N.test+i-1)*K+1:K]/
post.$haz.test[ , (i-1)*K+1:K])/N.test
RI.lo <- apply(RI, 2, quantile, probs=0.025)
RI.mu <- apply(RI, 2, mean)
RI.hi <- apply(RI, 2, quantile, probs=0.975)
plot(post.$times, RI.hi, type='l', lty=2, log='y',
ylim=c(min(RI.lo, 1/RI.hi), max(1/RI.lo, RI.hi)),
xlab='t', ylab='RI(t, x)',
sub='insulin(ins270=1) vs. no insulin(ins270=0)',
main='Relative intensity of hospital admissions for diabetics')
lines(post.$times, RI.mu)
lines(post.$times, RI.lo, lty=2)
lines(post.$times, rep(1, K), col='darkgray')
## RI for insulin therapy seems fairly constant with time
mean(RI.mu)
## End(Not run)
|
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.