Title: | Inverse Probability of Censoring Weights to Deal with Treatment Switch in Randomized Clinical Trials |
---|---|
Description: | Contains functions for formatting clinical trials data and implementing inverse probability of censoring weights to handle treatment switches when estimating causal treatment effect in randomized clinical trials. |
Authors: | Nathalie Graffeo [aut, cre], Aurelien Latouche [aut], Sylvie Chevret [aut] |
Maintainer: | Nathalie Graffeo <[email protected]> |
License: | GPL-3 |
Version: | 1.0.4 |
Built: | 2024-11-26 03:35:45 UTC |
Source: | https://github.com/cran/ipcwswitch |
Censoring patient initiating the other arm treatment and building a treatment censoring indicator cens
cens.ipw( data, id, tstart, tstop, event, censTime, arm, realtrt = FALSE, trt.start = NULL, trt.stop = NULL )
cens.ipw( data, id, tstart, tstop, event, censTime, arm, realtrt = FALSE, trt.start = NULL, trt.stop = NULL )
data |
a dataframe containing the following variables |
id |
the patient's id |
tstart |
the date of the beginning of the follow-up (in numeric format) |
tstop |
the date of the end of the follow-up (in numeric format) |
event |
the indicator of failure (a death is denoted by 1 at the end of the follow-up) |
censTime |
the chosen time to censor the patients (in numeric format) |
arm |
the randomized treatment (2-levels factor) |
realtrt |
the randomized treatment (2-levels factor) |
trt.start |
the time of initiation of the randomized treatment (NULL by default) |
trt.stop |
the time of termination of the randomized treatment (NULL by default) |
a dataframe in the long format, with the data being censored according to the input date, censTime. a treatment censoring indicator, cens, is thus added to the previous dataset to indicate such a switch. Note that this function provides the option to include in the data the treatment really taken with the corresponding dates. Then, the treatment really taken is a 3-levels factor, i.e., the two from the randomized arms and a third indicating the no-treatment case (None).
Graffeo, N., Latouche, A., Le Tourneau C., Chevret, S. (2019) "ipcwswitch: an R package for inverse probability of censoring weighting with an application to switches in clinical trials". Computers in biology and medicine, 111, 103339. doi : "10.1016/j.compbiomed.2019.103339"
SHIdat
, timesTokeep
, wideToLongTDC
# To obtain the times parameter, we can apply the timesTokeep function on the same # dataframe in the wide format kept.t <- timesTokeep(toydata, id = "id", tstart = "randt", tstop = "lastdt", mes.cov = list(c("ps1", "ps2", "ps3")), time.cov = list(c("randt", "dt2", "dt3"))) # Now, we can build the long format toy.long <- wideToLongTDC(data = toydata, id = "id", tstart = "randt", tstop = "lastdt", event = "status", bas.cov = c("age", "arm", "swtrtdt"), mes.cov = list(TDconf = c("ps1", "ps2", "ps3")), time.cov = list(c("randt", "dt2", "dt3")), times = kept.t[[1]]) # Put dates in numeric format with tstart at 0 toy.long$tstart <- as.numeric(toy.long$tstart) toy.long$tstop <- as.numeric(toy.long$tstop) toy.long$swtrtdt <- as.numeric(toy.long$swtrtdt) tabi <- split(toy.long, toy.long$id) L.tabi <- length(tabi) tablist <- lapply(1:L.tabi, function(i){ refstart <- tabi[[i]]$tstart[1] tabi[[i]]$tstart <- tabi[[i]]$tstart - refstart tabi[[i]]$tstop <- tabi[[i]]$tstop - refstart tabi[[i]]$swtrtdt <- tabi[[i]]$swtrtdt - refstart return(tabi[[i]]) }) toy.long <- do.call( rbind, tablist ) # Patients are censored when initiating the other arm treatment, that is, at time swtrtdt toy.long2 <- cens.ipw(toy.long, id = "id", tstart = "tstart", tstop = "tstop", event = "event", arm = "arm", realtrt = FALSE, censTime ="swtrtdt") # Before censoring: toy.long # Ater censoring: toy.long2
# To obtain the times parameter, we can apply the timesTokeep function on the same # dataframe in the wide format kept.t <- timesTokeep(toydata, id = "id", tstart = "randt", tstop = "lastdt", mes.cov = list(c("ps1", "ps2", "ps3")), time.cov = list(c("randt", "dt2", "dt3"))) # Now, we can build the long format toy.long <- wideToLongTDC(data = toydata, id = "id", tstart = "randt", tstop = "lastdt", event = "status", bas.cov = c("age", "arm", "swtrtdt"), mes.cov = list(TDconf = c("ps1", "ps2", "ps3")), time.cov = list(c("randt", "dt2", "dt3")), times = kept.t[[1]]) # Put dates in numeric format with tstart at 0 toy.long$tstart <- as.numeric(toy.long$tstart) toy.long$tstop <- as.numeric(toy.long$tstop) toy.long$swtrtdt <- as.numeric(toy.long$swtrtdt) tabi <- split(toy.long, toy.long$id) L.tabi <- length(tabi) tablist <- lapply(1:L.tabi, function(i){ refstart <- tabi[[i]]$tstart[1] tabi[[i]]$tstart <- tabi[[i]]$tstart - refstart tabi[[i]]$tstop <- tabi[[i]]$tstop - refstart tabi[[i]]$swtrtdt <- tabi[[i]]$swtrtdt - refstart return(tabi[[i]]) }) toy.long <- do.call( rbind, tablist ) # Patients are censored when initiating the other arm treatment, that is, at time swtrtdt toy.long2 <- cens.ipw(toy.long, id = "id", tstart = "tstart", tstop = "tstop", event = "event", arm = "arm", realtrt = FALSE, censTime ="swtrtdt") # Before censoring: toy.long # Ater censoring: toy.long2
Computing the stabilized IPCweights
ipcw( data, id, tstart, tstop, cens, arm, bas.cov, conf, trunc = NULL, type = "kaplan-meier" )
ipcw( data, id, tstart, tstop, cens, arm, bas.cov, conf, trunc = NULL, type = "kaplan-meier" )
data |
a dataframe containing the following variables |
id |
the patient's id |
tstart |
the date of the beginning of the follow-up (in numeric format, with the first being equal at 0) |
tstop |
the date of the end of the follow-up (in numeric format) |
cens |
the indicator of treatment censoring (denoted by 1 at the end of the follow-up) |
arm |
the randomized treatment (2-levels factor) |
bas.cov |
a vector the baseline covariates |
conf |
a vector of time-dependent confounders |
trunc |
an optional fraction for the weights. For instance, when trunc = 0.01, the left tail is truncated to the 1st percentile and the right tail is truncated to the 99th percentile |
type |
a character string specifying the type of survival curve. The default is |
the initial dataframe data with stabilized IPCweights as additional arguments. By default, the un-truncated stabilized weights are given. If the trunc option is not NULL then the truncated stabilized weights are also given.
Graffeo, N., Latouche, A., Le Tourneau C., Chevret, S. (2019) "ipcwswitch: an R package for inverse probability of censoring weighting with an application to switches in clinical trials". Computers in biology and medicine, 111, 103339. doi : "10.1016/j.compbiomed.2019.103339"
## Not run # ipcw(toy.rep, tstart = tstart, tstop = tstop, cens = cens, # arm="arm", # bas.cov = c("age"), # conf = c("TDconf"), trunc = 0.05) # see ?SHIdat for a complete example
## Not run # ipcw(toy.rep, tstart = tstart, tstop = tstop, cens = cens, # arm="arm", # bas.cov = c("age"), # conf = c("TDconf"), trunc = 0.05) # see ?SHIdat for a complete example
Function to replicate the rows so that each patients' follow-up is split according to all event times (times parameter) up to each patient's end time
replicRows(data, tstart, tstop, event, cens, times1, times2, arm)
replicRows(data, tstart, tstop, event, cens, times1, times2, arm)
data |
a dataframe containing the following variables |
tstart |
the date of the beginning of the follow-up (in numeric format, with the first being equal at 0) |
tstop |
the date of the end of the follow-up (in numeric format) |
event |
the indicator of failure (a death is denoted by 1 at the end of the follow-up) |
cens |
the indicator of treatment censoring (denoted by 1 at the end of the follow-up) |
times1 |
a vector of times (in numeric format) indicating the times according to which the rows have to be split for patients in the first arm |
times2 |
a vector of times (in numeric format) indicating the times according to which the rows have to be split for patients in the second arm |
arm |
the randomized treatment (2-levels factor) |
a formatted dataframe with the rows replicated according to the provided times parameter
Graffeo, N., Latouche, A., Le Tourneau C., Chevret, S. (2019) "ipcwswitch: an R package for inverse probability of censoring weighting with an application to switches in clinical trials". Computers in biology and medicine, 111, 103339. doi : "10.1016/j.compbiomed.2019.103339"
cens.ipw
, SHIdat
, timesTokeep
, wideToLongTDC
# To obtain the times parameter, we can apply the timesTokeep function on the same # dataframe in the wide format kept.t <- timesTokeep(toydata, id = "id", tstart = "randt", tstop = "lastdt", mes.cov = list(c("ps1", "ps2", "ps3")), time.cov = list(c("randt", "dt2", "dt3"))) # Now, we can build the long format toy.long <- wideToLongTDC(data = toydata, id = "id", tstart = "randt", tstop = "lastdt", event = "status", bas.cov = c("age", "arm", "swtrtdt"), mes.cov = list(TDconf = c("ps1", "ps2", "ps3")), time.cov = list(c("randt", "dt2", "dt3")), times = kept.t[[1]]) # Put dates in numeric format with tstart at 0 toy.long$tstart <- as.numeric(toy.long$tstart) toy.long$tstop <- as.numeric(toy.long$tstop) toy.long$swtrtdt <- as.numeric(toy.long$swtrtdt) tabi <- split(toy.long, toy.long$id) L.tabi <- length(tabi) tablist <- lapply(1:L.tabi, function(i){ refstart <- tabi[[i]]$tstart[1] tabi[[i]]$tstart <- tabi[[i]]$tstart - refstart tabi[[i]]$tstop <- tabi[[i]]$tstop - refstart tabi[[i]]$swtrtdt <- tabi[[i]]$swtrtdt - refstart return(tabi[[i]]) }) toy.long <- do.call( rbind, tablist ) # Patients are censored when initiating the other arm treatment, that is, at time swtrtdt toy.long2 <- cens.ipw(toy.long, id = "id", tstart = "tstart", tstop = "tstop", event = "event", arm = "arm", realtrt = FALSE, censTime ="swtrtdt") # We collect all event times (death for both arms and treatment censoring according to the trt arm) rep.times1 <- unique(c(toy.long2$tstop[toy.long2$cens==1 & toy.long2$arm == "A"], toy.long2$tstop[toy.long2$event==1])) rep.times2 <- unique(c(toy.long2$tstop[toy.long2$cens==1 & toy.long2$arm == "B"], toy.long2$tstop[toy.long2$event==1])) # to put times in same order as arms levels levels(toy.long2[, "arm"]) # Now, we can replicate the rows toy.rep <- replicRows(toy.long2, tstart = "tstart", tstop = "tstop", event = "event", cens = "cens", times1 = rep.times1, times2 = rep.times2, arm = "arm") toy.rep
# To obtain the times parameter, we can apply the timesTokeep function on the same # dataframe in the wide format kept.t <- timesTokeep(toydata, id = "id", tstart = "randt", tstop = "lastdt", mes.cov = list(c("ps1", "ps2", "ps3")), time.cov = list(c("randt", "dt2", "dt3"))) # Now, we can build the long format toy.long <- wideToLongTDC(data = toydata, id = "id", tstart = "randt", tstop = "lastdt", event = "status", bas.cov = c("age", "arm", "swtrtdt"), mes.cov = list(TDconf = c("ps1", "ps2", "ps3")), time.cov = list(c("randt", "dt2", "dt3")), times = kept.t[[1]]) # Put dates in numeric format with tstart at 0 toy.long$tstart <- as.numeric(toy.long$tstart) toy.long$tstop <- as.numeric(toy.long$tstop) toy.long$swtrtdt <- as.numeric(toy.long$swtrtdt) tabi <- split(toy.long, toy.long$id) L.tabi <- length(tabi) tablist <- lapply(1:L.tabi, function(i){ refstart <- tabi[[i]]$tstart[1] tabi[[i]]$tstart <- tabi[[i]]$tstart - refstart tabi[[i]]$tstop <- tabi[[i]]$tstop - refstart tabi[[i]]$swtrtdt <- tabi[[i]]$swtrtdt - refstart return(tabi[[i]]) }) toy.long <- do.call( rbind, tablist ) # Patients are censored when initiating the other arm treatment, that is, at time swtrtdt toy.long2 <- cens.ipw(toy.long, id = "id", tstart = "tstart", tstop = "tstop", event = "event", arm = "arm", realtrt = FALSE, censTime ="swtrtdt") # We collect all event times (death for both arms and treatment censoring according to the trt arm) rep.times1 <- unique(c(toy.long2$tstop[toy.long2$cens==1 & toy.long2$arm == "A"], toy.long2$tstop[toy.long2$event==1])) rep.times2 <- unique(c(toy.long2$tstop[toy.long2$cens==1 & toy.long2$arm == "B"], toy.long2$tstop[toy.long2$event==1])) # to put times in same order as arms levels levels(toy.long2[, "arm"]) # Now, we can replicate the rows toy.rep <- replicRows(toy.long2, tstart = "tstart", tstop = "tstop", event = "event", cens = "cens", times1 = rep.times1, times2 = rep.times2, arm = "arm") toy.rep
Dataset SHIdat contains an anonymized excerpt of data from the SHIVA01 trial. This was the first randomized cli,ical trial that aimed at comparing molecularly targeted therapy based on tumour profiling (MTA) versus conventiona therapy (CT) for advanced cancer. A switch to the other arm was scheduled to be proposed at disease progression for patients in both treatment groups.
data("SHIdat")
data("SHIdat")
A data frame with 197 observations on the following 306 variables.
id
a numeric vector corresponding to the patient's identifier
bras.f
a vector containing the patient's randomized arm
agerand
a numeric vector containing patient's age (in years) at randomization
sex.f
a vector containing the patient's gender
tt_Lnum
a numeric vector containing the number of previous lines of treatment
rmh_alea.c
a numeric vector containing the Royal Marsden Hospital score segregated into two categories
pathway.f
a vector the molecular pathway altered (pathway.f: the hormone receptors pathway, the PI3K/ AKT/mTOR pathway, and the RAF/MEK pathway)
myps.v2
,ps.v3
,ps1.v1
,ps1.v2
,ps1.v3
,ps1.v4
,ps1.v5
,ps1.v6
,ps1.v7
,ps1.v8
,ps1.v9
,ps1.v10
,ps1.v11
,ps1.v12
, ps1.v13
,ps1.v14
,ps1.v15
,ps1.v16
,ps1.v17
,ps1.v18
,ps1.v19
,ps1.v20
, ps1.v21
numeric vectors containing the ECOG performance status measured at the randomization visit, the visit before the potential switch and the planned visits (maximum number of planned visits: 21)
mytran.v1
,tran.v2
,tran.v3
,tran.v4
,tran.v5
,tran.v6
,tran.v7
,tran.v8
,tran.v9
,tran.v10
,tran.v11
,tran.v12
, tran.v13
,tran.v14
,tran.v15
,tran.v16
,tran.v17
,tran.v18
,tran.v19
,tran.v20
,tran.v21
numeric vectors containing the use of platelet transfusions at each of the potential 21 planned visits
myttc.v2
,ttc.v3
,ttc1.v1
,ttc1.v2
,ttc1.v3
,ttc1.v4
,ttc1.v5
,ttc1.v6
,ttc1.v7
,ttc1.v8
,ttc1.v9
,ttc1.v10
, ttc1.v11
,ttc1.v12
,ttc1.v13
,ttc1.v14
,ttc1.v15
,ttc1.v16
,ttc1.v17
,ttc1.v18
,ttc1.v19
,ttc1.v20
, ttc1.v21
numeric vectors containing the presence of concomitant treatments at the randomization visit, the visit before the potential switch and the planned visits (maximum number of planned visits: 21)
tox.t1
,tox.t2
,tox.t3
,tox.t4
,tox.t5
,tox.t6
,tox.t7
,tox.t8
,tox.t9
,tox.t10
,tox.t11
,tox.t12
,tox.t13
,tox.t14
, tox.t15
,tox.t16
,tox.t17
,tox.t18
,tox.t19
,tox.t20
,tox.t21
,tox.t22
,tox.t23
,tox.t24
,tox.t25
,tox.t26
, tox.t27
,tox.t28
,tox.t29
,tox.t30
,tox.t31
,tox.t32
,tox.t33
,tox.t34
,tox.t35
,tox.t36
,tox.t37
,tox.t38
, tox.t39
,tox.t40
,tox.t41
,tox.t42
,tox.t43
,tox.t44
,tox.t45
,tox.t46
,tox.t47
,tox.t48
,tox.t49
,tox.t50
, tox.t51
,tox.t52
,tox.t53
,tox.t54
,tox.t55
,tox.t56
,tox.t57
,tox.t58
,tox.t59
,tox.t60
,tox.t61
,tox.t62
, tox.t63
,tox.t64
,tox.t65
,tox.t66
,tox.t67
,tox.t68
,tox.t69
,tox.t70
,tox.t71
,tox.t72
,tox.t73
,tox.t74
, tox.t75
,tox.t76
,tox.t77
,tox.t78
,tox.t79
,tox.t80
,tox.t81
,tox.t82
,tox.t83
,tox.t84
,tox.t85
,tox.t86
, tox.t87
,tox.t88
,tox.t89
,tox.t90
,tox.t91
,tox.t92
,tox.t93
,tox.t94
,tox.t95
,tox.t96
,tox.t97
,tox.t98
, tox.t99
, tox.t100
numeric vectors corresponding to the presence of an adveerse event. tox.ti
contains 1 if the patient started an adverse event linked with the treatment at datetox.ti
, 0 if the patient ended an adverse event linked with the treatment at datetox.ti
, and NA otherwise
ddn
a vector containing the date of latest news
debttCO
a vector containing the date of initiation of the other arm treatment
ddeath
a vector containg the death date
ddt.v1
a vector containing the date of initiation of the randomized treatment
datt
a vector containing the date of the interruption of the randomized treatment
dexac.v2
a vector containing the date of randomization
dexac.v3
a vector containing the date of the visit before the potential switch
dexac1.v1
,dexac1.v2
,dexac1.v3
,dexac1.v4
,dexac1.v5
,dexac1.v6
,dexac1.v7
,dexac1.v8
,dexac1.v9
, dexac1.v10
,dexac1.v11
,dexac1.v12
,dexac1.v13
,dexac1.v14
,dexac1.v15
,dexac1.v16
,dexac1.v17
, dexac1.v18
,dexac1.v19
,dexac1.v20
, dexac1.v21
vectors containing the dates of the potential 21 planned visits
datetox.t1
,datetox.t2
,datetox.t3
,datetox.t4
,datetox.t5
,datetox.t6
,datetox.t7
,datetox.t8
, datetox.t9
,datetox.t10
,datetox.t11
,datetox.t12
,datetox.t13
,datetox.t14
,datetox.t15
, datetox.t16
,datetox.t17
,datetox.t18
,datetox.t19
,datetox.t20
,datetox.t21
,datetox.t22
, datetox.t23
,datetox.t24
,datetox.t25
,datetox.t26
,datetox.t27
,datetox.t28
,datetox.t29
, datetox.t30
,datetox.t31
,datetox.t32
,datetox.t33
,datetox.t34
,datetox.t35
,datetox.t36
, datetox.t37
,datetox.t38
,datetox.t39
,datetox.t40
,datetox.t41
,datetox.t42
,datetox.t43
, datetox.t44
,datetox.t45
,datetox.t46
,datetox.t47
,datetox.t48
,datetox.t49
,datetox.t50
, datetox.t51
,datetox.t52
,datetox.t53
,datetox.t54
,datetox.t55
,datetox.t56
,datetox.t57
, datetox.t58
,datetox.t59
,datetox.t60
,datetox.t61
,datetox.t62
,datetox.t63
,datetox.t64
, datetox.t65
,datetox.t66
,datetox.t67
,datetox.t68
,datetox.t69
,datetox.t70
,datetox.t71
, datetox.t72
,datetox.t73
,datetox.t74
,datetox.t75
,datetox.t76
,datetox.t77
,datetox.t78
, datetox.t79
,datetox.t80
,datetox.t81
,datetox.t82
,datetox.t83
,datetox.t84
,datetox.t85
, datetox.t86
,datetox.t87
,datetox.t88
,datetox.t89
,datetox.t90
,datetox.t91
,datetox.t92
, datetox.t93
,datetox.t94
,datetox.t95
,datetox.t96
,datetox.t97
,datetox.t98
, datetox.t99
, datetox.t100
vectors containing the dates related to adverse events (as explained above)
CO
a vector containing 1 if the patient changed treatment arm (i.e., did a switch)
progDate
a vector containing the date of a potential progression
progStatus
a vector containing 1 if the patient did a progression (and 0 otherwise)
status
a vector containing the patient's status at the date of latest news (1 if died, 0 otherwise)
Note that some variables were built from the original data for illustration purpose. We provided an excerpt containing only the covariates that are useful for our analysis. Note also that the SHIVA data were anonymized.
Acknowledgments: we thank the patients who volunteered to participate in this study for their dedication and the study-site staff who cared for them. This work is supported by grant ANR-10-EQPX-03 from the Agence Nationale de la Recherche (Investissements d'avenir) and Site de Recherche Integre contre le Cancer (SiRIC). High-throughput sequencing was done by the NGS platform of the Institut Curie, supported by grants ANR-10-EQPX-03 and ANR-10-INBS-09-08 from the Agence Nationale de la Recherche (Investissements d'avenir) and the Canceropole Ile-de-France.
Le Tourneau, C., Delord, J. P., Goncalves, A., et al. (2015). "Molecularly targeted therapy based on tumour molecular profiling versus conventional therapy for advanced cancer (SHIVA): a multicentre, open-label, proof-of-concept, randomised, controlled phase 2 trial". The Lancet Oncology, 16(13), 1324-1334. doi : "10.1016/S1470-2045(15)00188-6"
Graffeo, N., Latouche, A., Le Tourneau C., Chevret, S. (2019) "ipcwswitch: an R package for inverse probability of censoring weighting with an application to switches in clinical trials". Computers in biology and medicine, 111, 103339. doi : "10.1016/j.compbiomed.2019.103339"
cens.ipw
, ipcw
, replicRows
, timesTokeep
, wideToLongTDC
# To obtain the times parameter, we can apply the timesTokeep function on the same # dataframe in the wide format # names of the repeated measurements vect.ps <- c("myps.v2", "ps.v3", c(paste("ps1.v", seq(1,21), sep=""))) vect.ttc <- c("myttc.v2", "ttc.v3", c(paste("ttc1.v", seq(1,21), sep=""))) vect.tran <- c("mytran.v1", paste("tran.v", seq(2,21), sep="")) # corresponding dates dates <- c("dexac.v2", "dexac.v3", c(paste("dexac1.v", seq(21), sep=""))) dates2 <- dates[!(dates %in% c("dexac.v2","dexac.v3"))] # times to keep kept.t <- timesTokeep(SHIdat, id = "id", tstart = "dexac.v2", tstop = "ddn", mes.cov = list(vect.ps, vect.ttc, vect.tran), time.cov = list(dates, dates, dates2)) # Now, we can build the long format SHIlong <- wideToLongTDC(SHIdat, id = "id", tstart = "dexac.v2", tstop = "ddn", event = "status", bas.cov = c("agerand", "sex.f","tt_Lnum", "rmh_alea.c", "pathway.f", "bras.f","debttCO","ddt.v1", "datt"), mes.cov = list(f1=vect.ps, f2=vect.ttc, f3=vect.tran), time.cov = list(dates, dates, dates2), times = kept.t[[1]]) # Put dates in numeric format with tstart at 0 tabi <- split(SHIlong, SHIlong$id) L.tabi <- length(tabi) tablist <- lapply(1:L.tabi, function(i){ refstart <- tabi[[i]]$tstart[1] tabi[[i]]$tstart <- tabi[[i]]$tstart - refstart tabi[[i]]$tstop <- tabi[[i]]$tstop - refstart tabi[[i]]$debttCO <- tabi[[i]]$debttCO - refstart # to be used in next step tabi[[i]]$ddt.v1 <- tabi[[i]]$ddt.v1 - refstart # to be used in the final step tabi[[i]]$datt <- tabi[[i]]$datt - refstart # to be used in the final step return(tabi[[i]]) }) SHIlong <- do.call( rbind, tablist ) colnames(SHIlong)[14:16] <- c("ps", "ttc", "tran") # Eliminating patient not having initiated the treatment arm SHIlong2 <- SHIlong[!is.na(SHIlong$ddt.v1),] # Patients are censored when initiating the other arm treatment, that is, at time swtrtdt SHIlong2 <- cens.ipw(SHIlong2, id = "id", tstart = "tstart", tstop = "tstop", event = "event", arm = "bras.f", realtrt = FALSE, censTime ="debttCO") # We collect all event times # (death for both arms and treatment censoring according to the trt arm) replic.times.MTA <- unique(c(SHIlong2$tstop[SHIlong2$cens == 1 & SHIlong2$bras.f == "MTA"], SHIlong2$tstop[SHIlong2$event == 1])) replic.times.CT <- unique(c(SHIlong2$tstop[SHIlong2$cens == 1 & SHIlong2$bras.f == "CT"], SHIlong2$tstop[SHIlong2$event == 1])) # to put times in same order as arms levels levels(SHIlong2[,"bras.f"]) SHIrep <- replicRows(SHIlong2, tstart = "tstart", tstop = "tstop", event = "event", cens = "cens", times1 = replic.times.MTA, times2=replic.times.CT, arm = "bras.f") # Estimation of the stabilized weights library(survival) SHIres <- ipcw(SHIrep, id = "id", tstart = tstart, tstop = tstop, cens = cens, arm = "bras.f", bas.cov = c("agerand", "sex.f", "tt_Lnum", "rmh_alea.c", "pathway.f"), conf = c("ps", "ttc", "tran"), trunc = 0.05, type = 'kaplan-meier') # To have conventional therapy (CT) as reference SHIres$bras.f <- relevel(SHIres$bras.f, ref="CT") # Using the IPCW weights in Cox likelihood... fit.stab.w <- coxph(Surv(tstart, tstop, event) ~ bras.f + agerand + sex.f + tt_Lnum + rmh_alea.c + pathway.f + cluster(id), data = SHIres, weights = SHIres$weights.trunc) fit.stab.w
# To obtain the times parameter, we can apply the timesTokeep function on the same # dataframe in the wide format # names of the repeated measurements vect.ps <- c("myps.v2", "ps.v3", c(paste("ps1.v", seq(1,21), sep=""))) vect.ttc <- c("myttc.v2", "ttc.v3", c(paste("ttc1.v", seq(1,21), sep=""))) vect.tran <- c("mytran.v1", paste("tran.v", seq(2,21), sep="")) # corresponding dates dates <- c("dexac.v2", "dexac.v3", c(paste("dexac1.v", seq(21), sep=""))) dates2 <- dates[!(dates %in% c("dexac.v2","dexac.v3"))] # times to keep kept.t <- timesTokeep(SHIdat, id = "id", tstart = "dexac.v2", tstop = "ddn", mes.cov = list(vect.ps, vect.ttc, vect.tran), time.cov = list(dates, dates, dates2)) # Now, we can build the long format SHIlong <- wideToLongTDC(SHIdat, id = "id", tstart = "dexac.v2", tstop = "ddn", event = "status", bas.cov = c("agerand", "sex.f","tt_Lnum", "rmh_alea.c", "pathway.f", "bras.f","debttCO","ddt.v1", "datt"), mes.cov = list(f1=vect.ps, f2=vect.ttc, f3=vect.tran), time.cov = list(dates, dates, dates2), times = kept.t[[1]]) # Put dates in numeric format with tstart at 0 tabi <- split(SHIlong, SHIlong$id) L.tabi <- length(tabi) tablist <- lapply(1:L.tabi, function(i){ refstart <- tabi[[i]]$tstart[1] tabi[[i]]$tstart <- tabi[[i]]$tstart - refstart tabi[[i]]$tstop <- tabi[[i]]$tstop - refstart tabi[[i]]$debttCO <- tabi[[i]]$debttCO - refstart # to be used in next step tabi[[i]]$ddt.v1 <- tabi[[i]]$ddt.v1 - refstart # to be used in the final step tabi[[i]]$datt <- tabi[[i]]$datt - refstart # to be used in the final step return(tabi[[i]]) }) SHIlong <- do.call( rbind, tablist ) colnames(SHIlong)[14:16] <- c("ps", "ttc", "tran") # Eliminating patient not having initiated the treatment arm SHIlong2 <- SHIlong[!is.na(SHIlong$ddt.v1),] # Patients are censored when initiating the other arm treatment, that is, at time swtrtdt SHIlong2 <- cens.ipw(SHIlong2, id = "id", tstart = "tstart", tstop = "tstop", event = "event", arm = "bras.f", realtrt = FALSE, censTime ="debttCO") # We collect all event times # (death for both arms and treatment censoring according to the trt arm) replic.times.MTA <- unique(c(SHIlong2$tstop[SHIlong2$cens == 1 & SHIlong2$bras.f == "MTA"], SHIlong2$tstop[SHIlong2$event == 1])) replic.times.CT <- unique(c(SHIlong2$tstop[SHIlong2$cens == 1 & SHIlong2$bras.f == "CT"], SHIlong2$tstop[SHIlong2$event == 1])) # to put times in same order as arms levels levels(SHIlong2[,"bras.f"]) SHIrep <- replicRows(SHIlong2, tstart = "tstart", tstop = "tstop", event = "event", cens = "cens", times1 = replic.times.MTA, times2=replic.times.CT, arm = "bras.f") # Estimation of the stabilized weights library(survival) SHIres <- ipcw(SHIrep, id = "id", tstart = tstart, tstop = tstop, cens = cens, arm = "bras.f", bas.cov = c("agerand", "sex.f", "tt_Lnum", "rmh_alea.c", "pathway.f"), conf = c("ps", "ttc", "tran"), trunc = 0.05, type = 'kaplan-meier') # To have conventional therapy (CT) as reference SHIres$bras.f <- relevel(SHIres$bras.f, ref="CT") # Using the IPCW weights in Cox likelihood... fit.stab.w <- coxph(Surv(tstart, tstop, event) ~ bras.f + agerand + sex.f + tt_Lnum + rmh_alea.c + pathway.f + cluster(id), data = SHIres, weights = SHIres$weights.trunc) fit.stab.w
Function to keep all event times
timesTokeep(data, id, tstart, tstop, mes.cov, time.cov)
timesTokeep(data, id, tstart, tstop, mes.cov, time.cov)
data |
dataframe containing the following variables |
id |
patient's id |
tstart |
date of the beginning of the follow-up (in Date format) |
tstop |
date of the end of the follow-up (in Date format) |
mes.cov |
list of vectors, each of them must contain the names (in character format) of the repeated measurements related to one time-dependent covariate |
time.cov |
list of vectors, each of them must contain the times (in Date format) of the date when the abovementioned measurements were done |
list of two lists, one in Date format the other in numeric format. Each of them contains, for each patient, the event time and the times of changes in time-varying covariates
Graffeo, N., Latouche, A., Le Tourneau C., Chevret, S. (2019) "ipcwswitch: an R package for inverse probability of censoring weighting with an application to switches in clinical trials". Computers in biology and medicine, 111, 103339. doi : "10.1016/j.compbiomed.2019.103339"
kept.t <- timesTokeep(toydata, id = "id", tstart = "randt", tstop = "lastdt", mes.cov = list(c("ps1", "ps2", "ps3")), time.cov = list(c("randt", "dt2", "dt3"))) # For example, for patient id=3, to obtain the kept times in Date format: kept.t[[1]][[3]] # To obtain the kept times in numeric format: kept.t[[2]][[3]]
kept.t <- timesTokeep(toydata, id = "id", tstart = "randt", tstop = "lastdt", mes.cov = list(c("ps1", "ps2", "ps3")), time.cov = list(c("randt", "dt2", "dt3"))) # For example, for patient id=3, to obtain the kept times in Date format: kept.t[[1]][[3]] # To obtain the kept times in numeric format: kept.t[[2]][[3]]
Dataset toydata contains repeated measurements made in 3 patients. It mimics randomized clinical trials data with two parallel arms with a repeated measurement of a time-varying binary covariate, which could be the time-varying confounder acting both on the survival and treatment censoring.
data("toydata")
data("toydata")
A data frame with 3 observations on the following 12 variables.
id
a numeric vector corresponding to the patient's identifier
randt
a vector containing the date of the randomization visit
lastdt
a vector containing the date of latest news
status
a numeric vector. The value equals to 1 if the patient dies at lastdt (and 0 otherwise)
age
a numeric vector containing patient’s age (in years) at randomization
ps1
a numeric vector containing the values (0 or 1) of a repeated measurement
happening on date randt
. Note that some of them could be missing
ps2
a numeric vector containing the values (0 or 1) of a repeated measurement
happening on date dt2
. Note that some of them could be missing
ps3
a numeric vector containing the values (0 or 1) of a repeated measurement
happening on date dt3
. Note that some of them could be missing
dt2
a vector containing the dates of measurement
of ps2
. Note that some of them could be missing
dt3
a vector containing the date of measurement
ps3
. Note that some of them could be missing
arm
a vector containing the patient’s randomized arm
swtrtdt
a vector containing the date when the patient initiates the other arm treatment (NA if does not happen)
Graffeo, N., Latouche, A., Le Tourneau C., Chevret, S. (2019) "ipcwswitch: an R package for inverse probability of censoring weighting with an application to switches in clinical trials". Computers in biology and medicine, 111, 103339. doi : "10.1016/j.compbiomed.2019.103339"
data(toydata) toydata
data(toydata) toydata
Function from wide to long format
wideToLongTDC( data, id, tstart, tstop, event, bas.cov, mes.cov, time.cov, times )
wideToLongTDC( data, id, tstart, tstop, event, bas.cov, mes.cov, time.cov, times )
data |
a dataframe containing the variables id, tstart, tstop, mes.cov and time.cov |
id |
the patient's id |
tstart |
date of the beginning of the follow-up (in Date format) |
tstop |
date of the end of the follow-up (in Date format) |
event |
the indicator of failure (a death is denoted by 1 at the end of the follow-up) |
bas.cov |
a vector containing the names (in character format) of the baseline covariates |
mes.cov |
a list of vectors, each of them must contain the names (in character format) of the repeated measurements related to one time-dependent covariate |
time.cov |
a list of vectors, each of them must contain the times (in Date format) of the date when the abovementioned measurements were done |
times |
a list of vectors. Each of them must contain, for each patient, the event time and the times of changes in time-varying covariates |
the long format version of the initial dataframe data. The repeated values included in each vector of the list mes.cov are aggregated in a variable named aas the name of the corresponding list member.
Graffeo, N., Latouche, A., Le Tourneau C., Chevret, S. (2019) "ipcwswitch: an R package for inverse probability of censoring weighting with an application to switches in clinical trials". Computers in biology and medicine, 111, 103339. doi : "10.1016/j.compbiomed.2019.103339"
# To obtain the times parameter, we can apply the timesTokeep function on the same # dataframe in the wide format kept.t <- timesTokeep(toydata, id = "id", tstart = "randt", tstop = "lastdt", mes.cov = list(c("ps1", "ps2", "ps3")), time.cov = list(c("randt", "dt2", "dt3"))) # Now, we can build the long format toy.long <- wideToLongTDC(data = toydata, id = "id", tstart = "randt", tstop = "lastdt", event = "status", bas.cov = c("age", "arm", "swtrtdt"), mes.cov = list(TDconf = c("ps1", "ps2", "ps3")), time.cov = list(c("randt", "dt2", "dt3")), times = kept.t[[1]]) toy.long
# To obtain the times parameter, we can apply the timesTokeep function on the same # dataframe in the wide format kept.t <- timesTokeep(toydata, id = "id", tstart = "randt", tstop = "lastdt", mes.cov = list(c("ps1", "ps2", "ps3")), time.cov = list(c("randt", "dt2", "dt3"))) # Now, we can build the long format toy.long <- wideToLongTDC(data = toydata, id = "id", tstart = "randt", tstop = "lastdt", event = "status", bas.cov = c("age", "arm", "swtrtdt"), mes.cov = list(TDconf = c("ps1", "ps2", "ps3")), time.cov = list(c("randt", "dt2", "dt3")), times = kept.t[[1]]) toy.long