Bayesian reanalysis of clinical trials

 # Adapted from code by Dan Lane, pr_in prob of interest

https://benjamin-andrew.shinyapps.io/andromeda_shock_bayesian/?fbclid=IwAR1qHXH4TdjT6h1APC0IS07tXcmRO-36UKvSMb_h8NRzH82TLw8zXXYqToo&mibextid=Zxz2cZ

https://discourse.datamethods.org/t/bayesian-analysis-of-rct-data/1997/2?fbclid=IwZXh0bgNhZW0BMQABHVaVaDWAQl1XtzqVr4byQFje4WB3C_SbZC2u7b-rnv8OAJyaK1agsDF3fQ_aem_AWodvwieeBCpXTYGtS2vQ-psFnk549y7FLjaM9SCDRRLJJ6A1T-kRsYS2Hg-p9pEPyY

library(tidyverse)

library(RColorBrewer)

# Estimate Type Labels

est_type <- 1 # 1: HR, 2: OR, 3: RR

short_lab <- ifelse(est_type == 1, "HR", ifelse(est_type == 2, "OR", "RR"))

long_lab <- ifelse(est_type == 1, "Hazard Ratio", ifelse(est_type == 2, "Odds Ratio", "Risk Ratio"))

# hr_in HR of interest or MCID, pr_in prob of MCID

pt_est <- 0.5

upper_ci <- 0.9

ci_width <- 0.95

likelihood_p <- (1 - ((1 - ci_width) / 2))

hr_a <- 10

hr_b <- 30

se_hr <- NA

se_or <- NA

or_a <- 10

or_b <- 30

trt_n <- 50

ctrl_n <- 50

or_c <- trt_n - or_a

or_d <- ctrl_n - or_b

theta_in <- 1

sd_in <- 0.42

hr_in <- 0.5

pr_in <- 0.05

prior_theta <- log(theta_in)

prior_sd <- sd_in

# Calculate Likelihood Parameters

likelihood_theta <- ifelse(est_type == 1, log(pt_est),

                           ifelse(est_type == 2, log(((or_a + 0.5) * (or_d + 0.5)) / ((or_b + 0.5) * (or_c + 0.5))),

                                  log((or_a / (or_a + or_c)) / (or_b / (or_b + or_d)))))

likelihood_sd <- ifelse(est_type == 1, sqrt((1 / hr_a) + (1 / hr_b)),

                        ifelse(est_type == 2, sqrt((1 / (or_a + 0.5)) + (1 / (or_b + 0.5)) + (1 / (or_c + 0.5)) + (1 / (or_d + 0.5))),

                               sqrt((or_c / (or_a * (or_a + or_c))) + (or_d / (or_b * (or_b + or_d))))))

# Calculate Posterior Parameters

post_theta <- ((prior_theta / (prior_sd)^2) + (likelihood_theta / likelihood_sd^2)) / 

  ((1 / (prior_sd)^2) + (1 / likelihood_sd^2))

post_sd <- sqrt(1 / ((1 / (prior_sd)^2) + (1 / likelihood_sd^2)))

# Plot data

x <- seq(-5, 3, by = 0.01)

prior_plot <- dnorm(x, prior_theta, prior_sd)

likelihood_plot <- dnorm(x, likelihood_theta, likelihood_sd)

posterior_plot <- dnorm(x, post_theta, post_sd)

plot_data <- tibble(

  x = rep(x, 3)

) %>%

  mutate(

    dist = rep(c("prior", "likelihood", "posterior"), each = nrow(.) / 3),

    y = c(prior_plot, likelihood_plot, posterior_plot),

    x = exp(x),

    y = exp(y)

  )

# Max xlim

max_x <- max(likelihood_theta + (exp(likelihood_theta) * 1.5), 2)

# Credible interval

ci_in <- 89

lower_cred <- round(exp(qnorm((1 - (ci_in/100)) / 2, post_theta, post_sd)), 2)

upper_cred <- round(exp(qnorm(1 - (1 - (ci_in/100)) / 2, post_theta, post_sd)), 2)

mid_cred <- round(exp(qnorm(0.5, post_theta, post_sd)), 2)

# Colors

like_col <- brewer.pal(3, "Dark2")[1]

post_col <- brewer.pal(3, "Dark2")[2]

prior_col <- brewer.pal(3, "Dark2")[3]

# Plot

ggplot(plot_data, aes(x = x, y = y, group = dist)) + 

  geom_vline(xintercept = 1, linetype = "dashed",

             color = "grey50", alpha = 0.75, size = 0.75) + 

  geom_line(aes(color = dist), size = 1.1) + 

  scale_color_brewer(name = NULL, type = "qual", palette = "Dark2",

                     breaks = c("likelihood", "prior", "posterior"),

                     labels = c("Likelihood", "Prior", "Posterior")) + 

  xlim(0, max_x) + 

  labs(

    x = long_lab,

    y = "Probability Density"

  ) + 

  annotate(geom = "text",

           label = paste("Posterior probability ", short_lab,

                         paste(" < 1: ", 

                               round(pnorm(log(1), post_theta, post_sd, 

                                           lower.tail = TRUE), 3), sep = ""), sep = ""),

           x = max_x, y = max(plot_data$y), hjust = 1,

           fontface = "bold") + 

  annotate(geom = "text",

           label = paste("Posterior median (", ci_in,

                         paste("% credible interval): ",

                               mid_cred,

                               paste(" (", lower_cred, sep = ""),

                         paste(", ", upper_cred, sep = ""),

                         paste(")", sep = ""), sep = ""), sep = ""),

           x = max_x, y = max(plot_data$y) - (2 * max(plot_data$y)/25), hjust = 1,

           fontface = "bold") + 

  theme_classic() + 

  theme(

    legend.position = "bottom",

    text = element_text(family = "Gill Sans MT"),

    axis.ticks.y = element_blank(),

    axis.text.y = element_blank(),

    axis.title = element_text(size = 15),

    axis.text = element_text(size = 12),

    legend.text = element_text(size = 15)

  )

留言

這個網誌中的熱門文章

Bayesian reanalysis of ORBITA

Bayesian reanalysis with pymc3

Bayesian reanalysis of Apolipoprotein A1 Infusions