Code
library(EValue)
library(ggplot2)
library(tidyverse)
library(magrittr)
library(kableExtra)library(EValue)
library(ggplot2)
library(tidyverse)
library(magrittr)
library(kableExtra)HR <- 0.57
LCL <- 0.33
UCL <- 0.97In an analysis with missing data handled via complete case analysis, the M-value indicates how strongly a factor related to missingness would need to be associated with both treatment assignment and PFS to push the “true” PFS HR to null. It is expressed on the relative risk scale, but it can be approximately compared with hazard ratios for context.
m_value_df <- as.data.frame(evalues.HR(est = HR, lo = LCL, hi = UCL, true = 1, rare = FALSE)) %>%
set_rownames(c("RR", "M-value")) %>%
slice(2) %>%
select(point, upper) %>%
rename(
`Point estimate` = point,
`Upper 95% CI limit` = upper
)
m_val_est <- m_value_df %>%
pull(`Point estimate`)
m_val_UCL <- m_value_df %>%
pull(`Upper 95% CI limit`)
m_value_df %>%
kbl(digits=2) %>%
kable_material("striped", "hover")| Point estimate | Upper 95% CI limit | |
|---|---|---|
| M-value | 2.31 | 1.17 |
Among the subgroups analyzed, only LDH ≤185 U/L had an association with PFS stronger than the M-value point estimate, suggesting that the association between TP53 mutation status and PFS is robust to missing data bias. On the other hand, the M-value’s 95% CI upper bound of 1.17 was modest, indicating that a relatively weak confounder for missingness could push the “true” upper confidence bound to the null.
# Simulation
HRasRR <- toRR(est = HR(HR, rare=FALSE), rare = FALSE)
bias_factor <- function(RR_EU, RR_UD) {
(RR_EU * RR_UD) / (RR_EU + RR_UD - 1)
}
RR_EU_seq <- seq(1, 2, .01)
RR_UD <- toRR(HR(5, rare=FALSE), rare=FALSE)
# Create data frame of results
df <- data.frame(
RR_EU = RR_EU_seq
) %>%
mutate(
RR_UD = RR_UD,
HRasRR = HRasRR,
BF = bias_factor(RR_EU, RR_UD),
true_HR = case_when(
HRasRR <1 ~ HRasRR * BF,
HRasRR >=1 ~ HRasRR / BF
)
)# Cross point
# Find point where true_HR crosses 1 (closest match)
cross_point <- df[which.min(abs(df$true_HR - 1)), ]# Plot
df %>%
ggplot(aes(x = as.numeric(RR_EU), y = as.numeric(true_HR))) +
geom_line(color = "blue", linewidth = 1) +
geom_hline(yintercept = 1, linetype = "dashed", color = "red") +
geom_vline(xintercept = cross_point$RR_EU, linetype = "dotted", color = "darkgreen") +
geom_point(data = cross_point, aes(x = RR_EU, y = true_HR), color = "black", size = 3) +
annotate("text",
x = cross_point$RR_EU - 0.125,
y = 1,
label = paste0("Risk Ratio = ", round(cross_point$RR_EU, 2)),
vjust = -1, hjust = 0.5) +
labs(
x = "Association of Missingness-Related Confounder with Treatment Arm, Risk Ratio",
y = "'True' TP53 Mutation PFS HR\nCorrected for Missingness-Related Confounding",
title = "'True' TP53 Mutation PFS HR",
subtitle = "Dashed red line = Null effect ('True' HR = 1)"
) +
theme_minimal()A confounder associated with both missing TP53 mutation status and PFS (assumed PFS HR=5) would need to be almost twice as common in one treatment arm than in the other to reduce the true TP53 mutation PFS HR point estimate to null. This scenario is exceedingly unlikely in a randomized controlled trial like SYMPATICO. Thus, missing data bias does not likely explain the favorable impact of ibrutinib-venetoclax over ibrutinib monotherapy in the TP53-mutated subgroup.
HR_UCLasRR <- toRR(est = HR(UCL, rare=FALSE), rare = FALSE)
# Create data frame of results
df_UCL <- data.frame(
RR_EU = RR_EU_seq
) %>%
mutate(
RR_UD = RR_UD,
HR_UCLasRR = HR_UCLasRR,
BF = bias_factor(RR_EU, RR_UD),
true_HR_UCL = case_when(
HRasRR <1 ~ HR_UCLasRR * BF,
HRasRR >=1 ~ HR_UCLasRR / BF
)
)
# Find point where true_HR crosses 1 (closest match)
cross_point_UCL <- df_UCL[which.min(abs(df_UCL$true_HR_UCL - 1)), ] %>%
pull(RR_EU)A confounder associated with both missing TP53 mutation status and PFS (assumed PFS HR=5) would only need to be about 1.03x as common in one treatment arm than in the other to push the true TP53 mutation PFS HR upper confidence bound to null. This degree of imbalance could occur in a randomized controlled trial like SYMPATICO and so this sensitivity analysis calls for caution in interpreting the subgroup analysis 95% CI upper bound since missing data bias could conceivably push it to null.