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(
prostateDeath ~ rx * (dtime + I(dtime ^ 2) + I(dtime ^ 3)) + normalAct + ageCat + hx + hgBinary ,
data = longProstRed,
family = binomial())
### Pooled logistic regression for death due to other causes
plrFitO <-
glm(
otherDeath ~ dtime + I(dtime ^ 2) + normalAct + ageCat + hx + hgBinary + rx ,
data = longProstRed,
family = binomial())
### Pooled logistic regression for censoring after time 50
temp50 <- longProstRed[longProstRed$dtime > 50,]
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
longProstRed$predC <-
rep(1, dim(longProstRed)[1]) # The probability of *not* being censored is 1 for all t <= 50
longProstRed$predC[longProstRed$dtime > 50] <- # update this probability from time 50 and onwards
1 - predict(plrFitC, newdata = temp50, type = 'response')
### Numerator
longProstRed$predCnum <-
rep(1, dim(longProstRed)[1])
longProstRed$predCnum [longProstRed$dtime > 50] <-
1 - predict(plrFitCnum, newdata = temp50, type = 'response')
predC <- longProstRed$predC
predCnum <- longProstRed$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
weights_cens <- 1 / cumPredC
### Stabilized weights
weights_cens_stab <- cumPredCnum / cumPredC| 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
weights_compev <- 1 / cumPredO
weights_compev_stab <-
cumPredOnum / cumPredO- 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_de <- weights_cens * weights_compev
weights_de_stab <- weights_cens_stab * weights_compev_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) {
outputHazards <- rep(NA, length.out = length(cutTimes))
counter <- 1
for (i in cutTimes) {
if (outcomeProstate) {
indices <-
inputdata$dtime == i &
inputdata$rx == grp &
inputdata$eventCens == 0 & inputdata$otherDeath == 0
eventIndicator <- indices & inputdata$prostateDeath == 1
} else{
indices <-
inputdata$dtime == i & inputdata$rx == grp & inputdata$eventCens == 0
eventIndicator <- indices & inputdata$otherDeath == 1
}
outputHazards[counter] <-
sum(weightVector[eventIndicator]) / sum(weightVector[indices])
counter <- counter + 1
}
return(outputHazards)
}
nonParametricCumInc <- function(hazard1, hazard2, competing = FALSE) {
inc <- rep(NA, length.out = length(cutTimes))
cumulativeSurvival <- c(1, cumprod((1 - hazard1) * (1 - hazard2)))
counter <- 1
for (i in 1:length(cutTimes)) {
if (!competing) {
inc[i] <- hazard1[i] * (1 - hazard2[i]) * cumulativeSurvival[i]
} else{
inc[i] <- hazard1[i] * cumulativeSurvival[i]
}
}
cumInc <- cumsum(inc)
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)
Treated_de_hazardO <- rep(0, length.out = (length(cutTimes)))
cumIncTreated_de <-
nonParametricCumInc(Treated_de_hazardP, Treated_de_hazardO)
#### Stabilized
Treated_de_hazardPs <-
nonParametricCumHaz(
weights_de_stab,
inputdata = longProstRed,
grp = 1,
outcomeProstate = TRUE)
Treated_de_hazardOs <- rep(0, length.out = (length(cutTimes)))
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
)
Placebo_de_hazardO <- rep(0, length.out = (length(cutTimes)))
cumIncPlacebo_de <-
nonParametricCumInc(Placebo_de_hazardP, Placebo_de_hazardO)
#### Stabilized
Placebo_de_hazardPs <-
nonParametricCumHaz(
weights_de_stab,
inputdata = longProstRed,
grp = 0,
outcomeProstate = TRUE
)
Placebo_de_hazardOs <- rep(0, length.out = (length(cutTimes)))
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_60 <- cumIncTreated_de[length(cutTimes)]
cumIncPlacebo_de_60 <- cumIncPlacebo_de[length(cutTimes)]
de_rr <- cumIncTreated_de_60 / cumIncPlacebo_de_60
de_rd <- cumIncTreated_de_60 - cumIncPlacebo_de_60
results_de <- data.frame(cumIncTreated_de_60, cumIncPlacebo_de_60, de_rr, de_rd)
knitr::kable(round(results_de, 2)) | cumIncTreated_de_60 | cumIncPlacebo_de_60 | de_rr | de_rd |
|---|---|---|---|
| 0.36 | 0.37 | 0.97 | -0.01 |
## Stabilized
cumIncTreated_des_60 <- cumIncTreated_des[length(cutTimes)]
cumIncPlacebo_des_60 <- cumIncPlacebo_des[length(cutTimes)]
des_rr <- cumIncTreated_des_60 / cumIncPlacebo_des_60
des_rd <- cumIncTreated_des_60 - cumIncPlacebo_des_60
results_des <- data.frame(cumIncTreated_des_60, cumIncPlacebo_des_60, des_rr, des_rd)
knitr::kable(round(results_des, 2)) | cumIncTreated_des_60 | cumIncPlacebo_des_60 | des_rr | des_rd |
|---|---|---|---|
| 0.36 | 0.37 | 0.97 | -0.01 |
- Cumulative incidence curves
plot(
cutTimes, cumIncTreated_de, type = "s",
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_60 <- cumIncTreated_te[length(cutTimes)]
cumIncPlacebo_te_60 <- cumIncPlacebo_te[length(cutTimes)]
te_rr <- cumIncTreated_te_60 / cumIncPlacebo_te_60
te_rd <- cumIncTreated_te_60 - cumIncPlacebo_te_60
results_te <- data.frame(cumIncTreated_te_60, cumIncPlacebo_te_60, te_rr, te_rd)
knitr::kable(round(results_te, 2))| cumIncTreated_te_60 | cumIncPlacebo_te_60 | te_rr | te_rd |
|---|---|---|---|
| 0.22 | 0.28 | 0.78 | -0.06 |
- Cumulative incidence curves
plot(
cutTimes, cumIncTreated_te, type = "s",
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_60 <- cumIncTreated_te_comp[length(cutTimes)]
cumIncPlacebo_te_comp_60 <- cumIncPlacebo_te_comp[length(cutTimes)]
te_comp_rr <- cumIncTreated_te_comp_60 / cumIncPlacebo_te_comp_60
te_comp_rd <- cumIncTreated_te_comp_60 - cumIncPlacebo_te_comp_60
results_te_comp <- data.frame(cumIncTreated_te_comp_60, cumIncPlacebo_te_comp_60, te_comp_rr, te_comp_rd)
knitr::kable(round(results_te_comp, 2))| 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,
cumIncTreated_te_comp, type = "s",
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.
longProstRed$Orx <- longProstRed$rx- Fit conditional pooled logistic regression models
plrFitP <-
glm(
prostateDeath ~ rx*(dtime + I(dtime ^ 2)+ I(dtime ^ 3)) + normalAct + ageCat + hx + hgBinary,
data = longProstRed,
family = binomial()
)
plrFitO <-
glm(
otherDeath ~ Orx * (dtime + I(dtime ^ 2) + I(dtime ^ 3)) + normalAct + ageCat + hx + hgBinary,
data = longProstRed,
family = binomial()
)- Create three copies of the data. Data set construction where Ay and Ad = 1
treated <-
baseline[rep(1:n, each = length(cutTimes)), ] #One row for each time
treated$dtime <- rep(cutTimes, n)
treated$rx <- 1
treated$Orx <- 1- Data set construction where Ay and Ad = 0
placebo <-
baseline[rep(1:n, each = length(cutTimes)), ] #One row for each time
placebo$dtime <- rep(cutTimes, n)
placebo$rx <- 0
placebo$Orx <- 0- Dataset construction where Ay = 1, Ad = 0
treatAy <-
baseline[rep(1:n, each = length(cutTimes)), ]
treatAy$dtime <- rep(cutTimes, n)
treatAy$rx <- 1
treatAy$Orx <- 0- Calculate hazards for each time interval in the three cloned data sets
## For Ay = 1 and Ad = 1
treated$hazardP <-
predict(plrFitP, newdata = treated, type = 'response')
treated$hazardO <-
predict(plrFitO, newdata = treated, type = 'response')
treated$s <- (1 - treated$hazardP) * (1 - treated$hazardO)
## For Ay = 0, Ad = 0
placebo$hazardP <-
predict(plrFitP, newdata = placebo, type = 'response')
placebo$hazardO <-
predict(plrFitO, newdata = placebo, type = 'response')
placebo$s <- (1 - placebo$hazardP) * (1 - placebo$hazardO)
## For Ay = 1, Ad = 0
treatAy$hazardP <-
predict(plrFitP, newdata = treatAy, type = 'response')
treatAy$hazardO <-
predict(plrFitO, newdata = treatAy, type = 'response')
treatAy$s <- (1 - treatAy$hazardP) * (1 - treatAy$hazardO)- Calculate weights for censoring for lost to follow-up
plrFitC <-
glm(
eventCens ~ Orx* (dtime + I(dtime ^ 2) + I(dtime ^ 3)) + normalAct + ageCat +
hx + hgBinary,
data = longProstRed,
family = binomial()
)
predC <- 1 - predict(plrFitC, newdata = longProstRed, type = 'response')
# 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)
predOa0 <- compWeightsO$predOa0
predOa1 <- compWeightsO$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
ipw_d <- rep(NA, length.out = length(cum_pred_C))
# index time zeros
t0 <- longProstRed$prostateDeath == 0
ipw_d <- cum_pred_O_1 / cum_pred_O_0
ipw_d <- cum_pred_O_1 / cum_pred_O_0
ipw_cens <- 1 / cum_pred_C
ipw_sep_eff <- ipw_d / cum_pred_CLast, we will use the function discrete_cuminc_prost,
from the utility_functions script available in this
repository.
discrete_cuminc_prost <- function(weight_vector, inputdata, grp=0, outcome_y=TRUE,follow_up=1:max_time){
event_vec <- rep(NA, length.out=length(follow_up))
counter <- 1
# count number of individuals in grp (that is, we cound those who were present at baseline)
n_grp <- sum(inputdata$dtime==0 & inputdata$rx==grp)
for(i in follow_up){
if(outcome_y){
indices <- inputdata$dtime==i & inputdata$rx == grp & inputdata$eventCens==0 & inputdata$otherDeath==0
eventIndicator <- indices & inputdata$prostateDeath==1
}else{
indices <- inputdata$dtime==i & inputdata$rx == grp & inputdata$eventCens==0
eventIndicator <- indices & inputdata$otherDeath==1
}
event_vec[counter] <- sum(weight_vector[eventIndicator]) / n_grp
counter <- counter+1
}
output_cuminc <- cumsum(event_vec)
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)
knitr::kable(round(estimatesFullData[36,], 2))| 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