This file contains R code for the analyses in Chapter 9 of the book Dynamic Prediction in Clinical Survival Analysis (CRC Chapman & Hall) by Hans C. van Houwelingen and Hein Putter
R code written by Hein Putter (H.Putter@lumc.nl for comments/questions) The dynpred package is available from CRAN
Consistency with the book has been checked with - R version 2.14.0 - survival version 2.36-10 - dynpred version 0.1.1
Code
################################################################################################################################################################# Section 9.3: Application (ALL data)##############################################################################################################################################################require(dynpred)require(mstate)data(ALL)year <-365.25month <- year/12################################################################################################################################################################# Table 9.1: Cox regression for death and/or relapse################################################################################################################################################################# To construct this table, a new data set needs to be constructed containing### the time-dependent covariates (recent) AGvHD and PR, in long format.### This can be done from scratch; here the mstate package is used, in### particular the function msprep(). For this to work we need to define### a multi-state model with AGvHD and PR + 30 days as new eventstransListn <-list("Tx"=c(2, 4, 10, 11),"A"=c(3, 6, 10, 11),"A30"=c(7, 10, 11),"R"=c(5, 6, 10, 11),"R30"=c(8, 10, 11),"AR"=c(7, 8, 10, 11),"A30R"=c(9, 10, 11),"AR30"=c(9, 10, 11),"A30R30"=c(10, 11),"Rel"=c(),"Death"=c())tmat <-transMat(transListn)tmat# Define RFS (minimum of relapse and death)ALL$rfs <-pmin(ALL$rel,ALL$srv)ALL$rfs.s <-pmax(ALL$rel.s,ALL$srv.s)# Define "new states" as recovery and/or AE plus one monthALL$r30 <- ALL$rec + monthALL$r30.s <- ALL$rec.sALL$a30 <- ALL$ae + monthALL$a30.s <- ALL$ae.sALL$ar <-pmax(ALL$ae,ALL$rec) # already in data (as recae)ALL$ar.s <-pmin(ALL$ae.s,ALL$rec.s) # already in data (as recae.s)ALL$a30r <-pmax(ALL$a30,ALL$rec)ALL$a30r.s <-pmin(ALL$ae.s,ALL$rec.s)ALL$ar30 <-pmax(ALL$ae,ALL$r30)ALL$ar30.s <-pmin(ALL$ae.s,ALL$rec.s)ALL$a30r30 <-pmax(ALL$a30,ALL$r30)ALL$a30r30.s <-pmin(ALL$ae.s,ALL$rec.s)# These newly defined a30 etc should never go beyond end of follow-upwh <-which(ALL$r30>ALL$rfs)ALL$r30.s[wh] <-0ALL$r30[wh] <- ALL$rfs[wh]wh <-which(ALL$a30>ALL$rfs)ALL$a30.s[wh] <-0ALL$a30[wh] <- ALL$rfs[wh]wh <-which(ALL$a30r>ALL$rfs)ALL$a30r.s[wh] <-0ALL$a30r[wh] <- ALL$rfs[wh]wh <-which(ALL$ar30>ALL$rfs)ALL$ar30.s[wh] <-0ALL$ar30[wh] <- ALL$rfs[wh]wh <-which(ALL$a30r30>ALL$rfs)ALL$a30r30.s[wh] <-0ALL$a30r30[wh] <- ALL$rfs[wh]# covariatescovs <-c("year","agecl","proph","match")ALL2 <-msprep(time=c(NA,"ae","a30","rec","r30","ar","a30r","ar30","a30r30","rel","srv"),status=c(NA,"ae.s","a30.s","rec.s","r30.s","ar.s","a30r.s","ar30.s","a30r30.s","rel.s","srv.s"),data=ALL, trans=tmat, keep=covs)# We are now going to add the values of the time-dependent covariates in the# ALL2 dataALL2$A <- ALL2$recA <- ALL2$R <- ALL2$recR <-0ALL2$A[ALL2$from %in%c(2,3,6,7,8,9)] <-1ALL2$recA[ALL2$from %in%c(2,6,8)] <-1ALL2$R[ALL2$from %in%4:9] <-1ALL2$recR[ALL2$from %in%c(4,6,7)] <-1# For time-dependent Cox regression we are only interested in transitions# into either relapse or death### First relapseALL2Rel <- ALL2[ALL2$to==10,]ALL2Rel <- ALL2Rel[!is.na(ALL2Rel$id),]c1Rel <-coxph(Surv(Tstart,Tstop,status) ~ match + proph + year + agecl + A + recA + R + recR,data = ALL2Rel, method="breslow")c1Rel### Then deathALL2Death <- ALL2[ALL2$to==11,]ALL2Death <- ALL2Death[!is.na(ALL2Death$id),]c1Death <-coxph(Surv(Tstart,Tstop,status) ~ match + proph + year + agecl + A + recA + R + recR,data = ALL2Death, method="breslow")c1Death### For RFS, we could either adapt ALL2, or (quicker) redefine ALL2### based on new transition matrixtransListn <-list("Tx"=c(2, 4, 10),"A"=c(3, 6, 10),"A30"=c(7, 10),"R"=c(5, 6, 10),"R30"=c(8, 10),"AR"=c(7, 8, 10),"A30R"=c(9, 10),"AR30"=c(9, 10),"A30R30"=c(10),"RelDeath"=c())tmat2 <-transMat(transListn)tmat2ALL2 <-msprep(time=c(NA,"ae","a30","rec","r30","ar","a30r","ar30","a30r30","rfs"),status=c(NA,"ae.s","a30.s","rec.s","r30.s","ar.s","a30r.s","ar30.s","a30r30.s","rfs.s"),data=ALL, trans=tmat2, keep=covs)# Again add values of the time-dependent covariates in ALL2ALL2$A <- ALL2$recA <- ALL2$R <- ALL2$recR <-0ALL2$A[ALL2$from %in%c(2,3,6,7,8,9)] <-1ALL2$recA[ALL2$from %in%c(2,6,8)] <-1ALL2$R[ALL2$from %in%4:9] <-1ALL2$recR[ALL2$from %in%c(4,6,7)] <-1ALL2RFS <- ALL2[ALL2$to==10,]ALL2RFS <- ALL2RFS[!is.na(ALL2RFS$id),]c1 <-coxph(Surv(Tstart,Tstop,status) ~ match + proph + year + agecl + A + recA + R + recR,data = ALL2RFS, method="breslow")c1################################################################################################################################################################# Table 9.2: Cox regression for AGvHD and platelet recovery################################################################################################################################################################# Time-dependent Cox models for AGvHD and platelet recovery## AGvHDtransListn <-list("Tx"=c(2, 4),"R"=c(3, 4),"R30"=c(4),"A"=c())tmat3 <-transMat(transListn)tmat3ALL3 <-msprep(time=c(NA,"rec","r30","ae"),status=c(NA,"rec.s","r30.s","ae.s"),data=ALL, trans=tmat3, keep=covs)# Again add values of the time-dependent covariates in ALL3ALL3$R <- ALL3$recR <-0ALL3$R[ALL3$from %in%c(2,3)] <-1ALL3$recR[ALL3$from==2] <-1ALL3s <- ALL3[ALL3$to==4,]# For some reason, two "Inf" values for Tstop and time (with status 0),# set to largest observed timeALL3s$Tstop[is.infinite(ALL3s$Tstop)] <-max(ALL3s$Tstop[!is.infinite(ALL3s$Tstop)])ALL3s$time <- ALL3s$Tstop - ALL3s$Tstartc2 <-coxph(Surv(Tstart,Tstop,status) ~ match + proph + year + agecl + R + recR,data = ALL3s, method="breslow")c2## Platelet recoverytransListn <-list("Tx"=c(2, 4),"A"=c(3, 4),"A30"=c(4),"R"=c())tmat4 <-transMat(transListn)tmat4ALL4 <-msprep(time=c(NA,"ae","a30","rec"),status=c(NA,"ae.s","a30.s","rec.s"),data=ALL, trans=tmat3, keep=covs)# Again add values of the time-dependent covariates in ALL4ALL4$A <- ALL4$recA <-0ALL4$A[ALL4$from %in%c(2,3)] <-1ALL4$recA[ALL4$from==2] <-1ALL4s <- ALL4[ALL4$to==4,]c3 <-coxph(Surv(Tstart,Tstop,status) ~ match + proph + year + agecl + A + recA,data = ALL4s, method="breslow")c3################################################################################################################################################################# Figure 9.8: Cumulative baseline hazards for AGVHD, platelet recovery,### and for relapse and/or death################################################################################################################################################################# We have saved c1, c1Rel, c1Death, c2, c3, Cox models for RFS,### Relapse, Death, AE, and Rec, respectively### First fix a patient with reference values for the covariates### and 0 for all the time-dependent covariates; this will give the### baseline hazardsndata <-data.frame(match=1, proph=1, year=1, agecl=1, R=0, recR=0, A=0, recA=0)ndata$match <-factor(ndata$match, levels=1:2, labels=levels(ALL$match))ndata$proph <-factor(ndata$proph, levels=1:2, labels=levels(ALL$proph))ndata$year <-factor(ndata$year, levels=1:3, labels=levels(ALL$year))ndata$agecl <-factor(ndata$agecl, levels=1:3, labels=levels(ALL$agecl))ndatasf1Rel <-survfit(c1Rel, newdata=ndata, censor=FALSE)sf1Rel <-data.frame(time=sf1Rel$time,surv=sf1Rel$surv,Haz=-log(sf1Rel$surv))sf1Death <-survfit(c1Death, newdata=ndata, censor=FALSE)sf1Death <-data.frame(time=sf1Death$time,surv=sf1Death$surv,Haz=-log(sf1Death$surv))sf1 <-survfit(c1, newdata=ndata, censor=FALSE)sf1 <-data.frame(time=sf1$time,surv=sf1$surv,Haz=-log(sf1$surv))sf2 <-survfit(c2, newdata=ndata, censor=FALSE)sf2 <-data.frame(time=sf2$time,surv=sf2$surv,Haz=-log(sf2$surv))# extend sf2 a little bitn2 <-nrow(sf2)sf2 <-rbind(sf2,data.frame(time=500,surv=sf2$surv[n2],Haz=sf2$Haz[n2]))sf3 <-survfit(c3, newdata=ndata, censor=FALSE)sf3 <-data.frame(time=sf3$time,surv=sf3$surv,Haz=-log(sf3$surv))## Plot baseline cumulative hazardsmaxHaz <-max(c(sf1$Haz,sf2$Haz,sf3$Haz))plot(sf1$time/365.25,sf1$Haz,type="s",lwd=2,ylim=c(0,maxHaz),xlab="Years since transplantation",ylab="Cumulative hazard")lines(sf1Rel$time/365.25,sf1Rel$Haz,type="s",lwd=2,lty=2)lines(sf1Death$time/365.25,sf1Death$Haz,type="s",lwd=2,lty=3)lines(sf2$time/365.25,sf2$Haz,type="s",lwd=2,lty=4)lines(sf3$time/365.25,sf3$Haz,type="s",lwd=2,lty=5)legend("topright",c("Relapse or death","Relapse","Death"),lwd=2,lty=1:3,bty="n")legend(2,0.68,c("AGvHD","Platelet recovery"),lwd=2,lty=4:5,bty="n")###################################################### Prediction by landmarking###################################################ALL$time <-pmin(ALL$rel,ALL$srv)ALL$status <-0ALL$status[((ALL$rel<=ALL$srv) & (ALL$rel.s==1))] <-1ALL$status[((ALL$srv<=ALL$rel) & (ALL$srv.s==1))] <-2table(ALL$rel.s,ALL$srv.s,ALL$status)table(ALL$status)w <-5*yearcovs <-c("year","agecl","proph","match")### Construct landmark dataLMs <-seq(0,year,length=101)LMdata <-NULLfor (i inseq(along=LMs)) { LM <- LMs[i] ALLi <- ALL[ALL$time>LM,] R <-as.numeric(ALLi$rec<=LM) A <-as.numeric(ALLi$ae<=LM) recR <-as.numeric(ALLi$rec<=LM & ALLi$rec>LM-month) recA <-as.numeric(ALLi$ae<=LM & ALLi$ae<=LM-month) ALLi$status[ALLi$time>LM+w] <-0 ALLi$time[ALLi$time>LM+w] <- LM+w ALLicovs <- ALLi[,match(covs,names(ALLi))] dfri <-data.frame(id=ALLi$id,time=ALLi$time,status=ALLi$status,LM=LM,R=R,recR=recR,A=A,recA=recA) dfri <-cbind(dfri,ALLicovs) LMdata <-rbind(LMdata,dfri)}# Summariesdim(LMdata)table(table(LMdata$id))################################################################################################################################################################# Table 9.3: Landmark supermodel with proportional baseline hazards### for death and/or relapse, based on an equally spaced set of landmark### time-points from 0 to 1 with distance 0.01 and window width w = 5 years############################################################################################################################################################### For theta(s)g1 <-function(t) tg2 <-function(t) t^2LMdata$LM1 <-g1(LMdata$LM/year)LMdata$LM2 <-g2(LMdata$LM/year)### Landmark supermodels## First stratified (these are NOT included in the book)# RelapseLMcox1 <-coxph(Surv(time,status==1) ~ match + proph + year + agecl + A + recA + R + recR +strata(LM) +cluster(id), data=LMdata)LMcox1# Death before relapseLMcox2 <-coxph(Surv(time,status==2) ~ match + proph + year + agecl + A + recA + R + recR +strata(LM) +cluster(id), data=LMdata)LMcox2# RFSLMcox0 <-coxph(Surv(time,status>0) ~ match + proph + year + agecl + A + recA + R + recR +strata(LM) +cluster(id), data=LMdata)LMcox0### Same thing, now with proportional baselines (ipl*)## Take three coffee breaks; this takes a while, because of the large stacked## landmark data set# RelapseLMcox1 <-coxph(Surv(time,status==1) ~ match + proph + year + agecl + A + recA + R + recR + LM1 + LM2 +cluster(id),data=LMdata)LMcox1# Death before relapseLMcox2 <-coxph(Surv(time,status==2) ~ match + proph + year + agecl + A + recA + R + recR + LM1 + LM2 +cluster(id),data=LMdata)LMcox2# RFSLMcox0 <-coxph(Surv(time,status>0) ~ match + proph + year + agecl + A + recA + R + recR + LM1 + LM2 +cluster(id),data=LMdata)LMcox0################################################################################################################################################################# Figure 9.9: Baseline hazard and landmark effects in the proportional### baselines landmark supermodel of Table 9.3############################################################################################################################################################### Baseline hazards (plot as in chapters 7 and 8)ndata <-data.frame(match=1, proph=1, year=1, agecl=1, R=0, recR=0, A=0, recA=0,LM1=0, LM2=0)ndata$match <-factor(ndata$match, levels=1:2, labels=levels(ALL$match))ndata$proph <-factor(ndata$proph, levels=1:2, labels=levels(ALL$proph))ndata$year <-factor(ndata$year, levels=1:3, labels=levels(ALL$year))ndata$agecl <-factor(ndata$agecl, levels=1:3, labels=levels(ALL$agecl))ndatasf20 <-survfit(LMcox0, newdata=ndata, censor=FALSE)Haz20 <-data.frame(time=sf20$time,surv=sf20$surv)Haz20$Haz <--log(Haz20$surv)sf20Rel <-survfit(LMcox1, newdata=ndata, censor=FALSE)Haz20Rel <-data.frame(time=sf20Rel$time,surv=sf20Rel$surv)Haz20Rel$Haz <--log(Haz20Rel$surv)sf20Death <-survfit(LMcox2, newdata=ndata, censor=FALSE)Haz20Death <-data.frame(time=sf20Death$time,surv=sf20Death$surv)Haz20Death$Haz <--log(Haz20Death$surv)oldpar <-par(no.readonly=TRUE) # save graphical parameterspar(mfrow=c(1,2))par(mar=c(5,4,4,1.6)+0.1)plot(Haz20$time/year, Haz20$Haz, type="s", lwd=2,xlab="Time (years)", ylab="Cumulative hazard")lines(Haz20Rel$time/year, Haz20Rel$Haz, type="s", lwd=2, lty=2)lines(Haz20Death$time/year, Haz20Death$Haz, type="s", lwd=2, lty=3)legend("topleft",c("RFS","Relapse","Death"),lwd=2,lty=1:3,bty="n")par(mar=c(5,3.6,4,2)+0.1)plot(LMs/year, exp(LMcox0$coef[11]*g1(LMs/year) + LMcox0$coef[12]*g2(LMs/year)),type="l", lwd=2, ylim=c(0,1), xlab="Landmark (s)", ylab="exp(theta(s))")lines(LMs/year, exp(LMcox1$coef[11]*g1(LMs/year) + LMcox1$coef[12]*g2(LMs/year)),type="l", lwd=2, lty=2)lines(LMs/year, exp(LMcox2$coef[11]*g1(LMs/year) + LMcox2$coef[12]*g2(LMs/year)),type="l", lwd=2, lty=3)legend("topright",c("RFS","Relapse","Death"),lwd=2,lty=1:3,bty="n")par(oldpar) # reset graphical parameters################################################################################################################################################################# Figure 9.10 Landmark dynamic fixed width (w = 5) prediction probabilities### of relapse or death for all combinations of AGvHD and PR information##############################################################################################################################################################w <-5*yeartt <-seq(0,year,length=101)nt <-length(tt)Fwpredict <-function(bet, Haz, w, tt){ nt <-length(tt) Haz$haz <-diff(c(0,Haz$Haz)) Fw <-data.frame(time=tt,Fw=NA)for (i in1:nt) { sfi <- Haz # local copy tti <- tt[i] sfi$haz <- sfi$haz *exp(bet[11]*g1(tt[i]/year) + bet[12]*g2(tt[i]/year)) sfi$Haz <-cumsum(sfi$haz) tmp <-evalstep(sfi$time,sfi$Haz,c(tti,tti+w),subst=0) Fw$Fw[i] <-1-exp(-(tmp[2]-tmp[1])) }return(Fw)}# < 20Haz <- Haz20HazrecP <- HazP <- HazHazrecP$Haz <- HazrecP$Haz*exp(LMcox0$coef[9]+LMcox0$coef[10])HazP$Haz <- HazP$Haz*exp(LMcox0$coef[9])HazrecA <- HazHazrecA$Haz <- HazrecA$Haz*exp(LMcox0$coef[7]+LMcox0$coef[8])HazrecArecP <- HazrecAP <- HazrecAHazrecArecP$Haz <- HazrecArecP$Haz*exp(LMcox0$coef[9]+LMcox0$coef[10])HazrecAP$Haz <- HazrecAP$Haz*exp(LMcox0$coef[9])HazA <- HazHazA$Haz <- HazA$Haz*exp(LMcox0$coef[7])HazArecP <- HazAP <- HazrecAHazArecP$Haz <- HazArecP$Haz*exp(LMcox0$coef[9]+LMcox0$coef[10])HazAP$Haz <- HazAP$Haz*exp(LMcox0$coef[9])Fw20 <-Fwpredict(LMcox0$coef, Haz, w, tt)Fw20recP <-Fwpredict(LMcox0$coef, HazrecP, w, tt)Fw20P <-Fwpredict(LMcox0$coef, HazP, w, tt)Fw20recA <-Fwpredict(LMcox0$coef, HazrecA, w, tt)Fw20recArecP <-Fwpredict(LMcox0$coef, HazrecArecP, w, tt)Fw20recAP <-Fwpredict(LMcox0$coef, HazrecAP, w, tt)Fw20A <-Fwpredict(LMcox0$coef, HazA, w, tt)Fw20ArecP <-Fwpredict(LMcox0$coef, HazArecP, w, tt)Fw20AP <-Fwpredict(LMcox0$coef, HazAP, w, tt)# 20-40Haz <- Haz20Haz$Haz <- Haz$Haz*exp(LMcox0$coef[5])HazrecP <- HazP <- HazHazrecP$Haz <- HazrecP$Haz*exp(LMcox0$coef[9]+LMcox0$coef[10])HazP$Haz <- HazP$Haz*exp(LMcox0$coef[9])HazrecA <- HazHazrecA$Haz <- HazrecA$Haz*exp(LMcox0$coef[7]+LMcox0$coef[8])HazrecArecP <- HazrecAP <- HazrecAHazrecArecP$Haz <- HazrecArecP$Haz*exp(LMcox0$coef[9]+LMcox0$coef[10])HazrecAP$Haz <- HazrecAP$Haz*exp(LMcox0$coef[9])HazA <- HazHazA$Haz <- HazA$Haz*exp(LMcox0$coef[7])HazArecP <- HazAP <- HazrecAHazArecP$Haz <- HazArecP$Haz*exp(LMcox0$coef[9]+LMcox0$coef[10])HazAP$Haz <- HazAP$Haz*exp(LMcox0$coef[9])Fw2040 <-Fwpredict(LMcox0$coef, Haz, w, tt)Fw2040recP <-Fwpredict(LMcox0$coef, HazrecP, w, tt)Fw2040P <-Fwpredict(LMcox0$coef, HazP, w, tt)Fw2040recA <-Fwpredict(LMcox0$coef, HazrecA, w, tt)Fw2040recArecP <-Fwpredict(LMcox0$coef, HazrecArecP, w, tt)Fw2040recAP <-Fwpredict(LMcox0$coef, HazrecAP, w, tt)Fw2040A <-Fwpredict(LMcox0$coef, HazA, w, tt)Fw2040ArecP <-Fwpredict(LMcox0$coef, HazArecP, w, tt)Fw2040AP <-Fwpredict(LMcox0$coef, HazAP, w, tt)# >40Haz <- Haz20Haz$Haz <- Haz$Haz*exp(LMcox0$coef[6])HazrecP <- HazP <- HazHazrecP$Haz <- HazrecP$Haz*exp(LMcox0$coef[9]+LMcox0$coef[10])HazP$Haz <- HazP$Haz*exp(LMcox0$coef[9])HazrecA <- HazHazrecA$Haz <- HazrecA$Haz*exp(LMcox0$coef[7]+LMcox0$coef[8])HazrecArecP <- HazrecAP <- HazrecAHazrecArecP$Haz <- HazrecArecP$Haz*exp(LMcox0$coef[9]+LMcox0$coef[10])HazrecAP$Haz <- HazrecAP$Haz*exp(LMcox0$coef[9])HazA <- HazHazA$Haz <- HazA$Haz*exp(LMcox0$coef[7])HazArecP <- HazAP <- HazrecAHazArecP$Haz <- HazArecP$Haz*exp(LMcox0$coef[9]+LMcox0$coef[10])HazAP$Haz <- HazAP$Haz*exp(LMcox0$coef[9])Fw40 <-Fwpredict(LMcox0$coef, Haz, w, tt)Fw40recP <-Fwpredict(LMcox0$coef, HazrecP, w, tt)Fw40P <-Fwpredict(LMcox0$coef, HazP, w, tt)Fw40recA <-Fwpredict(LMcox0$coef, HazrecA, w, tt)Fw40recArecP <-Fwpredict(LMcox0$coef, HazrecArecP, w, tt)Fw40recAP <-Fwpredict(LMcox0$coef, HazrecAP, w, tt)Fw40A <-Fwpredict(LMcox0$coef, HazA, w, tt)Fw40ArecP <-Fwpredict(LMcox0$coef, HazArecP, w, tt)Fw40AP <-Fwpredict(LMcox0$coef, HazAP, w, tt)# Prepare everything in single data set, to make nice (trellis) pictureFwall <-rbind(Fw20,Fw2040,Fw40,Fw20recP,Fw2040recP,Fw40recP,Fw20P,Fw2040P,Fw40P, Fw20recA,Fw2040recA,Fw40recA,Fw20recArecP,Fw2040recArecP,Fw40recArecP,Fw20recAP,Fw2040recAP,Fw40recAP, Fw20A,Fw2040A,Fw40A,Fw20ArecP,Fw2040ArecP,Fw40ArecP,Fw20AP,Fw2040AP,Fw40AP)Fwall$time <- Fwall$time/yearFwall$age <-rep(rep(1:3,rep(101,3)),9)Fwall$A <-rep(1:3,rep(101*9,3))Fwall$P <-rep(rep(1:3,rep(101*3,3)),3)Fwall$AP <-3*(4-Fwall$A) + Fwall$PFwall$AP <-factor(Fwall$AP,labels=c("Past AGvHD, no PR","Past AGvHD, recent PR","Past AGvHD, past PR","Recent AGvHD, no PR","Recent AGvHD, recent PR","Recent AGvHD, past PR","No AGvHD, no PR","No AGvHD, recent PR","No AGvHD, past PR"))Fwall$age <-factor(Fwall$age,labels=c("Age <= 20","Age 20-40","Age > 40"))require(lattice)key.age <-list(text =list(levels(Fwall$age)),lines =list(lwd =2, lty =1:3, col ="black"))xyplot(Fw ~ time | AP, data=Fwall, groups=age, ylim=c(0,1), lwd=2, type="l", col=1, lty=1:3,xlab="Prediction time (years)",ylab="Probability of relapse or death", key=key.age)################################################################################################################################################################# Figure 9.11: Landmark dynamic fixed width (w = 5) prediction probabilities### of relapse or death for a patient as intermediate clinical events occur############################################################################################################################################################### Example: patient $>40$ years old; with platelet recovery after 30 days, AGvHD after 80 daysplot(Fw40$time[1:9]/year,Fw40$Fw[1:9],type="l",lwd=2,xlim=c(0,1),ylim=c(0,1),xlab="Prediction time (years)", ylab="Probability of relapse/death within 5 years")lines(rep(Fw40$time[9]/year,2),c(Fw40$Fw[9],Fw40recP$Fw[9]),lty=2)lines(Fw40recP$time[9:17]/year,Fw40recP$Fw[9:17],type="l",lwd=2)lines(rep(Fw40recP$time[17]/year,2),c(Fw40recP$Fw[17],Fw40P$Fw[17]),lty=2)lines(Fw40P$time[17:22]/year,Fw40P$Fw[17:22],type="l",lwd=2)lines(rep(Fw40P$time[22]/year,2),c(Fw40P$Fw[22],Fw40recAP$Fw[22]),lty=2)lines(Fw40recAP$time[22:31]/year,Fw40recAP$Fw[22:31],type="l",lwd=2)lines(rep(Fw40recAP$time[31]/year,2),c(Fw40recAP$Fw[31],Fw40AP$Fw[31]),lty=2)lines(Fw40AP$time[31:101]/year,Fw40AP$Fw[31:101],type="l",lwd=2)### Simulation-based "calculation" of transition probabilities###### This is similar to mssample in mstate, but we cannot use that,### because of the distinction between recent-intermediate event### and intermediate event; functions are defined in### "sample function definitions.r", which needs to be placed in the### working directory.source("sample function definitions.r")### The code is given below, but the actual sampling command### (Events <- Msample(sfM,M,tcond=0,c1,c2,c3)) is commented out.### The main reason for this is that it takes a very long time.### Unfortunately, I forgot to set a random seed when I started### the simulations for the book, so exact reproduction is impossible,### I'm afraid. The results of the original simulations were saved in### text files "events20.txt", "events2040.txt", and "events40.txt".### These are read in and used in the sequel. They also need to be### placed in the working directory.### Age <= 20ndata <-data.frame(match=1, proph=1, year=1, agecl=1, R=0, recR=0, A=0, recA=0)ndata$match <-factor(ndata$match, levels=1:2, labels=levels(ALL$match))ndata$proph <-factor(ndata$proph, levels=1:2, labels=levels(ALL$proph))ndata$year <-factor(ndata$year, levels=1:3, labels=levels(ALL$year))ndata$agecl <-factor(ndata$agecl, levels=1:3, labels=levels(ALL$agecl))ndatasf1 <-survfit(c1, newdata=ndata, censor=FALSE)sf1 <-data.frame(time=sf1$time,surv=sf1$surv,Haz=-log(sf1$surv))sf2 <-survfit(c2, newdata=ndata, censor=FALSE)sf2 <-data.frame(time=sf2$time,surv=sf2$surv,Haz=-log(sf2$surv))sf3 <-survfit(c3, newdata=ndata, censor=FALSE)sf3 <-data.frame(time=sf3$time,surv=sf3$surv,Haz=-log(sf3$surv))# Combine sf's into onesf1$trans <-1; sf2$trans <-2; sf3$trans <-3sfM <-rbind(sf1,sf2,sf3)# M <- 100000# Events <- Msample(sfM,M,tcond=0,c1,c2,c3) # will not exactly reproduce book results# write.table(Events,"events20.txt",sep="\t",append=TRUE,row.names=FALSE,col.names=FALSE)### Age 20-40ndata <-data.frame(match=1, proph=1, year=1, agecl=2, R=0, recR=0, A=0, recA=0)ndata$match <-factor(ndata$match, levels=1:2, labels=levels(ALL$match))ndata$proph <-factor(ndata$proph, levels=1:2, labels=levels(ALL$proph))ndata$year <-factor(ndata$year, levels=1:3, labels=levels(ALL$year))ndata$agecl <-factor(ndata$agecl, levels=1:3, labels=levels(ALL$agecl))ndatasf1 <-survfit(c1, newdata=ndata, censor=FALSE)sf1 <-data.frame(time=sf1$time,surv=sf1$surv,Haz=-log(sf1$surv))sf2 <-survfit(c2, newdata=ndata, censor=FALSE)sf2 <-data.frame(time=sf2$time,surv=sf2$surv,Haz=-log(sf2$surv))sf3 <-survfit(c3, newdata=ndata, censor=FALSE)sf3 <-data.frame(time=sf3$time,surv=sf3$surv,Haz=-log(sf3$surv))# Combine sf's into sf1$trans <-1; sf2$trans <-2; sf3$trans <-3sfM <-rbind(sf1,sf2,sf3)# M <- 100000# Events <- Msample(sfM,M,tcond=0,c1,c2,c3) # will not exactly reproduce book results# write.table(Events,"events2040.txt",sep="\t",append=TRUE,row.names=FALSE,col.names=FALSE)### Age > 40ndata <-data.frame(match=1, proph=1, year=1, agecl=3, R=0, recR=0, A=0, recA=0)ndata$match <-factor(ndata$match, levels=1:2, labels=levels(ALL$match))ndata$proph <-factor(ndata$proph, levels=1:2, labels=levels(ALL$proph))ndata$year <-factor(ndata$year, levels=1:3, labels=levels(ALL$year))ndata$agecl <-factor(ndata$agecl, levels=1:3, labels=levels(ALL$agecl))ndatasf1 <-survfit(c1, newdata=ndata, censor=FALSE)sf1 <-data.frame(time=sf1$time,surv=sf1$surv,Haz=-log(sf1$surv))sf2 <-survfit(c2, newdata=ndata, censor=FALSE)sf2 <-data.frame(time=sf2$time,surv=sf2$surv,Haz=-log(sf2$surv))sf3 <-survfit(c3, newdata=ndata, censor=FALSE)sf3 <-data.frame(time=sf3$time,surv=sf3$surv,Haz=-log(sf3$surv))# Combine sf's into sf1$trans <-1; sf2$trans <-2; sf3$trans <-3sfM <-rbind(sf1,sf2,sf3)M <-100000# Events <- Msample(sfM,M,tcond=0,c1,c2,c3) # will not exactly reproduce book results# write.table(Events,"events40.txt",sep="\t",append=TRUE,row.names=FALSE,col.names=FALSE)### Read in the results of the simulationEv20 <-read.table("events20.txt",sep="\t")Ev2040 <-read.table("events2040.txt",sep="\t")Ev40 <-read.table("events40.txt",sep="\t")Ev <- Ev20r20 <-matrix(NA,909,5)r20[,5] <-1sseq <-seq(0,year,length=101)nseq <-length(sseq)# This is to monitor progressm <-floor(log10(nseq)) +1pre <-rep("\b", 2* m +1)for (i in1:length(sseq)) {cat(pre, i, "/", nseq, sep =""); flush.console() s <- sseq[i]# deb(s, method="cat") wh <-which(Ev[,1]>s) whrecP <-which(Ev[,1]<=s & Ev[,1]>s-month & Ev[,2]==3& Ev[,3]>s) whP <-which(Ev[,1]<=s-month & Ev[,2]==3& Ev[,3]>s) whrecA <-which(Ev[,1]<=s & Ev[,1]>s-month & Ev[,2]==2& Ev[,3]>s) whrecArecP <-which(Ev[,1]<=s & Ev[,1]>s-month & Ev[,3]<=s & Ev[,3]>s-month & Ev[,2]>1& Ev[,4]>1& Ev[,5]>s) whrecAP <-which(Ev[,3]<=s & Ev[,3]>s-month & Ev[,1]<=s-month & Ev[,2]==3& Ev[,4]==2& Ev[,5]>s) whA <-which(Ev[,1]<=s-month & Ev[,2]==2& Ev[,3]>s) whArecP <-which(Ev[,3]<=s & Ev[,3]>s-month & Ev[,1]<=s-month & Ev[,2]==2& Ev[,4]==3& Ev[,5]>s) whAP <-which(Ev[,1]<=s-month & Ev[,3]<=s-month & Ev[,2]>1& Ev[,4]>1& Ev[,5]>s) whout <-which((Ev[,1]<=s & Ev[,2]==1) | (Ev[,3]<=s & Ev[,4]==1) | (Ev[,5]<=s & Ev[,6]==1)) Ev[,7] <-NAif (length(wh)>0) Ev[wh,7] <-1if (length(whrecP)>0) Ev[whrecP,7] <-2if (length(whP)>0) Ev[whP,7] <-3if (length(whrecA)>0) Ev[whrecA,7] <-4if (length(whrecArecP)>0) Ev[whrecArecP,7] <-5if (length(whrecAP)>0) Ev[whrecAP,7] <-6if (length(whA)>0) Ev[whA,7] <-7if (length(whArecP)>0) Ev[whArecP,7] <-8if (length(whAP)>0) Ev[whAP,7] <-9if (length(whout)>0) Ev[whout,7] <-0# deb(table(Ev[,7],exclude=NULL)) r20[(i-1)*9+1,4] <-length(wh)/M r20[(i-1)*9+2,4] <-length(whrecP)/M r20[(i-1)*9+3,4] <-length(whP)/M r20[(i-1)*9+4,4] <-length(whrecA)/M r20[(i-1)*9+5,4] <-length(whrecArecP)/M r20[(i-1)*9+6,4] <-length(whrecAP)/M r20[(i-1)*9+7,4] <-length(whA)/M r20[(i-1)*9+8,4] <-length(whArecP)/M r20[(i-1)*9+9,4] <-length(whAP)/M Fwv <-rep(NA,9)if (length(wh)>0) Fwv[1] <-extractRFS(as.matrix(Ev[wh,1:6]),5*year+s)if (length(whrecP)>0) Fwv[2] <-extractRFS(as.matrix(Ev[whrecP,1:6]),5*year+s)if (length(whP)>0) Fwv[3] <-extractRFS(as.matrix(Ev[whP,1:6]),5*year+s)if (length(whrecA)>0) Fwv[4] <-extractRFS(as.matrix(Ev[whrecA,1:6]),5*year+s)if (length(whrecArecP)>0) Fwv[5] <-extractRFS(as.matrix(Ev[whrecArecP,1:6]),5*year+s)if (length(whrecAP)>0) Fwv[6] <-extractRFS(as.matrix(Ev[whrecAP,1:6]),5*year+s)if (length(whA)>0) Fwv[7] <-extractRFS(as.matrix(Ev[whA,1:6]),5*year+s)if (length(whArecP)>0) Fwv[8] <-extractRFS(as.matrix(Ev[whArecP,1:6]),5*year+s)if (length(whAP)>0) Fwv[9] <-extractRFS(as.matrix(Ev[whAP,1:6]),5*year+s)# deb(Fwv) r20[(i-1)*9+(1:9),1] <- s r20[(i-1)*9+(1:9),2] <-1:9 r20[(i-1)*9+(1:9),3] <- Fwv}Ev <- Ev2040r2040 <-matrix(NA,909,5)r2040[,5] <-2sseq <-seq(0,year,length=101)nseq <-length(sseq)# This is to monitor progressm <-floor(log10(nseq)) +1pre <-rep("\b", 2* m +1)for (i in1:length(sseq)) {cat(pre, i, "/", nseq, sep =""); flush.console() s <- sseq[i]# deb(s, method="cat") wh <-which(Ev[,1]>s) whrecP <-which(Ev[,1]<=s & Ev[,1]>s-month & Ev[,2]==3& Ev[,3]>s) whP <-which(Ev[,1]<=s-month & Ev[,2]==3& Ev[,3]>s) whrecA <-which(Ev[,1]<=s & Ev[,1]>s-month & Ev[,2]==2& Ev[,3]>s) whrecArecP <-which(Ev[,1]<=s & Ev[,1]>s-month & Ev[,3]<=s & Ev[,3]>s-month & Ev[,2]>1& Ev[,4]>1& Ev[,5]>s) whrecAP <-which(Ev[,3]<=s & Ev[,3]>s-month & Ev[,1]<=s-month & Ev[,2]==3& Ev[,4]==2& Ev[,5]>s) whA <-which(Ev[,1]<=s-month & Ev[,2]==2& Ev[,3]>s) whArecP <-which(Ev[,3]<=s & Ev[,3]>s-month & Ev[,1]<=s-month & Ev[,2]==2& Ev[,4]==3& Ev[,5]>s) whAP <-which(Ev[,1]<=s-month & Ev[,3]<=s-month & Ev[,2]>1& Ev[,4]>1& Ev[,5]>s) whout <-which((Ev[,1]<=s & Ev[,2]==1) | (Ev[,3]<=s & Ev[,4]==1) | (Ev[,5]<=s & Ev[,6]==1)) Ev[,7] <-NAif (length(wh)>0) Ev[wh,7] <-1if (length(whrecP)>0) Ev[whrecP,7] <-2if (length(whP)>0) Ev[whP,7] <-3if (length(whrecA)>0) Ev[whrecA,7] <-4if (length(whrecArecP)>0) Ev[whrecArecP,7] <-5if (length(whrecAP)>0) Ev[whrecAP,7] <-6if (length(whA)>0) Ev[whA,7] <-7if (length(whArecP)>0) Ev[whArecP,7] <-8if (length(whAP)>0) Ev[whAP,7] <-9if (length(whout)>0) Ev[whout,7] <-0# deb(table(Ev[,7],exclude=NULL)) r2040[(i-1)*9+1,4] <-length(wh)/M r2040[(i-1)*9+2,4] <-length(whrecP)/M r2040[(i-1)*9+3,4] <-length(whP)/M r2040[(i-1)*9+4,4] <-length(whrecA)/M r2040[(i-1)*9+5,4] <-length(whrecArecP)/M r2040[(i-1)*9+6,4] <-length(whrecAP)/M r2040[(i-1)*9+7,4] <-length(whA)/M r2040[(i-1)*9+8,4] <-length(whArecP)/M r2040[(i-1)*9+9,4] <-length(whAP)/M Fwv <-rep(NA,9)if (length(wh)>0) Fwv[1] <-extractRFS(as.matrix(Ev[wh,1:6]),5*year+s)if (length(whrecP)>0) Fwv[2] <-extractRFS(as.matrix(Ev[whrecP,1:6]),5*year+s)if (length(whP)>0) Fwv[3] <-extractRFS(as.matrix(Ev[whP,1:6]),5*year+s)if (length(whrecA)>0) Fwv[4] <-extractRFS(as.matrix(Ev[whrecA,1:6]),5*year+s)if (length(whrecArecP)>0) Fwv[5] <-extractRFS(as.matrix(Ev[whrecArecP,1:6]),5*year+s)if (length(whrecAP)>0) Fwv[6] <-extractRFS(as.matrix(Ev[whrecAP,1:6]),5*year+s)if (length(whA)>0) Fwv[7] <-extractRFS(as.matrix(Ev[whA,1:6]),5*year+s)if (length(whArecP)>0) Fwv[8] <-extractRFS(as.matrix(Ev[whArecP,1:6]),5*year+s)if (length(whAP)>0) Fwv[9] <-extractRFS(as.matrix(Ev[whAP,1:6]),5*year+s)# deb(Fwv) r2040[(i-1)*9+(1:9),1] <- s r2040[(i-1)*9+(1:9),2] <-1:9 r2040[(i-1)*9+(1:9),3] <- Fwv}Ev <- Ev40r40 <-matrix(NA,909,5)r40[,5] <-3sseq <-seq(0,year,length=101)nseq <-length(sseq)# This is to monitor progressm <-floor(log10(nseq)) +1pre <-rep("\b", 2* m +1)for (i in1:length(sseq)) {cat(pre, i, "/", nseq, sep =""); flush.console() s <- sseq[i]# deb(s, method="cat") wh <-which(Ev[,1]>s) whrecP <-which(Ev[,1]<=s & Ev[,1]>s-month & Ev[,2]==3& Ev[,3]>s) whP <-which(Ev[,1]<=s-month & Ev[,2]==3& Ev[,3]>s) whrecA <-which(Ev[,1]<=s & Ev[,1]>s-month & Ev[,2]==2& Ev[,3]>s) whrecArecP <-which(Ev[,1]<=s & Ev[,1]>s-month & Ev[,3]<=s & Ev[,3]>s-month & Ev[,2]>1& Ev[,4]>1& Ev[,5]>s) whrecAP <-which(Ev[,3]<=s & Ev[,3]>s-month & Ev[,1]<=s-month & Ev[,2]==3& Ev[,4]==2& Ev[,5]>s) whA <-which(Ev[,1]<=s-month & Ev[,2]==2& Ev[,3]>s) whArecP <-which(Ev[,3]<=s & Ev[,3]>s-month & Ev[,1]<=s-month & Ev[,2]==2& Ev[,4]==3& Ev[,5]>s) whAP <-which(Ev[,1]<=s-month & Ev[,3]<=s-month & Ev[,2]>1& Ev[,4]>1& Ev[,5]>s) whout <-which((Ev[,1]<=s & Ev[,2]==1) | (Ev[,3]<=s & Ev[,4]==1) | (Ev[,5]<=s & Ev[,6]==1)) Ev[,7] <-NAif (length(wh)>0) Ev[wh,7] <-1if (length(whrecP)>0) Ev[whrecP,7] <-2if (length(whP)>0) Ev[whP,7] <-3if (length(whrecA)>0) Ev[whrecA,7] <-4if (length(whrecArecP)>0) Ev[whrecArecP,7] <-5if (length(whrecAP)>0) Ev[whrecAP,7] <-6if (length(whA)>0) Ev[whA,7] <-7if (length(whArecP)>0) Ev[whArecP,7] <-8if (length(whAP)>0) Ev[whAP,7] <-9if (length(whout)>0) Ev[whout,7] <-0# deb(table(Ev[,7],exclude=NULL)) r40[(i-1)*9+1,4] <-length(wh)/M r40[(i-1)*9+2,4] <-length(whrecP)/M r40[(i-1)*9+3,4] <-length(whP)/M r40[(i-1)*9+4,4] <-length(whrecA)/M r40[(i-1)*9+5,4] <-length(whrecArecP)/M r40[(i-1)*9+6,4] <-length(whrecAP)/M r40[(i-1)*9+7,4] <-length(whA)/M r40[(i-1)*9+8,4] <-length(whArecP)/M r40[(i-1)*9+9,4] <-length(whAP)/M Fwv <-rep(NA,9)if (length(wh)>0) Fwv[1] <-extractRFS(as.matrix(Ev[wh,1:6]),5*year+s)if (length(whrecP)>0) Fwv[2] <-extractRFS(as.matrix(Ev[whrecP,1:6]),5*year+s)if (length(whP)>0) Fwv[3] <-extractRFS(as.matrix(Ev[whP,1:6]),5*year+s)if (length(whrecA)>0) Fwv[4] <-extractRFS(as.matrix(Ev[whrecA,1:6]),5*year+s)if (length(whrecArecP)>0) Fwv[5] <-extractRFS(as.matrix(Ev[whrecArecP,1:6]),5*year+s)if (length(whrecAP)>0) Fwv[6] <-extractRFS(as.matrix(Ev[whrecAP,1:6]),5*year+s)if (length(whA)>0) Fwv[7] <-extractRFS(as.matrix(Ev[whA,1:6]),5*year+s)if (length(whArecP)>0) Fwv[8] <-extractRFS(as.matrix(Ev[whArecP,1:6]),5*year+s)if (length(whAP)>0) Fwv[9] <-extractRFS(as.matrix(Ev[whAP,1:6]),5*year+s)# deb(Fwv) r40[(i-1)*9+(1:9),1] <- s r40[(i-1)*9+(1:9),2] <-1:9 r40[(i-1)*9+(1:9),3] <- Fwv}r <-rbind(r20,r2040,r40)r <-as.data.frame(r)names(r) <-c("time","group","Fw","freq","age")# This is to manipulate awkward plotting order of lattice plotsr$A <-1r$A[r$group>3] <-2r$A[r$group>6] <-3r$P <-1r$P[r$group %in%c(2,5,8)] <-2r$P[r$group %in%c(3,6,9)] <-3r$AP <-3*(4-r$A) + r$Pr$AP <-factor(r$AP,labels=c("Past AGvHD, no PR","Past AGvHD, recent PR","Past AGvHD, past PR","Recent AGvHD, no PR","Recent AGvHD, recent PR","Recent AGvHD, past PR","No AGvHD, no PR","No AGvHD, recent PR","No AGvHD, past PR"))r$age <-factor(r$age,labels=c("Age <= 20","Age 20-40","Age > 40"))r$time <- r$time/yearrequire(lattice)key.age <-list(text =list(levels(r$age)),lines =list(lwd =2, lty =1:3, col ="black"))xyplot(Fw ~ time | AP, data=r, groups=age, ylim=c(0,1), lwd=2, type="l", col=1, lty=1:3,xlab="Prediction time (years)",ylab="Probability of relapse or death", key=key.age)key.age <-list(text =list(levels(r$age)),lines =list(lwd =2, lty =1:3, col ="black"))xyplot(freq ~ time | AP, data=r, groups=age, ylim=c(0,1), lwd=2, type="l", col=1, lty=1:3,xlab="Prediction time (years)",ylab="Probability of relapse or death", key=key.age)