%\VignetteIndexEntry{BuyseTest: overview} %\VignetteEngine{R.rsp::asis} %\VignetteKeyword{PDF} %\VignetteKeyword{vignette} %\VignetteKeyword{package} ## chunk 2 library(BuyseTest) library(data.table) ## chunk 3 data(cancer, package = "survival") veteran <- cbind(id = 1:NROW(veteran), veteran) veteran$trt <- factor(veteran$trt,1:2,c("Pl","Exp")) head(veteran) ## chunk 4 utils::packageVersion("BuyseTest") ## chunk 5 sessionInfo() ## * Performing generalized pairwise comparisons (GPC) ## chunk 6 BT <- BuyseTest(data = veteran, endpoint = "time", type = "timeToEvent", treatment = "trt", status = "status", threshold = 20) ## chunk 7 BT.f <- BuyseTest(trt ~ tte(time, threshold = 20, status = "status"), data = veteran, trace = FALSE) ## chunk 8 BT.f@call <- list(); BT@call <- list(); testthat::expect_equal(BT.f,BT) ## ** Displaying the results ## chunk 9 summary(BT) ## chunk 10 print(BT, percentage = FALSE) ## chunk 11 model.tables(BT, percentage = FALSE) ## chunk 12 confint(BT) ## chunk 13 coef(BT) ## ** What about other summary statistics? ## chunk 14 summary(BT, statistic = "winRatio") ## chunk 15 confint(BT, statistic = "favorable") ## chunk 16 BT.perm <- BuyseTest(trt ~ tte(time, threshold = 20, status = "status"), data = veteran, trace = FALSE, method.inference = "permutation", seed = 10) confint(BT.perm, statistic = "favorable") ## chunk 17 rbind(confint(BT, statistic = "favorable", null = 0.42), confint(BT, statistic = "favorable", null = 0.5)) ## chunk 18 BT.half <- BuyseTest(trt ~ tte(time, threshold = 20, status = "status"), data = veteran, trace = FALSE, add.halfNeutral = TRUE) confint(BT.half, statistic = "favorable") ## chunk 19 confint(BT.half, statistic = "winRatio") ## chunk 20 BT.halfboot <- BuyseTest(trt ~ tte(time, threshold = 20, status = "status"), data = veteran, trace = FALSE, add.halfNeutral = TRUE, method.inference = "bootstrap", seed = 10) Mstat <- rbind(netBenefit = confint(BT.halfboot, statistic = "netBenefit"), winRatio = confint(BT.halfboot, statistic = "winRatio"), favorable = confint(BT.halfboot, statistic = "favorable")) Mstat ## ** Stratified GPC ## chunk 21 ffstrata <- trt ~ tte(time, threshold = 20, status = "status") + strata(celltype) BTstrata <- BuyseTest(ffstrata, data = veteran, trace = 0) ## chunk 22 keep.colStrata <- c("endpoint","strata", "total", "favorable","unfavorable","neutral","uninf","delta","Delta") summary(BTstrata, type.display = keep.colStrata) ## chunk 23 strata.obs <- as.data.frame(nobs(BTstrata, strata = TRUE)) strata.obs ## chunk 24 dfStrata <- model.tables(BTstrata, percentage = FALSE, strata = c("squamous","smallcell","adeno","large"), columns = c("strata","total","favorable","unfavorable")) dfStrata ## chunk 25 delta <- (dfStrata$favorable - dfStrata$unfavorable)/strata.obs$pairs delta ## chunk 26 weightCMH <- strata.obs$pairs/(strata.obs$Pl + strata.obs$Exp) list(estimate = sum(delta * weightCMH/sum(weightCMH)), weight = 100*weightCMH/sum(weightCMH)) ## chunk 27 BTstrata2 <- BuyseTest(ffstrata, data = veteran, trace = 0, pool.strata = "buyse") summary(BTstrata2, type.display = keep.colStrata) ## chunk 28 confint(BTstrata2) ## chunk 29 confint(BTstrata, strata = TRUE) ## ** Standardization ## chunk 30 BTstd <- BuyseTest(ffstrata, data = veteran, trace = 0, pool.strata = "standardization") model.tables(BTstd)[,c("strata","total","delta","Delta","lower.ci","upper.ci","p.value")] ## chunk 31 BuyseTest(trt ~ tte(time, threshold = 20, status = "status"), data = rbind(veteran[veteran$celltype == "smallcell" & veteran$trt == "Pl",], veteran[veteran$celltype == "squamous" & veteran$trt == "Exp",]), trace = 0) ## chunk 32 BTstd.boot <- BuyseTest(ffstrata, data = veteran, trace = 0, pool.strata = "standardization", method.inference = "bootstrap", n.resampling = 100, seed = 10) confint(BTstd.boot, strata = TRUE)[1:6,] ## ** Using multiple endpoints (hierarchical) ## chunk 33 ff2 <- trt ~ tte(time, threshold = 20, status = "status") + cont(karno, threshold = 0) BT.H <- BuyseTest(ff2, data = veteran, trace = 0) summary(BT.H) ## chunk 34 plot(BT.H, type = "hist") plot(BT.H, type = "racetrack") plot(BT.H, type = "pie") ## ** Using multiple endpoints (non-hierarchical) ## chunk 36 BT.nH <- BuyseTest(ff2, hierarchical = FALSE, data = veteran, trace = 0) summary(BT.nH) ## chunk 37 ff2w <- trt ~ tte(time, threshold = 20, status = "status", weight = 0.8) ff2w <- update.formula(ff2w, . ~ . + cont(karno, threshold = 0, weight = 0.2)) BT.nHw <- BuyseTest(ff2w, hierarchical = FALSE, data = veteran, trace = 0) model.tables(BT.nHw) ## chunk 38 confint(BuyseTest(trt ~ cont(karno, threshold = 0), data = veteran, trace = 0)) ## chunk 39 confint(BT.nHw, cumulative = FALSE) ## chunk 40 confint(BT.nHw, transform = FALSE) ## ** Statistical inference ## chunk 41 BT.perm <- BuyseTest(trt ~ tte(time, threshold = 20, status = "status"), data = veteran, trace = 0, method.inference = "permutation", seed = 10) summary(BT.perm) ## chunk 42 BT.boot <- BuyseTest(trt ~ tte(time, threshold = 20, status = "status"), data = veteran, trace = 0, method.inference = "bootstrap", seed = 10) summary(BT.boot) ## chunk 43 BT.ustat <- BuyseTest(trt ~ tte(time, threshold = 20, status = "status"), data = veteran, trace = 0, method.inference = "u-statistic") summary(BT.ustat) ## chunk 44 set.seed(10) sapply(1:10, function(i){mean(rbinom(1e4, size = 1, prob = 0.05))}) ## ** What if smaller is better? ## chunk 45 ffop <- trt ~ tte(time, status = "status", threshold = 20, operator = "<0") BTinv <- BuyseTest(ffop, data = veteran, trace = 0) summary(BTinv) ## ** What about a multiplicative instead of additive threshold? ## chunk 46 ffstar <- trt ~ tte(time, status = "status", threshold = 20, operator = "*") BTstar <- BuyseTest(ffstar, data = veteran, trace = 0) print(BTstar) ## ** Stopping comparison for neutral pairs ## chunk 48 dt.sim <- data.table(Id = 1:2, treatment = c("Yes","No"), tumor = c("Yes","Yes"), size = c(15,20)) dt.sim ## chunk 49 BT.pair <- BuyseTest(treatment ~ bin(tumor) + cont(size, operator = "<0"), data = dt.sim, trace = 0, method.inference = "none") summary(BT.pair) ## chunk 50 BT.pair2 <- BuyseTest(treatment ~ bin(tumor) + cont(size, operator = "<0"), data = dt.sim, trace = 0, method.inference = "none", neutral.as.uninf = FALSE) summary(BT.pair2) ## ** Is multiple testing a concern with GPC? ## chunk 51 BTse <- sensitivity(BT.ustat, threshold = seq(0,500, length.out=10), trace = FALSE) BTse ## chunk 52 BuyseMultComp(BT.H, endpoint = 1:2) ## chunk 53 BuyseMultComp(BT.nH, cumulative = FALSE, endpoint = 1:2) ## chunk 54 BuyseMultComp(list(hierarchical = BT.H, Obrien = BT.nH), cluster = "id") ## chunk 55 BTse.ustat <- sensitivity(BT.ustat, threshold = seq(0,500, length.out=10), band = TRUE, adj.p.value = TRUE, seed = 10, trace = FALSE) BTse.ustat[,c("time","estimate", "lower.ci","upper.ci","p.value", "lower.band","upper.band","adj.p.value")] ## chunk 56 library(ggplot2) autoplot(BTse.ustat) ## chunk 58 BTse.cor <- cor(lava::iid(BTse.ustat)) range(BTse.cor[lower.tri(BTse.cor)]) ## chunk 59 BTse.H <- sensitivity(BT.H, trace = FALSE, threshold = list(time = seq(0,500,length = 10), karno = c(0,40,80))) head(BTse.H) ## chunk 60 grid <- expand.grid(list("time_t20" = seq(0,500,length = 10), "karno" = c(0,40,80))) cbind(head(grid)," " = " ... ",tail(grid)) BTse.H2 <- sensitivity(BT.H, threshold = grid, trace = FALSE) range(BTse.H-BTse.H2) ## chunk 61 autoplot(BTse.H, col = NA) ## alternative display: ## autoplot(BTse.H, position = position_dodge(width = 15)) ## * Getting additional inside: looking at the pair level ## ** Extracting the contribution of each pair to the statistic (long format) ## chunk 63 form <- trt ~ tte(time, threshold = 20, status = "status") + cont(karno) BT.keep <- BuyseTest(form, data = veteran, keep.pairScore = TRUE, trace = 0, method.inference = "none") ## chunk 64 getPairScore(BT.keep, endpoint = 1) ## chunk 65 veteran[c(70,1),] ## chunk 66 getPairScore(BT.keep, endpoint = 1)[, mean(favorable) - mean(unfavorable)] ## chunk 67 BT.keep ## ** Extracting the contribution of each pair to the statistic (matrix format) ## chunk 68 Mscore <- getMatrixScore(BT.keep, endpoint = 1) dim(Mscore) Mscore[1:4,1:4] ## chunk 69 MscoreAll <- getMatrixScore(BT.keep, endpoint = 1, within = TRUE) dim(MscoreAll) ## chunk 70 rbind(cbind(MscoreAll[1:4,1:4],NA,MscoreAll[70:73,1:4]), NA, cbind(MscoreAll[1:4,70:73],NA,MscoreAll[70:73,70:73])) ## ** Extracting the survival probabilities ## chunk 71 BuyseTest.options(keep.survival = TRUE, precompute = FALSE) BT.keep2 <- BuyseTest(trt ~ tte(time, threshold = 20, status = "status") + cont(karno), data = veteran, keep.pairScore = TRUE, scoring.rule = "Peron", trace = 0, method.inference = "none") ## chunk 72 outSurv <- getSurvival(BT.keep2, endpoint = 1, strata = 1) str(outSurv) ## *** Computation of the score with only one censored event ## chunk 73 getPairScore(BT.keep2, endpoint = 1, rm.withinStrata = FALSE)[91] ## chunk 74 veteran[c(22,71),] ## chunk 75 iSurv <- outSurv$survTimeC[22,] iSurv ## chunk 76 Sc97 <- iSurv["survivalC_0"] Sc97 ## chunk 77 iSurv <- outSurv$survTimeT[2,] ## survival at time 112+20 iSurv ## chunk 78 Sc132 <- iSurv["survivalC+threshold"] Sc132 ## chunk 79 Sc132/Sc97 ## *** Computation of the score with two censored events ## chunk 80 head(outSurv$survJumpT) ## chunk 81 getPairScore(BT.keep2, endpoint = 1, rm.withinStrata = FALSE)[148] ## chunk 82 veteran[c(10,72),] ## chunk 83 calcInt <- function(...){ ## no need for the functionnal derivative of the score BuyseTest:::.calcIntegralSurv_cpp(..., returnDeriv = FALSE, derivSurv = matrix(0), derivSurvD = matrix(0)) } ## chunk 84 denom <- as.double(outSurv$survTimeT[3,"survivalT_0"] * outSurv$survTimeC[10,"survivalC_0"]) M <- cbind("favorable" = -calcInt(outSurv$survJumpC, start = 100, lastSurv = outSurv$lastSurv[2], lastdSurv = outSurv$lastSurv[1])/denom, "unfavorable" = -calcInt(outSurv$survJumpT, start = 87, lastSurv = outSurv$lastSurv[1], lastdSurv = outSurv$lastSurv[2])/denom) rownames(M) <- c("lowerBound","upperBound") M ## chunk 85 outSurv$lastSurv ## * Dealing with missing values or/and right censoring ## chunk 86 set.seed(10) dt <- simBuyseTest(1e2, latent = TRUE, argsCont = NULL, argsTTE = list(scale.T = 1/2, scale.C = 1, scale.censoring.C = 1, scale.censoring.T = 1)) dt[, eventtimeCensoring := NULL] dt[, status1 := 1] head(dt) ## chunk 87 100*dt[,mean(status==0)] ## chunk 88 eGS <- BuyseTest(treatment ~ tte(eventtimeUncensored, status1, threshold = 0.5), data = dt, scoring.rule = "Gehan", method.inference = "none", trace = 0) coef(eGS) ## chunk 89 names(survival::survreg.distributions) ## ** Gehan's scoring rule ## chunk 90 e.Gehan <- BuyseTest(treatment ~ tte(eventtime, status, threshold = 0.5), data = dt, scoring.rule = "Gehan", trace = 0) model.tables(e.Gehan) ## ** Latta's scoring rule ## chunk 91 e.Latta <- BuyseTest(treatment ~ tte(eventtime, status, threshold = 0.5), data = dt, scoring.rule = "Latta", trace = 0) model.tables(e.Latta) ## chunk 92 dt[,.SD[which.max(eventtime)]] ## chunk 93 e.prodlimLatta <- prodlim(Hist(eventtime, status) ~ 1, data = dt) attr(e.prodlimLatta,"iidNuisance") <- TRUE ## chunk 94 e.LattaManual <- BuyseTest(treatment ~ tte(eventtime, status, threshold = 0.5), model.tte = e.prodlimLatta, data = dt, scoring.rule = "Peron", trace = 0) confint(e.LattaManual) ## ** Peron's scoring rule ## chunk 95 e.Peron <- BuyseTest(treatment ~ tte(eventtime, status, threshold = 0.5), data = dt, scoring.rule = "Peron", trace = 0) model.tables(e.Peron) ## chunk 96 dt[,.SD[which.max(eventtime)],by="treatment"] ## chunk 97 library(prodlim) e.prodlimPeron <- prodlim(Hist(eventtime, status) ~ treatment, data = dt) ## chunk 98 e.PeronManual <- BuyseTest(treatment ~ tte(eventtime, status, threshold = 0.5), model.tte = e.prodlimPeron, data = dt, scoring.rule = "Peron", trace = 0) confint(e.PeronManual) ## chunk 99 dt2 <- dt[order(dt$eventtime)] e.PeronManual2 <- BuyseTest(treatment ~ tte(eventtime, status, threshold = 0.5), model.tte = prodlim(Hist(eventtime, status) ~ treatment, data = dt2), data = dt, scoring.rule = "Peron", trace = 0) confint(e.PeronManual2) ## ** Efron's scoring rule ## chunk 100 e.Efron <- BuyseTest(treatment ~ tte(eventtime, status, threshold = 0.5), data = dt, scoring.rule = "Efron", trace = 0) model.tables(e.Efron) ## chunk 101 dt[,.SD[which.max(eventtime)],by="treatment"] ## chunk 102 dtEfron <- copy(dt) dtEfron[treatment=="T" & id == 154, c("eventtime","status") := .(eventtime+1e-10,1)] ## dt2[treatment=="T" & eventtime > 1.58865, status := 1] ## chunk 103 e.prodlimEfron <- prodlim(Hist(eventtime, status) ~ treatment, data = dtEfron) attr(e.prodlimEfron,"iidNuisance") <- TRUE ## chunk 104 e.Efron <- BuyseTest(treatment ~ tte(eventtime, status, threshold = 0.5), model.tte = e.prodlimEfron, data = dt, scoring.rule = "Peron", trace = 0) confint(e.Efron) ## ** Scoring rule based on a parametric survival model ## chunk 105 names(survreg.distributions) ## chunk 106 e.Weibull <- BuyseTest(treatment ~ tte(eventtime, status, threshold = 0.5), data = dt, scoring.rule = "Weibull", trace = 0) model.tables(e.Weibull) ## chunk 108 library(survival) e.survregWeibull <- survreg(Surv(eventtime, status) ~ treatment, data = dt, dist = "weibull") ## chunk 109 e.WeibullManual <- BuyseTest(treatment ~ tte(eventtime, status, threshold = 0.5), model.tte = e.survregWeibull, data = dt, scoring.rule = "Peron", trace = 0) model.tables(e.WeibullManual) ## ** Correction via re-weighting citep:peron2021correcting ## *** At the trial level ## chunk 110 BT.trialW <- BuyseTest(treatment ~ tte(eventtime, status, threshold = 0.5), data = dt, keep.pairScore = TRUE, trace = 0, scoring.rule = "Gehan", method.inference = "none", correction.uninf = 2) summary(BT.trialW) ## chunk 111 iScore <- getPairScore(BT.trialW, endpoint = 1) ## chunk 112 iScore[,.SD[1], .SDcols = c("favorableC","unfavorableC","neutralC","uninfC"), by = c("favorable","unfavorable","neutral","uninf")] ## chunk 113 iScore[,1/mean(favorable + unfavorable + neutral)] ## *** At the pair level ## chunk 114 BT.pairI <- BuyseTest(treatment ~ tte(eventtime, status, threshold = 0.5), data = dt, keep.pairScore = TRUE, trace = 0, scoring.rule = "Gehan", method.inference = "none", correction.uninf = TRUE) summary(BT.pairI) ## chunk 115 iScore <- getPairScore(BT.pairI, endpoint = 1) iScore[,.SD[1], .SDcols = c("favorableC","unfavorableC","neutralC","uninfC"), by = c("favorable","unfavorable","neutral","uninf")] ## chunk 116 c(favorable = unname(coef(BT.pairI, statistic = "favorable")), unfavorable = unname(coef(BT.pairI, statistic = "unfavorable")), neutral = unname(coef(BT.pairI, statistic = "neutral"))) ## *** Note on the use of the corrections ## chunk 117 set.seed(10);n <- 250; df <- rbind(data.frame(group = "T1", time = rweibull(n, shape = 1, scale = 2), status = 1), data.frame(group = "T2", time = rweibull(n, shape = 2, scale = 1.8), status = 1)) df$censoring <- runif(NROW(df),0,2) df$timeC <- pmin(df$time,df$censoring) df$statusC <- as.numeric(df$time<=df$censoring) plot(prodlim(Hist(time,status)~group, data = df)); title("complete data"); plot(prodlim(Hist(timeC,statusC)~group, data = df)); title("right-censored data"); ## chunk 119 e.ref <- BuyseTest(group ~ tte(time,status), data = df, method.inference = "none", trace = FALSE) s.ref <- model.tables(e.ref, column = c("favorable","unfavorable","neutral","uninf","Delta")) s.ref ## chunk 120 e.correction <- BuyseTest(group ~ tte(timeC,statusC), data = df, method.inference = "none", trace = FALSE, correction.uninf = 1) s.correction <- model.tables(e.correction, column = c("favorable","unfavorable","neutral","uninf","Delta")) ## chunk 121 e.Peron <- BuyseTest(group ~ tte(timeC,statusC), data = df, trace = FALSE) s.Peron <- model.tables(e.Peron, column = c("favorable","unfavorable","neutral","uninf","Delta")) rbind("reference" = s.ref, "no correction" = s.Peron, "correction" = s.correction) ## * Simulating data using =simBuyseTest= ## chunk 122 set.seed(10) simBuyseTest(n.T = 5, n.C = 5) ## chunk 123 set.seed(10) argsCont <- list(mu.T = c(5,5), mu.C = c(10,10), sigma.T = c(1,1), sigma.C = c(1,1), name = c("tumorSize","score")) dt <- simBuyseTest(n.T = 5, n.C = 5, argsCont = argsCont) dt ## * Power calculation using =powerBuyseTest= ## chunk 124 simFCT <- function(n.C, n.T){ out <- rbind(cbind(Y=stats::rt(n.C, df = 5), group=0), cbind(Y=stats::rt(n.T, df = 5) + 1/2, group=1)) return(data.table::as.data.table(out)) } set.seed(10) simFCT(101,101) ## chunk 125 null <- c("netBenefit" = 0) ## chunk 126 powerW <- powerBuyseTest(sim = simFCT, method.inference = "u-statistic", null = null, sample.size = c(5,10,20,30,50,100), formula = group ~ cont(Y), n.rep = 1000, seed = 10, cpus = 10, trace = 0) ## chunk 127 summary(powerW) ## chunk 128 nW <- powerBuyseTest(sim = simFCT, method.inference = "u-statistic", power = 0.8, max.sample.size = 1000, formula = group ~ cont(Y), null = c("netBenefit" = 0), n.rep = c(1000,10), seed = 10, cpus = 5, trace = 0) ## chunk 129 summary(nW) ## * Modifying default options ## chunk 130 BuyseTest.options("trace") ## chunk 131 BuyseTest.options(trace = 0) ## chunk 132 BuyseTest.options(summary.display = list(c("endpoint","threshold","delta","Delta","information(%)"))) summary(BT) ## chunk 133 BuyseTest.options(reinitialise = TRUE) ## * References