Learn R Programming

rms (version 8.1-0)

val.surv: Validate Predicted Probabilities Against Observed Survival Times

Description

The val.surv function is useful for validating predicted survival probabilities against right-censored failure times. If u is specified, the hazard regression function hare in the polspline package is used to relate predicted survival probability at time u to observed survival times (and censoring indicators) to estimate the actual survival probability at time u as a function of the estimated survival probability at that time, est.surv. If est.surv is not given, fit must be specified and the survest function is used to obtain the predicted values (using newdata if it is given, or using the stored linear predictor values if not). hare or movStats (when method="smoothkm") is given the sole predictor fun(est.surv) where fun is given by the user or is inferred from fit. fun is the function of predicted survival probabilities that one expects to create a linear relationship with the linear predictors.

hare uses an adaptive procedure to find a linear spline of fun(est.surv) in a model where the log hazard is a linear spline in time \(t\), and cross-products between the two splines are allowed so as to not assume proportional hazards. Thus hare assumes that the covariate and time functions are smooth but not much else, if the number of events in the dataset is large enough for obtaining a reliable flexible fit. Or specify method="smoothkm" to use the Hmisc movStats function to compute smoothed (by default using supsmu) moving window Kaplan-Meier estimates. This method is more flexible than hare.

There are special print and plot methods when u is given. In this case, val.surv returns an object of class "val.survh", otherwise it returns an object of class "val.surv".

If u is not specified, val.surv uses Cox-Snell (1968) residuals on the cumulative probability scale to check on the calibration of a survival model against right-censored failure time data. If the predicted survival probability at time \(t\) for a subject having predictors \(X\) is \(S(t|X)\), this method is based on the fact that the predicted probability of failure before time \(t\), \(1 - S(t|X)\), when evaluated at the subject's actual survival time \(T\), has a uniform (0,1) distribution. The quantity \(1 - S(T|X)\) is right-censored when \(T\) is. By getting one minus the Kaplan-Meier estimate of the distribution of \(1 - S(T|X)\) and plotting against the 45 degree line we can check for calibration accuracy. A more stringent assessment can be obtained by stratifying this analysis by an important predictor variable. The theoretical uniform distribution is only an approximation when the survival probabilities are estimates and not population values.

When censor is specified to val.surv, a different validation is done that is more stringent but that only uses the uncensored failure times. This method is used for type I censoring when the theoretical censoring times are known for subjects having uncensored failure times. Let \(T\), \(C\), and \(F\) denote respectively the failure time, censoring time, and cumulative failure time distribution (\(1 - S\)). The expected value of \(F(T | X)\) is 0.5 when \(T\) represents the subject's actual failure time. The expected value for an uncensored time is the expected value of \(F(T | T \leq C, X) = 0.5 F(C | X)\). A smooth plot of \(F(T|X) - 0.5 F(C|X)\) for uncensored \(T\) should be a flat line through \(y=0\) if the model is well calibrated. A smooth plot of \(2F(T|X)/F(C|X)\) for uncensored \(T\) should be a flat line through \(y=1.0\). The smooth plot is obtained by smoothing the (linear predictor, difference or ratio) pairs.

Note that the Cox-Snell residual plot is not very sensitive to model lack of fit.

Usage

val.surv(fit, newdata, S, est.surv,
         method=c('hare', 'smoothkm'),
         censor, u, fun, lim, evaluate=100, pred, maxdim=5, ...)

# S3 method for val.survh print(x, ...)

# S3 method for val.survh plot(x, lim, xlab, ylab, riskdist=TRUE, add=FALSE, scat1d.opts=list(nhistSpike=200), ...)

# S3 method for val.surv plot(x, group, g.group=4, what=c('difference','ratio'), type=c('l','b','p'), xlab, ylab, xlim, ylim, datadensity=TRUE, ...)

Arguments

Value

a list of class "val.surv" or "val.survh". Some plot methods return a ggplot2 object.

References

Cox DR, Snell EJ (1968):A general definition of residuals (with discussion). JRSSB 30:248--275.

Kooperberg C, Stone C, Truong Y (1995): Hazard regression. JASA 90:78--94.

May M, Royston P, Egger M, Justice AC, Sterne JAC (2004):Development and validation of a prognostic model for survival time data: application to prognosis of HIV positive patients treated with antiretroviral therapy. Stat in Med 23:2375--2398.

Stallard N (2009): Simple tests for th external validation of mortality prediction scores. Stat in Med 28:377--388.

See Also

validate, calibrate, hare, scat1d, cph, psm, groupkm

Examples

Run this code
# Generate failure times from an exponential distribution
require(survival)
set.seed(123)              # so can reproduce results
n <- 1000
age <- 50 + 12*rnorm(n)
sex <- factor(sample(c('Male','Female'), n, rep=TRUE, prob=c(.6, .4)))
cens <- 15*runif(n)
h <- .02*exp(.04*(age-50)+.8*(sex=='Female'))
t <- -log(runif(n))/h
units(t) <- 'Year'
label(t) <- 'Time to Event'
ev <- ifelse(t <= cens, 1, 0)
t <- pmin(t, cens)
S <- Surv(t, ev)

# First validate true model used to generate data

# If hare is available, make a smooth calibration plot for 1-year
# survival probability where we predict 1-year survival using the
# known true population survival probability
# In addition, use groupkm to show that grouping predictions into
# intervals and computing Kaplan-Meier estimates is not as accurate.

s1 <- exp(-h*1)
w <- val.surv(est.surv=s1, S=S, u=1,
              fun=function(p)log(-log(p)))
plot(w, lim=c(.85,1), scat1d.opts=list(nhistSpike=200, side=1))
groupkm(s1, S, m=100, u=1, pl=TRUE, add=TRUE)

# Now validate the true model using residuals

w <- val.surv(est.surv=exp(-h*t), S=S)
plot(w)
plot(w, group=sex)  # stratify by sex


# Now fit an exponential model and validate
# Note this is not really a validation as we're using the
# training data here
f <- psm(S ~ age + sex, dist='exponential', y=TRUE)
w <- val.surv(f)
plot(w, group=sex)


# We know the censoring time on every subject, so we can
# compare the predicted Pr[T <= observed T | T>c, X] to
# its expectation 0.5 Pr[T <= C | X] where C = censoring time
# We plot a ratio that should equal one
w <- val.surv(f, censor=cens)
plot(w)
plot(w, group=age, g=3)   # stratify by tertile of age

Run the code above in your browser using DataLab