The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.
This is the R example code from ‘Weighted Cox Regression Using the R Package coxphw’ by Dunkler, Ploner, Schemper and Heinze (Journal of Statistical Software, 2018, 84: 1-26, doi: 10.18637/jss.v084.i02). It works with R >=3.2.2 and coxphw package >=4.0.0.
#########################################################################################
## R code for
## Weighted Cox Regression using the R package coxphw
## written by Daniela Dunkler
#########################################################################################
## This R example code works with R >=3.4.2 and coxphw-package >=4.0.0.
## load R packages
library("coxphw")
## Lade nötiges Paket: survival
library("survival")
library("splines") # for splines::ns used in plotzph
pdfind <- FALSE # indicator, if plots should be saved as pdf
runSimulation <- FALSE # indicator, if simulation should be run
# Running the simulation is time-consuming.
#########################################################################################
## additional function for nice plots of scaled Schoenfeld residuals versus time
#########################################################################################
plotcoxzph <- function(x, resid = TRUE, se = TRUE, df = 4, nsmo = 40, var, wd = 1,
limits = NULL, ...)
{
## plot.cox.zph function from survival package 2.37-4 slightly adapted
xx <- x$x
yy <- x$y
d <- nrow(yy)
df <- max(df)
nvar <- ncol(yy)
pred.x <- seq(from = min(xx), to = max(xx), length = nsmo)
temp <- c(pred.x, xx)
lmat <- ns(temp, df = df, intercept = TRUE)
pmat <- lmat[1:nsmo, ]
xmat <- lmat[-(1:nsmo), ]
qmat <- qr(xmat)
if (qmat$rank < df)
stop("Spline fit is singular, try a smaller degrees of freedom")
if (se) {
bk <- backsolve(qmat$qr[1:df, 1:df], diag(df))
xtx <- bk %*% t(bk)
seval <- d*((pmat%*% xtx) *pmat) %*% rep(1, df)
}
ylab <- paste("Beta(t) for", dimnames(yy)[[2]])
if (missing(var)) var <- 1:nvar
else {
if (is.character(var)) var <- match(var, dimnames(yy)[[2]])
if (any(is.na(var)) || max(var)>nvar || min(var) <1)
stop("Invalid variable requested")
}
if (x$transform == "log") {
xx <- exp(xx)
pred.x <- exp(pred.x)
}
else if (x$transform != "identity") {
xtime <- as.numeric(dimnames(yy)[[1]])
indx <- !duplicated(xx)
apr1 <- approx(xx[indx], xtime[indx],
seq(min(xx), max(xx), length = 17)[2*(1:8)])
temp <- signif(apr1$y, 2)
apr2 <- approx(xtime[indx], xx[indx], temp)
xaxisval <- apr2$y
xaxislab <- rep("", 8)
for (i in 1:8) xaxislab[i] <- format(temp[i])
}
for (i in var) {
y <- yy[,i]
yhat <- pmat %*% qr.coef(qmat, y)
if (resid) yr <-range(yhat, y)
else yr <-range(yhat)
if (se) {
temp <- 2* sqrt(x$var[i,i] * seval)
yup <- yhat + temp
ylow<- yhat - temp
yr <- range(yr, yup, ylow)
}
if (is.null(limits)) { limits <- yr }
if (x$transform == "identity")
plot(range(xx), limits, type = "n", xlab = "", ylab = "", lwd = 2, las = 1, ...)
else if (x$transform == "log")
plot(range(xx), limits, type = "n", xlab = "", ylab = "", log = "x", ...)
else {
plot(range(xx), limits, type ="n", xlab = "", ylab = "", lwd = 2, axes = FALSE, ...)
axis(1, xaxisval, xaxislab)
axis(2, las = 1)
box()
}
if (resid) points(xx, y)
lines(pred.x, yhat, lwd = wd, ...)
if (se) {
lines(pred.x, yup,lty = 2)
lines(pred.x, ylow, lty = 2)
}
}
}
## id radiation time status
## 1 1 0 1 1
## 2 2 1 17 1
## 3 3 1 42 1
## 4 4 1 44 1
## 5 5 1 48 1
## 6 6 1 60 1
## [1] 90
## Call: survfit(formula = Surv(yrs, abs(1 - status)) ~ 1, data = gastric)
##
## n events median 0.95LCL 0.95UCL
## [1,] 90 11 4.34 4 NA
## gastric$status
## 0 1
## 11 79
## gastric$status
## 0 1
## 12.22 87.78
## gastric$status
## gastric$radiation 0 1 Sum
## 0 3 42 45
## 1 8 37 45
## Sum 11 79 90
## gastric$status
## gastric$radiation 0 1
## 0 6.67 93.33
## 1 17.78 82.22
## check assumption of proportional hazards
gsurv <- survfit(Surv(yrs, status) ~ radiation, data = gastric)
summary(gsurv)
## Call: survfit(formula = Surv(yrs, status) ~ radiation, data = gastric)
##
## radiation=0
## time n.risk n.event survival std.err lower 95% CI upper 95% CI
## 0.00274 45 1 0.9778 0.0220 0.9356 1.000
## 0.17248 44 1 0.9556 0.0307 0.8972 1.000
## 0.28747 43 1 0.9333 0.0372 0.8632 1.000
## 0.34223 42 1 0.9111 0.0424 0.8316 0.998
## 0.49829 41 1 0.8889 0.0468 0.8017 0.986
## 0.59138 40 1 0.8667 0.0507 0.7728 0.972
## 0.68446 39 1 0.8444 0.0540 0.7449 0.957
## 0.71732 38 1 0.8222 0.0570 0.7178 0.942
## 0.82409 37 2 0.7778 0.0620 0.6653 0.909
## 0.93634 35 1 0.7556 0.0641 0.6399 0.892
## 0.96920 34 1 0.7333 0.0659 0.6149 0.875
## 0.97467 33 1 0.7111 0.0676 0.5903 0.857
## 0.98015 32 1 0.6889 0.0690 0.5661 0.838
## 1.04038 31 1 0.6667 0.0703 0.5422 0.820
## 1.04860 30 2 0.6222 0.0723 0.4955 0.781
## 1.06229 28 1 0.6000 0.0730 0.4727 0.762
## 1.07871 27 1 0.5778 0.0736 0.4501 0.742
## 1.11704 26 1 0.5556 0.0741 0.4278 0.721
## 1.25941 25 1 0.5333 0.0744 0.4058 0.701
## 1.33881 24 1 0.5111 0.0745 0.3841 0.680
## 1.36619 23 1 0.4889 0.0745 0.3626 0.659
## 1.43190 22 1 0.4667 0.0744 0.3415 0.638
## 1.43463 21 1 0.4444 0.0741 0.3206 0.616
## 1.46475 20 1 0.4222 0.0736 0.3000 0.594
## 1.53867 19 1 0.4000 0.0730 0.2797 0.572
## 1.55784 18 1 0.3778 0.0723 0.2597 0.550
## 1.84805 17 1 0.3556 0.0714 0.2399 0.527
## 1.85079 16 1 0.3333 0.0703 0.2205 0.504
## 2.04791 15 1 0.3111 0.0690 0.2014 0.481
## 2.13005 14 1 0.2889 0.0676 0.1827 0.457
## 2.15195 13 1 0.2667 0.0659 0.1643 0.433
## 2.18207 12 1 0.2444 0.0641 0.1462 0.409
## 2.61465 11 1 0.2222 0.0620 0.1286 0.384
## 2.65024 10 1 0.2000 0.0596 0.1115 0.359
## 2.67488 9 1 0.1778 0.0570 0.0948 0.333
## 3.40862 8 1 0.1556 0.0540 0.0787 0.307
## 3.47981 7 1 0.1333 0.0507 0.0633 0.281
## 3.88775 6 1 0.1111 0.0468 0.0486 0.254
## 4.24641 3 1 0.0741 0.0435 0.0234 0.234
## 4.63792 1 1 0.0000 NaN NA NA
##
## radiation=1
## time n.risk n.event survival std.err lower 95% CI upper 95% CI
## 0.0465 45 1 0.978 0.0220 0.936 1.000
## 0.1150 44 1 0.956 0.0307 0.897 1.000
## 0.1205 43 1 0.933 0.0372 0.863 1.000
## 0.1314 42 1 0.911 0.0424 0.832 0.998
## 0.1643 41 1 0.889 0.0468 0.802 0.986
## 0.1971 40 1 0.867 0.0507 0.773 0.972
## 0.2026 39 1 0.844 0.0540 0.745 0.957
## 0.2601 38 1 0.822 0.0570 0.718 0.942
## 0.2820 37 1 0.800 0.0596 0.691 0.926
## 0.2957 36 1 0.778 0.0620 0.665 0.909
## 0.3340 35 1 0.756 0.0641 0.640 0.892
## 0.3943 34 1 0.733 0.0659 0.615 0.875
## 0.4572 33 1 0.711 0.0676 0.590 0.857
## 0.4654 32 1 0.689 0.0690 0.566 0.838
## 0.5010 31 1 0.667 0.0703 0.542 0.820
## 0.5065 30 1 0.644 0.0714 0.519 0.801
## 0.5284 29 1 0.622 0.0723 0.496 0.781
## 0.5339 28 1 0.600 0.0730 0.473 0.762
## 0.5394 27 1 0.578 0.0736 0.450 0.742
## 0.5695 26 1 0.556 0.0741 0.428 0.721
## 0.6407 25 1 0.533 0.0744 0.406 0.701
## 0.6434 24 1 0.511 0.0745 0.384 0.680
## 0.6954 23 1 0.489 0.0745 0.363 0.659
## 0.8405 22 1 0.467 0.0744 0.341 0.638
## 0.8624 21 1 0.444 0.0741 0.321 0.616
## 1.0979 20 1 0.422 0.0736 0.300 0.594
## 1.2183 19 1 0.400 0.0730 0.280 0.572
## 1.2704 18 1 0.378 0.0723 0.260 0.550
## 1.3251 17 1 0.356 0.0714 0.240 0.527
## 1.4456 16 1 0.333 0.0703 0.221 0.504
## 1.4839 15 1 0.311 0.0690 0.201 0.481
## 1.5524 14 1 0.289 0.0676 0.183 0.457
## 1.5797 13 1 0.267 0.0659 0.164 0.433
## 1.5880 12 1 0.244 0.0641 0.146 0.409
## 2.1766 11 1 0.222 0.0620 0.129 0.384
## 2.3409 10 1 0.200 0.0596 0.111 0.359
## 3.7399 6 1 0.167 0.0583 0.084 0.331
## plot of cumulative survival probabilities
if (pdfind) { pdf(file = "figure1A.pdf", width = 10.2, height = 5) }
par(oma = c(2, 2, 0.5, 0.5), mar = c(2, 2, 0, 0))
plot(gsurv, lty = 1:2, las = 1, lwd = 2)
mtext(side = 1, line = 2.5, text = "time (years)", cex = 1.2)
mtext(side = 2, line = 3, text = "survival distribution function", cex = 1.2)
legend("topright", title = "radiation", legend = c("no", "yes"),
lty = 1:2, inset = 0.05, bty = "n", cex = 1.4)
if (pdfind) { dev.off() }
## plots of scaled Schoenfeld residuals and test departure from proportional hazards
gfit1 <- coxph(Surv(yrs, status) ~ radiation + cluster(id), data = gastric, x = TRUE,
method = "breslow")
gfit1.ph <- cox.zph(fit = gfit1, transform = "km")
gfit1.ph
## chisq df p
## radiation 12.4 1 0.00042
## GLOBAL 12.4 1 0.00042
if (pdfind) { pdf(file = "figure1B.pdf", width = 5, height = 5) }
par(oma = c(2, 2, 0.5, 0.5), mar = c(2, 2, 0, 0))
plotcoxzph(x = gfit1.ph, wd = 2, limits = c(-3, 4.3))
abline(a = 0, b = 0, lty = 3)
mtext(side = 1, line = 2.5, cex = 1.2,
text = expression(paste("time (years, ", hat(F), "(t) transformation)")))
mtext(side = 2, line = 2.2, cex = 1.2,
text = expression(paste(hat(beta), "(t) for radiation")))
## add the linear fit
abline(lm(gfit1.ph$y ~ gfit1.ph$x)$coefficients, lty = 3, col = "red", lwd = 2)
if (pdfind) { dev.off() }
gfit1.ph2 <- cox.zph(fit = gfit1, transform = "identity")
if (pdfind) { pdf(file = "figure1C.pdf", width = 5.2, height = 5) }
par(oma = c(2, 2, 0.5, 0.5), mar = c(2, 2, 0, 2))
plotcoxzph(x = gfit1.ph2, wd = 2, limits = c(-3, 4.3))
mtext(side = 1, line = 2.5, text = "time (years)", cex = 1.2)
mtext(side = 2, line = 2.2, cex = 1.2,
text = expression(paste(hat(beta), "(t) for radiation")))
abline(a = 0, b = 0, lty = 3)
mtext(text = "radiation...", side = 4, line = 0.1, font = 3)
mtext(text = "protective", side = 4, line = 1, adj = 0, font = 3)
mtext(text = " harmful", side = 4, line = 1, adj = 1, font = 3)
if (pdfind) { dev.off() }
## ignore non-proportional hazards and apply a standard Cox proportional hazards model
summary(coxph(Surv(yrs, status) ~ radiation + cluster(id), data = gastric, x = TRUE,
method = "breslow"))
## Call:
## coxph(formula = Surv(yrs, status) ~ radiation, data = gastric,
## x = TRUE, method = "breslow", cluster = id)
##
## n= 90, number of events= 79
##
## coef exp(coef) se(coef) robust se z Pr(>|z|)
## radiation 0.1415 1.1520 0.2263 0.2292 0.617 0.537
##
## exp(coef) exp(-coef) lower .95 upper .95
## radiation 1.152 0.8681 0.7351 1.805
##
## Concordance= 0.565 (se = 0.031 )
## Likelihood ratio test= 0.39 on 1 df, p=0.5
## Wald test = 0.38 on 1 df, p=0.5
## Score (logrank) test = 0.39 on 1 df, p=0.5, Robust = 0.37 p=0.5
##
## (Note: the likelihood ratio and score tests assume independence of
## observations within a cluster, the Wald and robust score tests do not).
## ------------------------------------------
data("biofeedback", package = "coxphw")
head(biofeedback)
## id success thdur bfb theal log2heal
## 1 1 1 25 0 17 4.08746
## 2 2 1 5 1 20 4.32193
## 3 3 0 53 0 81 6.33985
## 4 4 0 100 1 135 7.07682
## 5 5 0 30 0 730 9.51175
## 6 6 1 89 0 15 3.90689
## [1] 33
## biofeedback$bfb
## 0 1
## 14 19
## biofeedback$bfb
## 0 1
## 42.42 57.58
## follow-up/observation time
## survfit(Surv(thdur, abs(1-success)) ~ 1, data = biofeedback)
survfit(Surv(thdur, success) ~ 1, data = biofeedback)
## Call: survfit(formula = Surv(thdur, success) ~ 1, data = biofeedback)
##
## n events median 0.95LCL 0.95UCL
## [1,] 33 23 25 21 89
## biofeedback$success
## biofeedback$bfb 0 1 Sum
## 0 4 10 14
## 1 6 13 19
## Sum 10 23 33
## biofeedback$success
## biofeedback$bfb 0 1
## 0 28.57 71.43
## 1 31.58 68.42
## hist(biofeedback$theal)
## hist(biofeedback$log2heal)
## Kaplan-Meier analysis
bsurv <- survfit(Surv(thdur, success) ~ bfb, data = biofeedback)
summary(bsurv)
## Call: survfit(formula = Surv(thdur, success) ~ bfb, data = biofeedback)
##
## bfb=0
## time n.risk n.event survival std.err lower 95% CI upper 95% CI
## 9 14 1 0.929 0.0688 0.8030 1.000
## 18 13 1 0.857 0.0935 0.6921 1.000
## 24 12 1 0.786 0.1097 0.5977 1.000
## 25 11 2 0.643 0.1281 0.4351 0.950
## 32 8 1 0.562 0.1349 0.3515 0.900
## 58 6 1 0.469 0.1413 0.2596 0.846
## 84 5 1 0.375 0.1407 0.1797 0.783
## 85 4 1 0.281 0.1332 0.1112 0.711
## 89 3 1 0.188 0.1172 0.0551 0.639
##
## bfb=1
## time n.risk n.event survival std.err lower 95% CI upper 95% CI
## 5 19 1 0.947 0.0512 0.852 1.000
## 7 18 1 0.895 0.0704 0.767 1.000
## 11 17 1 0.842 0.0837 0.693 1.000
## 13 16 1 0.789 0.0935 0.626 0.996
## 14 15 2 0.684 0.1066 0.504 0.929
## 15 13 1 0.632 0.1107 0.448 0.890
## 17 12 1 0.579 0.1133 0.395 0.850
## 20 11 1 0.526 0.1145 0.344 0.806
## 21 10 1 0.474 0.1145 0.295 0.761
## 22 9 1 0.421 0.1133 0.249 0.713
## 23 8 1 0.368 0.1107 0.204 0.664
## 33 6 1 0.307 0.1079 0.154 0.611
if (pdfind) { pdf(file = "figure2A.pdf", width = 10, height = 5) }
par(oma =c(2, 2, 0.5, 0.5), mar = c(2, 2, 0, 0))
plot(bsurv, fun = "event", lty = 1:2, lwd = 2, las = 1, ylim = c(0, 1))
mtext(side = 1, line = 2.5, text = "duration of therapy (days)", cex = 1.2)
mtext(side = 2, line = 3, text = "cumulative propability of rehabilitation", cex = 1.2)
legend("topleft", title = "biofeedback (bfb)", legend = c("no", "yes"), lty = 1:2,
inset = 0.05, bty = "n", cex = 1.4)
if (pdfind) { dev.off() }
bfit1 <- coxph(Surv(thdur, success) ~ bfb + log2heal + cluster(id), data = biofeedback,
x = TRUE, method = "breslow")
summary(bfit1)
## Call:
## coxph(formula = Surv(thdur, success) ~ bfb + log2heal, data = biofeedback,
## x = TRUE, method = "breslow", cluster = id)
##
## n= 33, number of events= 23
##
## coef exp(coef) se(coef) robust se z Pr(>|z|)
## bfb 0.2700 1.3099 0.4273 0.3453 0.782 0.434
## log2heal -0.5267 0.5906 0.2543 0.3636 -1.448 0.148
##
## exp(coef) exp(-coef) lower .95 upper .95
## bfb 1.3099 0.7634 0.6658 2.577
## log2heal 0.5906 1.6933 0.2896 1.205
##
## Concordance= 0.665 (se = 0.061 )
## Likelihood ratio test= 7.19 on 2 df, p=0.03
## Wald test = 2.66 on 2 df, p=0.3
## Score (logrank) test = 5.16 on 2 df, p=0.08, Robust = 4.72 p=0.09
##
## (Note: the likelihood ratio and score tests assume independence of
## observations within a cluster, the Wald and robust score tests do not).
## chisq df p
## bfb 7.44 1 0.0064
## log2heal 4.29 1 0.0384
## GLOBAL 11.10 2 0.0039
if (pdfind) { pdf(file = "figure2B.pdf", width = 5, height = 5) }
par(oma = c(2, 2, 0.5, 0.5), mar = c(2, 2, 0, 0))
plotcoxzph(x = bfit1.ph[1], wd = 2)
mtext(side = 1, line = 2.5, text = "duration of therapy (days)", cex = 1.2)
mtext(side = 2, line = 2.2, text = expression(hat(beta)), cex = 1.2)
abline(a = 0, b = 0, lty = 3)
abline(lm(bfit1.ph$y[, 1] ~ bfit1.ph$x)$coefficients, lty = 3, col = "red", lwd = 2)
legend("bottomleft", legend = "bfb", bty = "n", inset = 0.08, cex = 1.5)
if (pdfind) { dev.off() }
if (pdfind) { pdf(file = "figure2C.pdf", width = 5, height = 5) }
par(oma = c(2, 2, 0.5, 0.5), mar = c(2, 2, 0, 0))
plotcoxzph(x = bfit1.ph[2], wd = 2, limits = c(-4.5, 4))
mtext(side = 1, line = 2.5, text = "duration of therapy (days)", cex = 1.2)
mtext(side = 2, line = 2.2, text = expression(hat(beta)), cex = 1.2)
abline(a = 0, b = 0, lty = 3)
abline(lm(bfit1.ph$y[, 2] ~ bfit1.ph$x)$coefficients, lty = 3, col = "red", lwd = 2)
legend("topright", legend = "log2heal", bty = "n", inset = 0.08, cex = 1.5)
simulation <- function(n1 = 100, n2 = 100, sim = 10, seed = 123,
type = c("ph", "nph1", "nph2", "nph3"), scalewei = NULL,
shapewei = NULL, beta = NULL, scaleexp = NULL, shapewei2 = NULL,
scalewei2 = NULL, shapegom = NULL, scalegom = NULL, scaleexpC,
admincens, npop = 10000, xmaxplot = NULL, addconstant = 1e-4)
{
## Simulate time-to-event data (following either an expoential, Weibuill or Gompertz
## distribution) with one binary explanatory variable, generate six versions of
## each simulated data set with differnt censoring patterns (no censoring, administrative
## censoring and loss-to-follow-up) and analyse these data sets with Cox regression
## and weighted Cox regression. Population-c is computed, as well.
##
## sim: number of simulations, 0 only population c is computed and plot is generated.
##
## type = "ph" : Weibull distributed distributions, proportional hazards
## "nph1" : exponential and Weibull distribution, non-proportional hazards
## "nph2" : exponential and Weibull distribution, non-proportional hazards
## "nph3" : exponential and Gompertz distribution, non-proportional hazards
##
## "ph" requires scalewei, shapewei and beta
## "nph1" requires scalewei, shapewei and scaleexp
## "nph2" requires scalewei, shapewei, scalewei2 and shapewei2
## "nph3" requires scaleexp, scalegom and shapegom
##
## scaleexpC and admincens: parameters for loss-to-follow-up and adminitrative censoring
##
## add.constant : this number will be added to all times to prevent survival times of
## exactly 0.
type <- match.arg(type)
if (type == "ph") {
stopifnot(!is.null(scalewei),!is.null(shapewei),!is.null(beta))
} else if (type == "nph1") {
stopifnot(!is.null(scalewei),!is.null(shapewei),!is.null(scaleexp))
} else if (type == "nph2") {
stopifnot(!is.null(scalewei),!is.null(shapewei),!is.null(scalewei2),!is.null(shapewei2))
} else if (type == "nph3") {
stopifnot(!is.null(scaleexp),!is.null(scalegom),!is.null(shapegom))
}
set.seed(seed)
## 1) compute population c
if (type != "ph") {
if (type == "nph1") {
integrandA <- function(x) { (scalewei * exp(-scalewei * x)) *
exp(-scalewei * x ^ scalewei) }
} else if (type == "nph2") {
integrandA <- function(x) { (scalewei2 * shapewei2 * x ^ (shapewei2 - 1) *
exp(-scalewei2 * x ^ shapewei2)) * exp(-scalewei *
x ^ shapewei) }
} else if (type == "nph3") {
integrandA <- function(x) { scaleexp * exp(-scaleexp * x) *
exp(scalegom / shapegom * (1 - exp(shapegom * x))) }
}
popc100 <- rep(c(integrate(integrandA, lower = 0, upper = Inf)$value,
integrate(integrandA, lower = 0, upper = admincens[1])$value,
integrate(integrandA, lower = 0, upper = admincens[2])$value) * 100,
each = 2)
} else { popc100 <- rep(exp(beta) / (1+exp(beta)), 6) * 100 }
if (sim == 0) { output <- list(results = NA, olist = NA, popc100 = popc100) }
## 2) Kaplan-Meier plot of scenario
xpop <- c(rep(0, npop / 2), rep(1, npop / 2))
u <- runif(n = npop, min = 0, max = 1)
if (type == "ph") {
time1pop <- (-log(u[1:(npop / 2)]) / (scalewei * exp(beta * 0))) ^ (1 / shapewei)
time2pop <- (-log(u[((npop / 2) + 1):npop]) / (scalewei * exp(beta * 1))) ^ (1 / shapewei)
} else if (type == "nph1") {
time1pop <- ((-log(u[1:(npop / 2)])) / scalewei) ^ (1 / shapewei)
time2pop <- -log(u[((npop / 2) + 1):npop]) / scaleexp
} else if (type == "nph2") {
time1pop <- ((-log(u[1:(npop / 2)])) / scalewei) ^ (1 / shapewei)
time2pop <- ((-log(u[((npop / 2) + 1):npop])) / scalewei2) ^ (1 / shapewei2)
} else if (type == "nph3") {
time1pop <- 1 / shapegom * log(1 - (shapegom * log(u[1:(npop / 2)])) / scalegom)
time2pop <- -log(u[((npop / 2) + 1):npop]) / scaleexp
}
time1pop <- time1pop + addconstant
time2pop <- time2pop + addconstant
datapop <- data.frame(cbind(time = c(time1pop, time2pop), event = 1, x = xpop))
fitpop <- coxph(Surv(time, event) ~ x, data = datapop)
if (is.null(xmaxplot)) { xmaxplot <- max(datapop$time) }
par(oma = c(2, 2, 0.5, 0.5), mar = c(2, 2, 0, 0))
plot(survfit(Surv(time, event) ~ x, data = datapop), lty = 1:2, lwd = 2,
las = 1, xlim = c(0, xmaxplot))
abline(v = admincens, col = "gray", lty = 2)
mtext(side = 1, line = 2.5, text = "time", cex = 1.2)
mtext(side = 2, line = 3, text = "survival distribution function",
cex = 1.2)
mtext(side = 3, line = -3, cex = 1.2, font = 2,
text = if (type == "ph") { "proportional hazards scenario" } else {
"non-proportional\nhazards scenario" } )
## 3) simulate data sets and analyse them
if (sim != 0) {
n <- n1 + n2
out <- data.frame(matrix(NA, nrow = sim, ncol = 7, dimnames = list(1:(sim),
c("cens", "cox_beta", "cox_c100", "wcox_beta", "wcox_c100",
"wilcox100", "prt0st1"))))
olist <- list(out = out, outC = out, out1 = out, outC1 = out, out2 = out, outC2 = out)
x <- c(rep(0, n1), rep(1, n2))
for (i in 1:sim) {
cat(paste(".", sep = ""))
## simulate data without censoring (data), type 1
u <- runif(n = n, min = 0, max = 1)
if (type == "ph") {
time1 <- (-log(u[1:n1]) / (scalewei * exp(beta * 0))) ^ (1 / shapewei)
time2 <- (-log(u[(n1 + 1):n]) / (scalewei * exp(beta * 1))) ^ (1 / shapewei)
} else if (type == "nph1") {
time1 <- ((-log(u[1:n1])) / scalewei) ^ (1 / shapewei)
time2 <- -log(u[(n1 + 1):n]) / scaleexp
} else if (type == "nph2") {
time1 <- ((-log(u[1:n1])) / scalewei) ^ (1 / shapewei)
time2 <- ((-log(u[(n1 + 1):n])) / scalewei2) ^ (1 / shapewei2)
} else if (type == "nph3") {
time1 <- 1 / shapegom * log(1 - (shapegom * log(u[1:n1])) / scalegom)
time2 <- -log(u[(n1 + 1):n]) / scaleexp
}
time1 <- time1 + addconstant
time2 <- time2 + addconstant
data <- data.frame(cbind(time = c(time1, time2), event = 1, x = x))
fit1 <- coxph(Surv(time, event) ~ x, data = data)
fit2 <-
coxphw(Surv(time, event) ~ x, data = data)
fit1zph <- cox.zph(fit = fit1, transform = "km")
eg <- expand.grid(time1, time2)
olist$out[i, ] <- c(
0,
fit1$coefficients, concord(fit1)[1],
fit2$coefficients, concord(fit2)[1],
wilcox.test(time ~ x, data = data, correct = FALSE)$statistic /
(n1 * n2),
1 - (sum(eg[, 1] < eg[, 2]) / nrow(eg)))
## follow-up distribution
timecens <- (-log(runif(n = nrow(data), min = 0, max = 1)) / scaleexpC) + addconstant
## data with censoring (dataC), type 2
dataC <- data
dataC$time[data$time > timecens] <- timecens[data$time > timecens]
dataC$event[data$time > timecens] <- 0
censC <- sum(dataC$event == 0) / n * 100
fit1C <- coxph(Surv(time, event) ~ x, data = dataC)
fit2C <- coxphw(Surv(time, event) ~ x, data = dataC)
dataC$id <- 1:nrow(dataC)
wilcoxC <- wilcox.test(time ~ x, data = dataC, correct = FALSE)$statistic
egC <- expand.grid(dataC$event[dataC$x == 0], dataC$event[dataC$x == 1])
olist$outC[i, ] <- c(censC,
fit1C$coefficients, concord(fit1C)[1],
fit2C$coefficients, concord(fit2C)[1],
wilcoxC / (length(dataC$x[dataC$x == 0]) *
length(dataC$x[dataC$x == 1])),
NA)
## data with administrative censoring 1 (data1), type 3
data1 <- data
data1$event[data$time > admincens[1]] <- 0
data1$time[data$time > admincens[1]] <- admincens[1]
cens1 <- sum(data1$event == 0) / n * 100
fit11 <- coxph(Surv(time, event) ~ x, data = data1)
fit21 <- coxphw(Surv(time, event) ~ x, data = data1)
fit11zph <- cox.zph(fit = fit11, transform = "km")
eg1 <- eg[!(eg[, 1] >= admincens[1] & eg[, 2] >= admincens[1]), ]
wilcox1 <- wilcox.test(time ~ x, data = data1, correct = FALSE)$statistic
olist$out1[i, ] <- c(cens1,
fit11$coefficients, concord(fit11)[1],
fit21$coefficients, concord(fit21)[1],
wilcox1 / (n1 * n2),
1 - ((sum(eg1[, 1] < eg1[, 2]) +
sum(eg[, 1] >= admincens[1] &
eg[, 2] >= admincens[1]) / 2) / nrow(eg)))
## data1 with censoring (datacens1), type 4
dataC1 <- data1
dataC1$time[data1$time > timecens] <- timecens[data1$time > timecens]
dataC1$event[data1$time > timecens] <- 0
censC1 <- sum(dataC1$event == 0) / n * 100
fit1C1 <- coxph(Surv(time, event) ~ x, data = dataC1)
fit2C1 <- coxphw(Surv(time, event) ~ x, data = dataC1)
wilcoxC1 <- wilcox.test(time ~ x, data = dataC1, correct = FALSE)$statistic
egC1 <- expand.grid(dataC1$event[dataC1$x == 0], dataC1$event[dataC1$x == 1])
olist$outC1[i, ] <- c(censC1,
fit1C1$coefficients, concord(fit1C1)[1],
fit2C1$coefficients, concord(fit2C1)[1],
wilcoxC1 / (length(dataC1$x[dataC1$x == 0]) *
length(dataC1$x[dataC1$x == 1])),
NA)
## data with administrative censoring 2 (data2), type 5
data2 <- data
data2$event[data$time > admincens[2]] <- 0
data2$time[data$time > admincens[2]] <- admincens[2]
cens2 <- sum(data2$event == 0) / n * 100
fit12 <- coxph(Surv(time, event) ~ x, data = data2)
fit22 <- coxphw(Surv(time, event) ~ x, data = data2)
fit12zph <- cox.zph(fit = fit12, transform = "km")
eg2 <- eg[!(eg[, 1] >= admincens[2] & eg[, 2] >= admincens[2]), ]
wilcox2 <- wilcox.test(time ~ x, data = data2, correct = FALSE)$statistic
olist$out2[i, ] <- c(cens2,
fit12$coefficients, concord(fit12)[1],
fit22$coefficients, concord(fit22)[1],
wilcox2 / (n1 * n2),
1 - ((sum(eg2[, 1] < eg2[, 2]) +
sum(eg[, 1] >= admincens[2] &
eg[, 2] >= admincens[2]) / 2) / nrow(eg)))
## data2 with censoring (datacens2), type 6
dataC2 <- data2
dataC2$time[data2$time > timecens] <- timecens[data2$time > timecens]
dataC2$event[data2$time > timecens] <- 0
censC2 <- sum(dataC2$event == 0) / n * 100
fit1C2 <- coxph(Surv(time, event) ~ x, data = dataC2)
fit2C2 <- coxphw(Surv(time, event) ~ x, data = dataC2)
wilcoxC2 <- wilcox.test(time ~ x, data = dataC2, correct = FALSE)$statistic
egC2 <- expand.grid(dataC2$event[dataC2$x == 0], dataC2$event[dataC2$x == 1])
olist$outC2[i, ] <- c(censC2,
fit1C2$coefficients, concord(fit1C2)[1],
fit2C2$coefficients, concord(fit2C2)[1],
wilcoxC2 / (length(dataC2$x[dataC2$x == 0]) *
length(dataC2$x[dataC2$x == 1])),
NA)
}
results <- matrix(NA, nrow = 6, ncol = 7, dimnames = list(c("No", "Loss-to-fup",
"Admin. 1", "Loss-to-fup & admin. 1", "Admin. 2", "Loss-to-fup & admin. 2"),
colnames(olist$out)))
for (j in 1:6) {
olist[[j]][, c("cox_c100", "wcox_c100", "wilcox100", "prt0st1")] <-
olist[[j]][, c("cox_c100", "wcox_c100", "wilcox100", "prt0st1")] * 100
r1 <- round(apply(olist[[j]], 2, mean), 3)
r2 <- round(apply(olist[[j]], 2, sd) / sqrt(sim), 3)
results[j, ] <- t(paste(r1, " (", r2, ")", sep = ""))
}
output <- list(results = results, olist = olist, popc100 = popc100)
}
invisible(output)
}
## Section 5. Simulation
if (runSimulation) {
## Figure 3 and Table 1
if (pdfind) { pdf("simph.pdf", width = 5, height = 5) }
sim1 <- simulation(n1 = 1000, n2 = 1000, sim = 2000, seed = 3460, type = "ph",
scalewei = 0.11, shapewei = 1.22, scaleexpC =0.06029,
beta = log(0.55/(1-0.55)), admincens = c(11.21083, 9.549136),
npop = 10000, xmaxplot = 23, addconstant = 1e-4)
if (pdfind) { dev.off() }
print(sim1$results[, 1:6])
print(round(sim1$popc100[1], 2)) # true population-c * 100
if (pdfind) { pdf("simnph.pdf", width = 5, height = 5) }
sim2 <- simulation(n1 = 1000, n2 = 1000, sim = 2000, seed = 3458, type ="nph3",
scaleexp = 0.35653, shapegom = 1.6, scalegom = 0.0228,
scaleexpC = 0.122, admincens = c(4.506223, 3.535000),
npop = 10000, xmaxplot = 6)
if (pdfind) { dev.off() }
print(sim2$results[, 1:6])
print(round(sim2$popc[1], 2)) # true population-c * 100
}
## prepare Table 2
models <- c("Ignoring non-proportional hazards *", "HR Cox regression",
"Estimating piecewise constant HRs *", "HR 1st year", "HR >1st year",
"Including a time-by-covariate interaction", "HR at 0.5 years", "HR at 1 year",
"HR at 2 years", "Weighted Cox regression", "average HR", "c'%")
Table2 <- data.frame(matrix(NA, nrow = length(models), ncol = 4, dimnames = list(models,
c("HR", "HRlower", "HRupper", "p"))))
## ignore non-proportional hazards and apply a Cox proportional hazards model
gfit2 <- coxphw(Surv(yrs, status) ~ radiation, data = gastric, template = "PH",
robust = TRUE)
## or equivalently
coxph(Surv(yrs, status) ~ radiation + cluster(id), data = gastric, x = TRUE,
method = "breslow")
## Call:
## coxph(formula = Surv(yrs, status) ~ radiation, data = gastric,
## x = TRUE, method = "breslow", cluster = id)
##
## coef exp(coef) se(coef) robust se z p
## radiation 0.1415 1.1520 0.2263 0.2292 0.617 0.537
##
## Likelihood ratio test=0.39 on 1 df, p=0.5325
## n= 90, number of events= 79
## extract estimates for Table 1: HR, 95% CI, p-value
Table2["HR Cox regression", ] <- c(exp(gfit2$coeff),
exp(confint(gfit2)),
summary(gfit2)$prob)
## coxphw(formula = Surv(yrs, status) ~ radiation, data = gastric,
## template = "PH", robust = TRUE)
##
## Model fitted by unweighted estimation (PH template)
##
## coef se(coef) exp(coef) lower 0.95 upper 0.95 z
## radiation 0.141495 0.2292141 1.151995 0.7350944 1.805335 0.6173052
## p
## radiation 0.5370334
##
## Wald Chi-square = 0.3810657 on 1 df p = 0.5370334 n = 90
##
## Covariance-Matrix:
## radiation
## radiation 0.05253909
##
## Generalized concordance probability: Estimates may be biased!
## concordance prob. lower 0.95 upper 0.95
## radiation 0.5353 0.4237 0.6435
## estimating piecewise constant hazard ratios (by two separate Cox models)
## (two time periods with equal number of events)
table(gastric$status)
##
## 0 1
## 11 79
## [1] 39
## first time period
gastricp1 <- gastric
gastricp1$status[gastricp1$yrs > 1] <- 0
gastricp1$yrs[gastricp1$yrs > 1] <- 1
nrow(gastricp1)
## [1] 90
## gastricp1$status
## 0 1
## 51 39
## gastricp1$status
## 0 1
## 56.67 43.33
## gastricp1$status
## gastricp1$radiation 0 1 Sum
## 0 31 14 45
## 1 20 25 45
## Sum 51 39 90
## gastricp1$status
## gastricp1$radiation 0 1
## 0 68.89 31.11
## 1 44.44 55.56
gfit3 <- coxph(Surv(yrs, status) ~ radiation + cluster(id), data = gastricp1,
x = TRUE, method = "breslow")
gfit3.ph <- cox.zph(fit = gfit3, transform = "km")
gfit3.ph$table
## chisq df p
## radiation 2.836058 1 0.09217006
## GLOBAL 2.836058 1 0.09217006
## plot of scaled Schoenfeld residuals in the first time period
par(oma = c(2, 2, 0.5, 0.5), mar = c(2, 2, 0, 0))
plotcoxzph(x = gfit3.ph, wd = 2)
abline(a = 0, b = 0, lty = 3)
mtext(side = 1, line = 2.5, text = "time (years, KM-transformation)", cex = 1)
mtext(side = 2, line = 2.5, text = expression(paste(beta, "(t) for radiation")), cex = 1)
abline(lm(gfit3.ph$y ~ gfit3.ph$x)$coefficients, lty = 3, col = "red", lwd = 2)
## plot of cumulative survival probabilities
## gsurv2 <- survfit(Surv(yrs, status) ~ radiation, data = gastricp1)
## par(oma = c(2, 2, 0.5, 0.5), mar = c(2, 2, 0, 0))
## plot(gsurv2, lty = 1:2, las = 1, lwd = 2)
## mtext(side = 1, line = 2.5, text = "time (years)")
## mtext(side = 2, line = 3, text = "survival distribution function")
## legend("bottomleft", title = "radiation", legend = c("yes", "no"),
## lty = 2:1, inset = 0.02, bty = "n", cex = 1.2)
## Cox proportional hazards model for the first time period
gfit4 <- coxphw(Surv(yrs, status) ~ radiation, data = gastricp1, template = "PH")
summary(gfit4)
## coxphw(formula = Surv(yrs, status) ~ radiation, data = gastricp1,
## template = "PH")
##
## Model fitted by unweighted estimation (PH template)
##
## coef se(coef) exp(coef) lower 0.95 upper 0.95 z
## radiation 0.8774141 0.325826 2.404673 1.269733 4.55407 2.692892
## p
## radiation 0.007083531
##
## Wald Chi-square = 7.251665 on 1 df p = 0.007083531 n = 90
##
## Covariance-Matrix:
## radiation
## radiation 0.1061626
##
## Generalized concordance probability: Estimates may be biased!
## concordance prob. lower 0.95 upper 0.95
## radiation 0.7063 0.5594 0.82
Table2["HR 1st year", ] <- c(exp(gfit4$coeff),
exp(confint(gfit4)),
summary(gfit4, print = FALSE)$prob)
## or equivalently
## coxph(Surv(yrs, status) ~ radiation + cluster(id), data = gastricp1, method = "breslow")
## second time period
gastricp2 <- subset(gastric, yrs > 1)
nrow(gastricp2)
## [1] 51
## gastricp2$status
## 0 1
## 11 40
## gastricp2$status
## 0 1
## 21.57 78.43
## gastricp2$status
## gastricp2$radiation 0 1 Sum
## 0 3 28 31
## 1 8 12 20
## Sum 11 40 51
## gastricp2$status
## gastricp2$radiation 0 1
## 0 9.68 90.32
## 1 40.00 60.00
gfit5 <- coxph(Surv(yrs, status) ~ radiation + cluster(id), data = gastricp2, x = TRUE,
method = "breslow")
gfit5.ph <- cox.zph(fit = gfit5, transform = "km")
gfit5.ph$table
## chisq df p
## radiation 0.5706304 1 0.4500085
## GLOBAL 0.5706304 1 0.4500085
## plot of scaled Schoenfeld residuals for the second time period
par(oma = c(2, 2, 0.5, 0.5), mar = c(2, 2, 0, 0))
plotcoxzph(x = gfit5.ph, wd = 2)
abline(a = 0, b = 0, lty = 3)
mtext(side = 1, line = 2.5, text = "time (years, KM-transformation)", cex = 1)
mtext(side = 2, line = 2.5, text = expression(paste(beta, "(t) for radiation")), cex = 1)
abline(lm(gfit5.ph$y ~ gfit5.ph$x)$coefficients, lty = 3, col = "red", lwd = 2)
## plot of cumulative survival probabilities
## gsurv3 <- survfit(Surv(yrs, status) ~ radiation, data = gastricp2)
## par(oma = c(2, 2, 0.5, 0.5), mar = c(2, 2, 0, 0))
## plot(gsurv3, lty = 1:2, las = 1, lwd = 2, xlim=c(1,5))
## mtext(side = 1, line = 2.5, text = "time (years)")
## mtext(side = 2, line = 3, text = "survival distribution function")
## legend("bottomleft", title = "radiation", legend = c("yes", "no"),
## lty = 2:1, inset = 0.02, bty = "n", cex = 1.2)
## Cox proportional hazards model for the second time period
gfit6 <- coxphw(Surv(yrs, status) ~ radiation, data = gastricp2, template = "PH")
summary(gfit6)
## coxphw(formula = Surv(yrs, status) ~ radiation, data = gastricp2,
## template = "PH")
##
## Model fitted by unweighted estimation (PH template)
##
## coef se(coef) exp(coef) lower 0.95 upper 0.95 z
## radiation -0.6051688 0.3471071 0.5459823 0.2765161 1.078044 -1.743464
## p
## radiation 0.08125255
##
## Wald Chi-square = 3.039668 on 1 df p = 0.08125255 n = 51
##
## Covariance-Matrix:
## radiation
## radiation 0.1204833
##
## Generalized concordance probability: Estimates may be biased!
## concordance prob. lower 0.95 upper 0.95
## radiation 0.3532 0.2166 0.5188
Table2["HR >1st year", ] <- c(exp(gfit6$coeff),
exp(confint(gfit6)),
summary(gfit6, print = FALSE)$prob)
## or equivalently
## coxph(Surv(yrs, status) ~ radiation + cluster(id), data = gastricp2, method = "breslow")
## including a time-by-covariate interaction
fun <- function(t) as.numeric(t > 1)
gfit7 <- coxphw(Surv(yrs, status) ~ radiation + fun(yrs):radiation, data = gastric, template = "PH")
summary(gfit7)
## coxphw(formula = Surv(yrs, status) ~ radiation + fun(yrs):radiation,
## data = gastric, template = "PH")
##
## Model fitted by unweighted estimation (PH template)
##
## coef se(coef) exp(coef) lower 0.95 upper 0.95
## radiation 0.8774141 0.3258260 2.4046734 1.26973327 4.5540699
## fun(yrs):radiation -1.4825829 0.4758515 0.2270505 0.08934636 0.5769896
## z p
## radiation 2.692892 0.007083531
## fun(yrs):radiation -3.115642 0.001835452
##
## Wald Chi-square = 10.30011 on 2 df p = 0.005799087 n = 90
##
## Covariance-Matrix:
## radiation fun(yrs):radiation
## radiation 0.1061626 -0.1060570
## fun(yrs):radiation -0.1060570 0.2264347
##
## Generalized concordance probability: Estimates may be biased!
## concordance prob. lower 0.95 upper 0.95
## radiation 0.7063 0.5594 0.8200
## fun(yrs):radiation 0.1850 0.0820 0.3659
## 2.4046734 * 0.2270505
## exp(0.8774141 - 1.4825829)
## or equivalently
summary(coxph(Surv(yrs, status) ~ radiation + tt(radiation) + cluster(id), data = gastric,
tt = function(x, t, ...) x * (t > 1), method = "breslow"))
## Call:
## coxph(formula = Surv(yrs, status) ~ radiation + tt(radiation),
## data = gastric, tt = function(x, t, ...) x * (t > 1), method = "breslow",
## cluster = id)
##
## n= 90, number of events= 79
##
## coef exp(coef) se(coef) robust se z Pr(>|z|)
## radiation 0.8774 2.4047 0.3351 0.3258 2.693 0.00708 **
## tt(radiation) -1.4826 0.2271 0.4816 0.4759 -3.116 0.00184 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## exp(coef) exp(-coef) lower .95 upper .95
## radiation 2.4047 0.4159 1.26973 4.554
## tt(radiation) 0.2271 4.4043 0.08935 0.577
##
## Concordance= 0.6 (se = 0.029 )
## Likelihood ratio test= 10.49 on 2 df, p=0.005
## Wald test = 10.3 on 2 df, p=0.006
## Score (logrank) test = 10.45 on 2 df, p=0.005, Robust = 10.73 p=0.005
##
## (Note: the likelihood ratio and score tests assume independence of
## observations within a cluster, the Wald and robust score tests do not).
## extended Cox model - assume a linear time-dependent effect
fit1 <- coxphw(Surv(yrs, status) ~ radiation + yrs:radiation, data = gastric, template = "PH")
summary(fit1)
## coxphw(formula = Surv(yrs, status) ~ radiation + yrs:radiation,
## data = gastric, template = "PH")
##
## Model fitted by unweighted estimation (PH template)
##
## coef se(coef) exp(coef) lower 0.95 upper 0.95 z
## radiation 1.2699606 0.4334889 3.5607124 1.5224762 8.3276657 2.929627
## yrs:radiation -0.9652886 0.3409321 0.3808733 0.1952444 0.7429892 -2.831322
## p
## radiation 0.003393692
## yrs:radiation 0.004635608
##
## Wald Chi-square = 9.047941 on 2 df p = 0.01084588 n = 90
##
## Covariance-Matrix:
## radiation yrs:radiation
## radiation 0.1879126 -0.1241715
## yrs:radiation -0.1241715 0.1162347
##
## Generalized concordance probability: Estimates may be biased!
## concordance prob. lower 0.95 upper 0.95
## radiation 0.7807 0.6036 0.8928
## yrs:radiation 0.2758 0.1634 0.4263
## or equivalently
coxph(Surv(yrs, status) ~ radiation + tt(radiation) + cluster(id), tt = function(x,t, ...) x * t,
data = gastric, method = "breslow")
## Call:
## coxph(formula = Surv(yrs, status) ~ radiation + tt(radiation),
## data = gastric, tt = function(x, t, ...) x * t, method = "breslow",
## cluster = id)
##
## coef exp(coef) se(coef) robust se z p
## radiation 1.2700 3.5607 0.4186 0.4335 2.930 0.00339
## tt(radiation) -0.9653 0.3809 0.3177 0.3409 -2.831 0.00464
##
## Likelihood ratio test=13.47 on 2 df, p=0.001188
## n= 90, number of events= 79
## extract HR at 0.5, 1 and 2 years
fit1est <- predict(fit1, type = "slice.time", x = "yrs", z = "radiation", newx = c(0.5, 1, 2),
exp = TRUE, verbose = TRUE, pval = TRUE)
## yrs HR HR lower 0.95 HR upper 0.95 p
## 1 0.5 2.1975 1.2096 3.9924 0.0098
## 2 1.0 1.3562 0.8536 2.1547 0.1971
## 3 2.0 0.5165 0.2381 1.1207 0.0946
Table2[c("HR at 0.5 years", "HR at 1 year",
"HR at 2 years"), ] <- cbind(fit1est$estimates[, "HR"],
fit1est$estimates[, "HR lower 0.95"],
fit1est$estimates[, "HR upper 0.95"],
fit1est$estimates[, "p"])
## visualize the estimated linear time-dependent effect
fit1est2 <- predict(fit1, type = "slice.time", x = "yrs", z = "radiation",
newx = seq(from = 0.1, to = 3, by = 0.1))
if (pdfind) { pdf("figure3.pdf", width = 7, height = 5) }
par(oma = c(2, 2, 0.5, 0.5), mar=c(2, 2, 0, 0))
plot(fit1est2, addci = TRUE)
mtext(side = 1, line = 2.5, text = "time (yrs)", cex = 1.3)
mtext(side = 2, line = 2.3, text = expression(paste(hat(beta), "(t) for radiation")),
cex = 1.3)
if (pdfind) { dev.off() }
## extended Cox model - assume a log-linear time-dependent effect
gfit8 <- coxphw(Surv(yrs, status) ~ radiation + log(yrs):radiation, data = gastric,
template = "PH")
summary(gfit8)
## coxphw(formula = Surv(yrs, status) ~ radiation + log(yrs):radiation,
## data = gastric, template = "PH")
##
## Model fitted by unweighted estimation (PH template)
##
## coef se(coef) exp(coef) lower 0.95 upper 0.95
## radiation 0.03766302 0.2367992 1.0383813 0.6528193 1.651660
## log(yrs):radiation -0.66924556 0.4821178 0.5120948 0.1990540 1.317437
## z p
## radiation 0.1590504 0.8736291
## log(yrs):radiation -1.3881370 0.1650953
##
## Wald Chi-square = 1.97312 on 2 df p = 0.372857 n = 90
##
## Covariance-Matrix:
## radiation log(yrs):radiation
## radiation 0.056073853 0.004581723
## log(yrs):radiation 0.004581723 0.232437577
##
## Generalized concordance probability: Estimates may be biased!
## concordance prob. lower 0.95 upper 0.95
## radiation 0.5094 0.395 0.6229
## log(yrs):radiation 0.3387 0.166 0.5685
## or equivalently
coxph(Surv(yrs, status) ~ radiation + tt(radiation) + cluster(id),
tt = function(x, t, ...) x * log(t), data = gastric, method = "breslow")
## Call:
## coxph(formula = Surv(yrs, status) ~ radiation + tt(radiation),
## data = gastric, tt = function(x, t, ...) x * log(t), method = "breslow",
## cluster = id)
##
## coef exp(coef) se(coef) robust se z p
## radiation 0.03766 1.03838 0.23962 0.23680 0.159 0.874
## tt(radiation) -0.66925 0.51209 0.27299 0.48212 -1.388 0.165
##
## Likelihood ratio test=8.02 on 2 df, p=0.01809
## n= 90, number of events= 79
## weighted Cox regression
fit2 <- coxphw(Surv(yrs, status) ~ radiation, data = gastric, template = "AHR")
summary(fit2)
## coxphw(formula = Surv(yrs, status) ~ radiation, data = gastric,
## template = "AHR")
##
## Model fitted by weighted estimation (AHR template)
##
## coef se(coef) exp(coef) lower 0.95 upper 0.95 z
## radiation 0.4625051 0.2387432 1.588047 0.9945916 2.535608 1.937249
## p
## radiation 0.05271492
##
## Wald Chi-square = 3.752934 on 1 df p = 0.05271492 n = 90
##
## Covariance-Matrix:
## radiation
## radiation 0.05699834
##
## Generalized concordance probability:
## concordance prob. lower 0.95 upper 0.95
## radiation 0.6136 0.4986 0.7172
## weighted Cox regression with truncation of weights
gfit9 <- coxphw(Surv(yrs, status) ~ radiation, data = gastric, template = "AHR",
trunc.weights = 0.95)
summary(gfit9)
## coxphw(formula = Surv(yrs, status) ~ radiation, data = gastric,
## template = "AHR", trunc.weights = 0.95)
##
## Model fitted by weighted estimation (AHR template)
##
## coef se(coef) exp(coef) lower 0.95 upper 0.95 z
## radiation 0.4622282 0.2384041 1.587608 0.9949774 2.533221 1.938843
## p
## radiation 0.05252042
##
## Wald Chi-square = 3.759113 on 1 df p = 0.05252042 n = 90
##
## Covariance-Matrix:
## radiation
## radiation 0.05683651
##
## Generalized concordance probability:
## concordance prob. lower 0.95 upper 0.95
## radiation 0.6135 0.4987 0.717
if (pdfind) { pdf(file = "figure4.pdf", width = 6, height = 5) }
par(oma = c(2, 2, 0.5, 0.5), mar = c(2, 2, 0, 0))
plot(x = gfit9, las = 1, lwd = 2)
mtext(side = 1, line = 2.5, text = "time (years)")
mtext(side = 2, line = 2.5, text = "weight")
## [1] 0.3134808 1.6534706
Table2["average HR", ] <- cbind(exp(gfit9$coeff),
exp(confint(gfit9)),
summary(gfit9, print = FALSE)$prob)
Table2["c'%", ] <- c(as.vector(concord(gfit9)), summary(gfit9, print = FALSE)$prob)
## finish Table 1
Table2["c'%", 1:3] <- 100 * Table2["c'%", 1:3]
Table2 <- round(Table2, digits = 3)
Table2[, 1] <- paste(Table2[, 1], " (", Table2[, 2], "-", Table2[, 3], ")", sep = "")
Table2[, 2] <- Table2[, 4]
Table2 <- Table2[, 1:2]
dimnames(Table2)[[2]] <- c("Estimate (95% CI)", "p")
Table2
## Estimate (95% CI) p
## Ignoring non-proportional hazards * NA (NA-NA) NA
## HR Cox regression 1.152 (0.735-1.805) 0.537
## Estimating piecewise constant HRs * NA (NA-NA) NA
## HR 1st year 2.405 (1.27-4.554) 0.007
## HR >1st year 0.546 (0.277-1.078) 0.081
## Including a time-by-covariate interaction NA (NA-NA) NA
## HR at 0.5 years 2.197 (1.21-3.992) 0.010
## HR at 1 year 1.356 (0.854-2.155) 0.197
## HR at 2 years 0.517 (0.238-1.121) 0.095
## Weighted Cox regression NA (NA-NA) NA
## average HR 1.588 (0.995-2.533) 0.053
## c'% 61.35 (49.87-71.7) 0.053
## ignore non-proportional hazards and apply a Cox model
## (use breslow weights to make it directly comparable to coxphw)
bfit2 <- coxphw(Surv(thdur, success) ~ bfb + log2heal, data = biofeedback, template = "PH")
summary(bfit2)
## coxphw(formula = Surv(thdur, success) ~ bfb + log2heal, data = biofeedback,
## template = "PH")
##
## Model fitted by unweighted estimation (PH template)
##
## coef se(coef) exp(coef) lower 0.95 upper 0.95 z
## bfb 0.2699762 0.3453073 1.3099332 0.6657683 2.577361 0.7818433
## log2heal -0.5266649 0.3636448 0.5905713 0.2895592 1.204502 -1.4482949
## p
## bfb 0.4343067
## log2heal 0.1475346
##
## Wald Chi-square = 2.657646 on 2 df p = 0.2647887 n = 33
##
## Covariance-Matrix:
## bfb log2heal
## bfb 0.119237110 -0.002917929
## log2heal -0.002917929 0.132237551
##
## Generalized concordance probability: Estimates may be biased!
## concordance prob. lower 0.95 upper 0.95
## bfb 0.5671 0.3997 0.7205
## log2heal 0.3713 0.2245 0.5464
## or equivalently
coxph(Surv(thdur, success) ~ bfb + log2heal + cluster(id), data = biofeedback,
x = TRUE, method = "breslow")
## Call:
## coxph(formula = Surv(thdur, success) ~ bfb + log2heal, data = biofeedback,
## x = TRUE, method = "breslow", cluster = id)
##
## coef exp(coef) se(coef) robust se z p
## bfb 0.2700 1.3099 0.4273 0.3453 0.782 0.434
## log2heal -0.5267 0.5906 0.2543 0.3636 -1.448 0.148
##
## Likelihood ratio test=7.19 on 2 df, p=0.02753
## n= 33, number of events= 23
## two stage estimation
stage1 <- coxph(Surv(thdur, success) ~ strata(bfb) + log2heal + tt(log2heal) + cluster(id),
tt = function(x, t, ...) x * log(t), data = biofeedback, method = "breslow")
summary(stage1)
## Call:
## coxph(formula = Surv(thdur, success) ~ strata(bfb) + log2heal +
## tt(log2heal), data = biofeedback, tt = function(x, t, ...) x *
## log(t), method = "breslow", cluster = id)
##
## n= 33, number of events= 23
##
## coef exp(coef) se(coef) robust se z Pr(>|z|)
## log2heal 0.7368 2.0892 0.9008 0.3797 1.940 0.05233 .
## tt(log2heal) -0.4153 0.6602 0.3257 0.1490 -2.786 0.00533 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## exp(coef) exp(-coef) lower .95 upper .95
## log2heal 2.0892 0.4787 0.9926 4.3971
## tt(log2heal) 0.6602 1.5148 0.4929 0.8841
##
## Concordance= 0.664 (se = 0.063 )
## Likelihood ratio test= 8.53 on 2 df, p=0.01
## Wald test = 7.84 on 2 df, p=0.02
## Score (logrank) test = 6.59 on 2 df, p=0.04, Robust = 7.71 p=0.02
##
## (Note: the likelihood ratio and score tests assume independence of
## observations within a cluster, the Wald and robust score tests do not).
## for comparison linear time-dependent effect
coxph(Surv(thdur, success) ~ strata(bfb) + log2heal + tt(log2heal) + cluster(id),
tt = function(x, t, ...) x * t, data = biofeedback, method = "breslow")
## Call:
## coxph(formula = Surv(thdur, success) ~ strata(bfb) + log2heal +
## tt(log2heal), data = biofeedback, tt = function(x, t, ...) x *
## t, method = "breslow", cluster = id)
##
## coef exp(coef) se(coef) robust se z p
## log2heal -0.02130 0.97892 0.45270 0.43296 -0.049 0.961
## tt(log2heal) -0.01957 0.98062 0.02218 0.01549 -1.263 0.206
##
## Likelihood ratio test=8.64 on 2 df, p=0.01331
## n= 33, number of events= 23
stage2 <- coxphw(Surv(thdur, success) ~ bfb + log2heal + log(thdur):log2heal, data = biofeedback,
template = "AHR", betafix = c(NA, coef(stage1)))
summary(stage2)
## coxphw(formula = Surv(thdur, success) ~ bfb + log2heal + log(thdur):log2heal,
## data = biofeedback, template = "AHR", betafix = c(NA, coef(stage1)))
##
## Model fitted by weighted estimation (AHR template)
##
## coef se(coef) exp(coef) lower 0.95 upper 0.95
## bfb 0.5967993 0.3732872 1.8162961 0.8738643 3.775107
## log2heal 0.7367590 NA 2.0891536 NA NA
## log(thdur):log2heal -0.4152653 NA 0.6601651 NA NA
## z p
## bfb 1.598767 0.1098724
## log2heal NA NA
## log(thdur):log2heal NA NA
##
## Wald Chi-square = 2.556056 on 1 df p = 0.1098724 n = 33 (based on: bfb )
##
## Covariance-Matrix:
## [1] 0.1393434
##
## Generalized concordance probability:
## concordance prob. lower 0.95 upper 0.95
## bfb 0.6449 0.4663 0.7906
## log2heal 0.6763 NA NA
## log(thdur):log2heal 0.3977 NA NA
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.