Direct, total and separable effects, using inverse probability weighting (IPW)
Note: Most of the code in this tutorial is written in R base, to mimic the original code from the published papers (see References). Dr. Elena Dudukina has a version of this code in R tidyverse here.
Conditional pooled logistic models
- First, we run a set of conditional pooled logistic models, both as a first step to calculate the risk of prostate cancer death, and to calculate weights for death due to other causes, and weights for censoring due to loss to follow-up
### Pooled logistic regression for prostate cancer death (this will be needed in the next section)
<-
plrFitP glm(
~ rx * (dtime + I(dtime ^ 2) + I(dtime ^ 3)) + normalAct + ageCat + hx + hgBinary ,
prostateDeath data = longProstRed,
family = binomial())
### Pooled logistic regression for death due to other causes
<-
plrFitO glm(
~ dtime + I(dtime ^ 2) + normalAct + ageCat + hx + hgBinary + rx ,
otherDeath data = longProstRed,
family = binomial())
### Pooled logistic regression for censoring after time 50
<- longProstRed[longProstRed$dtime > 50,]
temp50
<-
plrFitC glm(eventCens ~ normalAct + ageCat + hx + rx,
data = temp50,
family = binomial())
- Fit models for the numerators in the stabilized weights corresponding to death due to other causes, and for censoring
<-
plrFitCnum glm(eventCens ~ rx , data = temp50, family = binomial())
<-
plrFitOnum glm(otherDeath ~ dtime + I(dtime ^ 2) + rx,
data = longProstRed,
family = binomial())
Weights calculation
Calculate weights for censoring due to loss to follow-up
### Denominator
$predC <-
longProstRedrep(1, dim(longProstRed)[1]) # The probability of *not* being censored is 1 for all t <= 50
$predC[longProstRed$dtime > 50] <- # update this probability from time 50 and onwards
longProstRed1 - predict(plrFitC, newdata = temp50, type = 'response')
### Numerator
$predCnum <-
longProstRedrep(1, dim(longProstRed)[1])
$predCnum [longProstRed$dtime > 50] <-
longProstRed1 - predict(plrFitCnum, newdata = temp50, type = 'response')
<- longProstRed$predC
predC
<- longProstRed$predCnum predCnum
- Glimpse of data:
patno | dtime | predC | predCnum |
---|---|---|---|
8 | 44 | 1.000000 | 1.0000000 |
8 | 45 | 1.000000 | 1.0000000 |
8 | 46 | 1.000000 | 1.0000000 |
8 | 47 | 1.000000 | 1.0000000 |
8 | 48 | 1.000000 | 1.0000000 |
8 | 49 | 1.000000 | 1.0000000 |
8 | 50 | 1.000000 | 1.0000000 |
8 | 51 | 0.963553 | 0.9693252 |
8 | 52 | 0.963553 | 0.9693252 |
8 | 53 | 0.963553 | 0.9693252 |
8 | 54 | 0.963553 | 0.9693252 |
8 | 55 | 0.963553 | 0.9693252 |
8 | 56 | 0.963553 | 0.9693252 |
8 | 57 | 0.963553 | 0.9693252 |
8 | 58 | 0.963553 | 0.9693252 |
8 | 59 | 0.963553 | 0.9693252 |
- Calculate the cumulative probability over time:
<-
cumPredC unlist(aggregate(predC ~ longProstRed$patno, FUN = cumprod)$predC,
use.names = F)
<-
cumPredCnum unlist(aggregate(predCnum ~ longProstRed$patno, FUN = cumprod)$predC,
use.names = F)
- Glimpse of data:
patno | dtime | predC | predCnum | cumPredC |
---|---|---|---|---|
8 | 44 | 1.000000 | 1.0000000 | 1.0000000 |
8 | 45 | 1.000000 | 1.0000000 | 1.0000000 |
8 | 46 | 1.000000 | 1.0000000 | 1.0000000 |
8 | 47 | 1.000000 | 1.0000000 | 1.0000000 |
8 | 48 | 1.000000 | 1.0000000 | 1.0000000 |
8 | 49 | 1.000000 | 1.0000000 | 1.0000000 |
8 | 50 | 1.000000 | 1.0000000 | 1.0000000 |
8 | 51 | 0.963553 | 0.9693252 | 0.9635530 |
8 | 52 | 0.963553 | 0.9693252 | 0.9284343 |
8 | 53 | 0.963553 | 0.9693252 | 0.8945956 |
8 | 54 | 0.963553 | 0.9693252 | 0.8619902 |
8 | 55 | 0.963553 | 0.9693252 | 0.8305733 |
8 | 56 | 0.963553 | 0.9693252 | 0.8003013 |
8 | 57 | 0.963553 | 0.9693252 | 0.7711327 |
8 | 58 | 0.963553 | 0.9693252 | 0.7430272 |
8 | 59 | 0.963553 | 0.9693252 | 0.7159460 |
- Calculate unstabilized and stabilized weights
### Unstabilized weights
<- 1 / cumPredC
weights_cens
### Stabilized weights
<- cumPredCnum / cumPredC weights_cens_stab
patno | dtime | predC | predCnum | cumPredC | weights_cens | weights_cens_stab |
---|---|---|---|---|---|---|
8 | 44 | 1.000000 | 1.0000000 | 1.0000000 | 1.000000 | 1.000000 |
8 | 45 | 1.000000 | 1.0000000 | 1.0000000 | 1.000000 | 1.000000 |
8 | 46 | 1.000000 | 1.0000000 | 1.0000000 | 1.000000 | 1.000000 |
8 | 47 | 1.000000 | 1.0000000 | 1.0000000 | 1.000000 | 1.000000 |
8 | 48 | 1.000000 | 1.0000000 | 1.0000000 | 1.000000 | 1.000000 |
8 | 49 | 1.000000 | 1.0000000 | 1.0000000 | 1.000000 | 1.000000 |
8 | 50 | 1.000000 | 1.0000000 | 1.0000000 | 1.000000 | 1.000000 |
8 | 51 | 0.963553 | 0.9693252 | 0.9635530 | 1.037826 | 1.005991 |
8 | 52 | 0.963553 | 0.9693252 | 0.9284343 | 1.077082 | 1.012017 |
8 | 53 | 0.963553 | 0.9693252 | 0.8945956 | 1.117824 | 1.018080 |
8 | 54 | 0.963553 | 0.9693252 | 0.8619902 | 1.160106 | 1.024178 |
8 | 55 | 0.963553 | 0.9693252 | 0.8305733 | 1.203988 | 1.030314 |
8 | 56 | 0.963553 | 0.9693252 | 0.8003013 | 1.249529 | 1.036486 |
8 | 57 | 0.963553 | 0.9693252 | 0.7711327 | 1.296794 | 1.042695 |
8 | 58 | 0.963553 | 0.9693252 | 0.7430272 | 1.345846 | 1.048941 |
8 | 59 | 0.963553 | 0.9693252 | 0.7159460 | 1.396753 | 1.055225 |
Calculate unstabilized and stabilized weights for death from other causes
### Denominator
<-
predO 1 - predict(plrFitO, newdata = longProstRed, type = 'response')
### Numerator
<-
predOnum 1 - predict(plrFitOnum, newdata = longProstRed, type = 'response')
### Calculate cumulative probability
<-
cumPredO unlist(aggregate(predO ~ longProstRed$patno, FUN = cumprod)$predO,
use.names = F)
<-
cumPredOnum unlist(aggregate(predOnum ~ longProstRed$patno, FUN = cumprod)$predO,
use.names = F)
### Weight calculation
<- 1 / cumPredO
weights_compev
<-
weights_compev_stab / cumPredO cumPredOnum
- Glimpse of data
patno | dtime | cumPredO | cumPredOnum | weights_compev | weights_compev_stab |
---|---|---|---|---|---|
487 | 0 | 0.9892248 | 0.9816935 | 1.010893 | 0.9923866 |
487 | 1 | 0.9787493 | 0.9641208 | 1.021712 | 0.9850538 |
487 | 2 | 0.9685558 | 0.9472325 | 1.032465 | 0.9779844 |
487 | 3 | 0.9586275 | 0.9309829 | 1.043158 | 0.9711624 |
487 | 4 | 0.9489487 | 0.9153301 | 1.053798 | 0.9645728 |
487 | 5 | 0.9395048 | 0.9002352 | 1.064391 | 0.9582018 |
487 | 6 | 0.9302818 | 0.8856621 | 1.074943 | 0.9520364 |
487 | 7 | 0.9212666 | 0.8715776 | 1.085462 | 0.9460645 |
- Multiply weights for censoring and for death due to other causes
<- weights_cens * weights_compev
weights_de
<- weights_cens_stab * weights_compev_stab weights_de_stab
- Assess weights
summary(weights_de)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.003 1.112 1.266 1.484 1.542 74.950
summary(weights_de_stab)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.4028 0.8615 0.9733 1.0156 1.0681 31.7854
Direct effect estimation
In this section and the following ones, we will apply the
nonParametricCumHaz
and nonParametricCumInc
functions from the utility_functions
script available in
this repository. These functions are necessary to calculate hazards and
cumulative incidence. Link
The functions look like this:
<-
nonParametricCumHaz function(weightVector,
inputdata,
grp,outcomeProstate = TRUE) {
<- rep(NA, length.out = length(cutTimes))
outputHazards <- 1
counter for (i in cutTimes) {
if (outcomeProstate) {
<-
indices $dtime == i &
inputdata$rx == grp &
inputdata$eventCens == 0 & inputdata$otherDeath == 0
inputdata<- indices & inputdata$prostateDeath == 1
eventIndicator else{
} <-
indices $dtime == i & inputdata$rx == grp & inputdata$eventCens == 0
inputdata<- indices & inputdata$otherDeath == 1
eventIndicator
}<-
outputHazards[counter] sum(weightVector[eventIndicator]) / sum(weightVector[indices])
<- counter + 1
counter
}return(outputHazards)
}
<- function(hazard1, hazard2, competing = FALSE) {
nonParametricCumInc <- rep(NA, length.out = length(cutTimes))
inc <- c(1, cumprod((1 - hazard1) * (1 - hazard2)))
cumulativeSurvival <- 1
counter for (i in 1:length(cutTimes)) {
if (!competing) {
<- hazard1[i] * (1 - hazard2[i]) * cumulativeSurvival[i]
inc[i] else{
} <- hazard1[i] * cumulativeSurvival[i]
inc[i]
}
}<- cumsum(inc)
cumInc return(cumInc)
}
Following equation (37) from Young et al. Statistics in Medicine. 2020.
### Calculate cumulative hazards and cumulative incidence for the treated arm
#### Unstabilized
<-
Treated_de_hazardP nonParametricCumHaz(
weights_de,inputdata = longProstRed,
grp = 1,
outcomeProstate = TRUE)
<- rep(0, length.out = (length(cutTimes)))
Treated_de_hazardO
<-
cumIncTreated_de nonParametricCumInc(Treated_de_hazardP, Treated_de_hazardO)
#### Stabilized
<-
Treated_de_hazardPs nonParametricCumHaz(
weights_de_stab,inputdata = longProstRed,
grp = 1,
outcomeProstate = TRUE)
<- rep(0, length.out = (length(cutTimes)))
Treated_de_hazardOs
<-
cumIncTreated_des nonParametricCumInc(Treated_de_hazardPs, Treated_de_hazardOs)
### Calculate cumulative hazards and cumulative incidence for the placebo arm
#### Unstabilized
<-
Placebo_de_hazardP nonParametricCumHaz(
weights_de,inputdata = longProstRed,
grp = 0,
outcomeProstate = TRUE
)
<- rep(0, length.out = (length(cutTimes)))
Placebo_de_hazardO
<-
cumIncPlacebo_de nonParametricCumInc(Placebo_de_hazardP, Placebo_de_hazardO)
#### Stabilized
<-
Placebo_de_hazardPs nonParametricCumHaz(
weights_de_stab,inputdata = longProstRed,
grp = 0,
outcomeProstate = TRUE
)
<- rep(0, length.out = (length(cutTimes)))
Placebo_de_hazardOs
<-
cumIncPlacebo_des nonParametricCumInc(Placebo_de_hazardPs, Placebo_de_hazardOs)
- Risks under each treatment arm at 60 months of follow-up, risk difference and risk ratio
## Unstabilized
<- cumIncTreated_de[length(cutTimes)]
cumIncTreated_de_60
<- cumIncPlacebo_de[length(cutTimes)]
cumIncPlacebo_de_60
<- cumIncTreated_de_60 / cumIncPlacebo_de_60
de_rr
<- cumIncTreated_de_60 - cumIncPlacebo_de_60
de_rd
<- data.frame(cumIncTreated_de_60, cumIncPlacebo_de_60, de_rr, de_rd)
results_de
::kable(round(results_de, 2)) knitr
cumIncTreated_de_60 | cumIncPlacebo_de_60 | de_rr | de_rd |
---|---|---|---|
0.36 | 0.37 | 0.97 | -0.01 |
## Stabilized
<- cumIncTreated_des[length(cutTimes)]
cumIncTreated_des_60
<- cumIncPlacebo_des[length(cutTimes)]
cumIncPlacebo_des_60
<- cumIncTreated_des_60 / cumIncPlacebo_des_60
des_rr
<- cumIncTreated_des_60 - cumIncPlacebo_des_60
des_rd
<- data.frame(cumIncTreated_des_60, cumIncPlacebo_des_60, des_rr, des_rd)
results_des
::kable(round(results_des, 2)) knitr
cumIncTreated_des_60 | cumIncPlacebo_des_60 | des_rr | des_rd |
---|---|---|---|
0.36 | 0.37 | 0.97 | -0.01 |
- Cumulative incidence curves
plot(
type = "s",
cutTimes, cumIncTreated_de, ylim = c(0, 1), ylab = "Risk", xlab = "Month",
lty = 1, lwd = 1, xlim = c(0, 60),
cex.lab = 1.2, cex.main = 1.2,
main = c(
paste("Risk of prostate cancer death"),
paste("under elimination of competing events")
)
)lines(
cutTimes,
cumIncPlacebo_de,type = "s", col = 2, ylim = c(0, 1), lwd = 1)
legend(
"topleft", c("Treatment", "Placebo"),
col = c(1, 2, 1, 2),
lty = c(1, 1, 2, 2),
cex = 1.2, pt.cex = 1.2, lwd = 2)
Total effect estimation.
For this effect, we will only use the unstabilized weights we
calculated for censoring due to loss to follow-up
weights_cens
, but using weights_cens_stab
is
possible as well.
Following equation (40) from Young et al. Statistics in Medicine. 2020.
### Calculate hazards and cumulative incidence for the treated arm
<-
Treated_te_hazardP nonParametricCumHaz(
weights_cens,inputdata = longProstRed,
grp = 1,
outcomeProstate = TRUE)
<-
Treated_te_hazardO nonParametricCumHaz(
weights_cens,inputdata = longProstRed,
grp = 1,
outcomeProstate = FALSE)
<-
cumIncTreated_te nonParametricCumInc(Treated_te_hazardP, Treated_te_hazardO)
### Calculate cumulative hazards and cumulative incidence for the placebo arm
<-
Placebo_te_hazardP nonParametricCumHaz(
weights_cens,inputdata = longProstRed,
grp = 0,
outcomeProstate = TRUE)
<-
Placebo_te_hazardO nonParametricCumHaz(
weights_cens,inputdata = longProstRed,
grp = 0,
outcomeProstate = FALSE)
<-
cumIncPlacebo_te nonParametricCumInc(Placebo_te_hazardP, Placebo_te_hazardO)
- Risks under each treatment arm at 60 months of follow-up, risk difference and risk ratio
<- cumIncTreated_te[length(cutTimes)]
cumIncTreated_te_60
<- cumIncPlacebo_te[length(cutTimes)]
cumIncPlacebo_te_60
<- cumIncTreated_te_60 / cumIncPlacebo_te_60
te_rr
<- cumIncTreated_te_60 - cumIncPlacebo_te_60
te_rd
<- data.frame(cumIncTreated_te_60, cumIncPlacebo_te_60, te_rr, te_rd)
results_te
::kable(round(results_te, 2)) knitr
cumIncTreated_te_60 | cumIncPlacebo_te_60 | te_rr | te_rd |
---|---|---|---|
0.22 | 0.28 | 0.78 | -0.06 |
- Cumulative incidence curves
plot(
type = "s",
cutTimes, cumIncTreated_te, ylim = c(0, 1), ylab = "Risk", xlab = "Month",
lty = 1, lwd = 1, xlim = c(0, 60),
cex.lab = 1.2, cex.main = 1.2,
main = c(
paste("Risk of prostate cancer death"),
paste("without elimination of competing events")
)
)lines(
cutTimes,
cumIncPlacebo_te,type = "s", col = 2, ylim = c(0, 1), lwd = 1)
legend(
"topleft", c("Treatment", "Placebo"),
col = c(1, 2, 1, 2), lty = c(1, 1, 2, 2),
cex = 1.2, pt.cex = 1.2, lwd = 2)
Total effect on death for other causes
We will use the hazards obtained for the total effect, from the previous section.
<-
cumIncTreated_te_comp nonParametricCumInc(Treated_te_hazardO, Treated_te_hazardP, competing = TRUE)
<-
cumIncPlacebo_te_comp nonParametricCumInc(Placebo_te_hazardO, Placebo_te_hazardP, competing = TRUE)
- Risks under each treatment arm at 60 months of follow-up, risk difference and risk ratio
<- cumIncTreated_te_comp[length(cutTimes)]
cumIncTreated_te_comp_60
<- cumIncPlacebo_te_comp[length(cutTimes)]
cumIncPlacebo_te_comp_60
<- cumIncTreated_te_comp_60 / cumIncPlacebo_te_comp_60
te_comp_rr
<- cumIncTreated_te_comp_60 - cumIncPlacebo_te_comp_60
te_comp_rd
<- data.frame(cumIncTreated_te_comp_60, cumIncPlacebo_te_comp_60, te_comp_rr, te_comp_rd)
results_te_comp
::kable(round(results_te_comp, 2)) knitr
cumIncTreated_te_comp_60 | cumIncPlacebo_te_comp_60 | te_comp_rr | te_comp_rd |
---|---|---|---|
0.51 | 0.43 | 1.19 | 0.08 |
- Cumulative incidence curves
plot(
cutTimes,type = "s",
cumIncTreated_te_comp, ylim = c(0, 1), ylab = "Risk", xlab = "Month",
lty = 1, lwd = 1, xlim = c(0, 60),
cex.lab = 1.2, cex.main = 1.2,
main = c(
paste("Risk of other causes of death (the competing event)")
))
lines(
cutTimes,
cumIncPlacebo_te_comp,type = "s", col = 2, ylim = c(0, 1), lwd = 1)
legend(
"topleft", c("Treatment", "Placebo"),
col = c(1, 2, 1, 2), lty = c(1, 1, 2, 2),
cex = 1.2, pt.cex = 1.2, lwd = 2)
Separable effects
Following equation (11) from Stensrud et al. Journal of the American Statistical Association. 2020
To this matter, we will use the long format data set prepared before:
longProstRed
.
- Make one extra copy of the exposure
rx
, namedOrx
, to be used in the hazard of death due to other causes.
$Orx <- longProstRed$rx longProstRed
- Fit conditional pooled logistic regression models
<-
plrFitP glm(
~ rx*(dtime + I(dtime ^ 2)+ I(dtime ^ 3)) + normalAct + ageCat + hx + hgBinary,
prostateDeath data = longProstRed,
family = binomial()
)
<-
plrFitO glm(
~ Orx * (dtime + I(dtime ^ 2) + I(dtime ^ 3)) + normalAct + ageCat + hx + hgBinary,
otherDeath data = longProstRed,
family = binomial()
)
- Create three copies of the data. Data set construction where Ay and Ad = 1
<-
treated rep(1:n, each = length(cutTimes)), ] #One row for each time
baseline[
$dtime <- rep(cutTimes, n)
treated
$rx <- 1
treated
$Orx <- 1 treated
- Data set construction where Ay and Ad = 0
<-
placebo rep(1:n, each = length(cutTimes)), ] #One row for each time
baseline[
$dtime <- rep(cutTimes, n)
placebo
$rx <- 0
placebo
$Orx <- 0 placebo
- Dataset construction where Ay = 1, Ad = 0
<-
treatAy rep(1:n, each = length(cutTimes)), ]
baseline[
$dtime <- rep(cutTimes, n)
treatAy
$rx <- 1
treatAy
$Orx <- 0 treatAy
- Calculate hazards for each time interval in the three cloned data sets
## For Ay = 1 and Ad = 1
$hazardP <-
treatedpredict(plrFitP, newdata = treated, type = 'response')
$hazardO <-
treatedpredict(plrFitO, newdata = treated, type = 'response')
$s <- (1 - treated$hazardP) * (1 - treated$hazardO)
treated
## For Ay = 0, Ad = 0
$hazardP <-
placebopredict(plrFitP, newdata = placebo, type = 'response')
$hazardO <-
placebopredict(plrFitO, newdata = placebo, type = 'response')
$s <- (1 - placebo$hazardP) * (1 - placebo$hazardO)
placebo
## For Ay = 1, Ad = 0
$hazardP <-
treatAypredict(plrFitP, newdata = treatAy, type = 'response')
$hazardO <-
treatAypredict(plrFitO, newdata = treatAy, type = 'response')
$s <- (1 - treatAy$hazardP) * (1 - treatAy$hazardO) treatAy
- Calculate weights for censoring for lost to follow-up
<-
plrFitC glm(
~ Orx* (dtime + I(dtime ^ 2) + I(dtime ^ 3)) + normalAct + ageCat +
eventCens + hgBinary,
hx data = longProstRed,
family = binomial()
)
<- 1 - predict(plrFitC, newdata = longProstRed, type = 'response')
predC
# Create a new data frame with predicted hazard estimates from treated and
<-
weightFrame data.frame(
dtime = treated$dtime,
patno = treated$patno,
predOa1 = (1 - placebo$hazardO),
predOa0 = (1 - treated$hazardO)
)
<-
compWeightsO merge(longProstRed,
weightFrame,by = c('patno', 'dtime'),
all.x = TRUE, sort = FALSE)
<- compWeightsO$predOa0
predOa0
<- compWeightsO$predOa1
predOa1
<-
cum_pred_O_0 unlist(aggregate(predOa0 ~ compWeightsO$patno, FUN = cumprod)$predOa0,
use.names = F) #unlist because aggregate creates list
<-
cum_pred_O_1 unlist(aggregate(predOa1 ~ compWeightsO$patno, FUN = cumprod)$predOa1,
use.names = F) #unlist because aggregate creates list
<-
cum_pred_C unlist(aggregate(predC ~ compWeightsO$patno, FUN = cumprod)$predC,
use.names = F) #unlist because aggregate creates list
<- rep(NA, length.out = length(cum_pred_C))
ipw_d
# index time zeros
<- longProstRed$prostateDeath == 0
t0
<- cum_pred_O_1 / cum_pred_O_0
ipw_d
<- cum_pred_O_1 / cum_pred_O_0
ipw_d
<- 1 / cum_pred_C
ipw_cens
<- ipw_d / cum_pred_C ipw_sep_eff
Last, we will use the function discrete_cuminc_prost
,
from the utility_functions
script available in this
repository.
<- function(weight_vector, inputdata, grp=0, outcome_y=TRUE,follow_up=1:max_time){
discrete_cuminc_prost <- rep(NA, length.out=length(follow_up))
event_vec <- 1
counter # count number of individuals in grp (that is, we cound those who were present at baseline)
<- sum(inputdata$dtime==0 & inputdata$rx==grp)
n_grp for(i in follow_up){
if(outcome_y){
<- inputdata$dtime==i & inputdata$rx == grp & inputdata$eventCens==0 & inputdata$otherDeath==0
indices <- indices & inputdata$prostateDeath==1
eventIndicator else{
}<- inputdata$dtime==i & inputdata$rx == grp & inputdata$eventCens==0
indices <- indices & inputdata$otherDeath==1
eventIndicator
}<- sum(weight_vector[eventIndicator]) / n_grp
event_vec[counter] <- counter+1
counter
}<- cumsum(event_vec)
output_cuminc return(output_cuminc)
}
<-
cumIncTreatAyIPW discrete_cuminc_prost(ipw_sep_eff, longProstRed, grp = 1, follow_up = cutTimes)
<-
cumIncTreatedIPW discrete_cuminc_prost(ipw_cens, longProstRed, grp = 1, follow_up = cutTimes)
<-
cumIncPlaceboIPW discrete_cuminc_prost(ipw_cens, longProstRed, grp = 0, follow_up = cutTimes)
<-
estimatesFullData data.frame(cumIncTreatedIPW, cumIncTreatAyIPW, cumIncPlaceboIPW)
::kable(round(estimatesFullData[36,], 2)) knitr
cumIncTreatedIPW | cumIncTreatAyIPW | cumIncPlaceboIPW | |
---|---|---|---|
36 | 0.14 | 0.15 | 0.2 |
- Cumulative incidence curves
plot(cutTimes,cumIncTreatedIPW, type="s",ylim=c(0,1), ylab="Cumulative incidence",
xlab="Months",lty=1,lwd=1,xlim=c(0,52))
lines(cutTimes,cumIncPlaceboIPW, type="s",col=2,ylim=c(0,1),lwd=1,lty=1)
lines(cutTimes,cumIncTreatAyIPW, type="s",col=3,ylim=c(0,1),lwd=1,lty=1)
legend(x=0,y=1, c(expression('Pr('*'Y'['k+1']^{"a"*'=1'} *'=1' * ')' ),expression('Pr('*'Y'['k+1']^{"a"['Y']*'=1' * ' , ' * "a"['D']*'=0'} *'=1' * ')' ),expression('Pr('*'Y'['k+1']^{"a"*'=0'} *'=1' * ')' )),bty = "n",
col=c(1,3,2), lty=c(1,1,1),cex=1,pt.cex=1,lwd=1)
References
Young JG, Stensrud MJ, Tchetgen Tchetgen EJ, Hernán MA. A causal framework for classical statistical estimands in failure time settings with competing events. Statistics in Medicine 2020. Paper link Code
Stensrud MJ, Young JG, Didelez V, Robins JM, Hernán MA. Separable Effects for Causal Inference in the Presence of Competing Events. Journal of the American Statistical Association 2022. Paper link
Rojas-Saunero LP, Young JG, Didelez V, Ikram MA, Swanson SA. Considering questions before methods in dementia research with competing events and causal goals. American Journal of Epidemiology. 2023. Paper link Code