options(na.action=na.exclude) # preserve missings
options(contrasts=c('contr.treatment', 'contr.poly')) #ensure constrast type
aeq <- function(x,y) all.equal(as.vector(x), as.vector(y))
# These results can be found in Miller
fit <- coxph(Surv(aml$time, aml$status) ~ aml$x, method='breslow')
resid(fit, type='mart')
resid(fit, type='score')
resid(fit, type='scho')

# Test the drop of an itercept: should have no effect
fit2 <- coxph(Surv(time, status) ~ x -1, method='breslow',
aeq(fit$loglik, fit2$loglik)
aeq(coef(fit), coef(fit2))
aeq(fit$var, fit2$var)

fit <- survfit(Surv(aml$time, aml$status) ~ aml$x)
survdiff(Surv(aml$time, aml$status)~ aml$x)

# Test out the weighted K-M
#  First, equal case weights- shouldn't change the survival, but will
#    halve the variance
temp2 <-survfit(Surv(aml$time, aml$status)~1, weight=rep(2,23))
temp  <-survfit(Surv(time, status)~1, aml)
aeq(temp$surv, temp2$surv)
aeq(temp$std.err^2, 2*temp2$std.err^2)

# Risk weights-- use a null Cox model
tfit <- coxph(Surv(aml$time, aml$status) ~ offset(log(1:23)))
sfit <- survfit(tfit, stype=2, ctype=1, censor=FALSE)

# Now compute it by hand.  The survfit program will produce a curve
#   corresponding to the mean offset.
#  Ties are a nuisance, the line above forced the Nelson rather than Efron 
# to make it easier
rscore <- exp(log(1:23) - mean(log(1:23)))[order(aml$time)]
atime <- sort(aml$time)
denom <- rev(cumsum(rev(rscore)))
denom <- denom[match(unique(atime), atime)]
deaths <- tapply(aml$status, aml$time, sum)
chaz <- cumsum(deaths/denom)
all.equal(sfit$surv, as.vector(exp(-chaz[deaths>0])))

# And the Efron result

# Lots of ties, so its a good test case
x1 <- coxph(Surv(time, status)~x, aml, method='efron')
x2 <- coxph(Surv(rep(0,23),time, status) ~x, aml, method='efron')
aeq(x1$coef, x2$coef)

Try the survival package in your browser

Any scripts or data that you put into this service are public.

survival documentation built on Aug. 24, 2021, 5:06 p.m.