Bayesian reanalysis of clinical trials
# Adapted from code by Dan Lane, pr_in prob of interest
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)
)
留言
張貼留言