Using Bayesian Methods to Augment the Interpretation of Critical Care Trials. An Overview of Theory and Example Reanalysis of the Alveolar Recruitment for Acute Respiratory Distress Syndrome Trial 20
#### Bayesian priors ####
##### LOAD PACKAGES ####
library(tidyverse)
library(insight)
library(bayestestR)
library(cowplot)
library(brms)
library(broom)
library(parameters)
####Analysis for ART — LR and Flat Prior####
#Traditional LR:
db$dead<-as.factor(ifelse(db$death==”yes”,1,0))
art.lr<-glm(dead~group,family=”binomial”,data=db) summary(art.lr)
exp(confint(art.lr))
#Flat prior analysis
flat_prior<-prior(normal(0,1000), class = “b”) art.flat <- brm(
dead ~ group,
data = db,
prior = flat_prior,
family = “bernoulli”,
seed = 123 # Adding a seed makes results reproducible.
)
#Uses insight package to sample posteriors
posteriors <- insight::get_parameters(art.flat,iterations=10^5)
#Summarizes the flat prior analysis art.flat.summary<-summary(art.flat) mean_eff<-art.flat.summary$fixed[2,1] mean_sd<-art.flat.summary$fixed[2,2]
#Some summaries using for plot legend any_harm<-sum(posteriors$b_groupART>0)/nrow(posteriors)
severe_harm<-sum(posteriors$b_groupART>log(1.25))/nrow(posteriors)
rope1<-sum(posteriors$b_groupART<log(1.1)|posteriors$b_groupART<log(1/1.1))/nrow(posteriors)
#Figure 1
temp.plot<-ggplot(posteriors, aes(x = b_groupART)) + geom_density()
p <- ggplot_build(temp.plot) # < — — INSTEAD OF `p <- print(m)`
plot.data<-p$data[[1]][,c(1,2)]
plot.data
fig1<-ggplot(plot.data, aes(x = x,y=y,group=1)) +
geom_line(size=1) +
geom_area(mapping = aes(x = ifelse(x>0, x, 0)), fill = “#FFB266") + geom_area(mapping = aes(x = ifelse(x<0, x, 0)), fill = “lightblue”) + geom_area(mapping = aes(x = ifelse(x>log(1.25), x, 0)), fill = “#FF9933") + geom_segment(inherit.aes = FALSE,
data=subset(plot.data,x>log(1/1.1)&x<log(1.1))[seq(1, nrow(subset(plot.data,x>log(1/1.1)&x<log(1.1))), 5), ],
aes(x=x,y=0,xend=x,yend=y))+ geom_vline(xintercept=0, color=”black”, linetype=1)+ geom_vline(xintercept=log(1.25), color=”#FF9933", linetype=1)+ geom_hline(yintercept=0,color=”black”,linetype=1)+ theme_cowplot()+
labs(x=”log(OR)”,y=””)+
scale_x_continuous(expand = c(0, 0),labels=seq(-0.2,0.6,by=0.1),breaks=seq(-0.2,0.6,by=0.1)) + scale_y_continuous(expand = c(0, 0))+
coord_cartesian(xlim=c(-0.25,0.75),ylim=c(0,3.5))+
annotate(“text”,x=0.35,y=3.2,label=paste0(“P(severe harm) = “,round(severe_harm,2),” “,sprintf(‘\u21d2')))+ annotate(“text”,x=0.1,y=3.2,label=paste0(“P(harm) = “,round(any_harm,2),” “,sprintf(‘\u21d2')))+ annotate(“text”,x=-0.1,y=3.2,label=paste0(sprintf(‘\u21d0'),” “,”P(benefit) = “,1-round(any_harm,2)))+
# annotate(“rect”, xmin = -0.06, xmax = 0.06, ymin = 0.06, ymax = 0.18,fill=”white”)+ annotate(“label”,x=0,y=0.1,label=paste0(“ROPE =”,
round(sum(posteriors$b_groupART<log(1.1)|posteriors$b_groupART<log(1/1.1))/nrow(posteriors),2)))
#Defining priors for Table 1 — Checks the probability for given values. You can play around if you want.
#Neutral Moderate: N(0,0.355) pnorm(log(2),mean = 0,sd=0.355)
#Neutral strong: N(0,0.205) pnorm(log(1.5),mean = 0,sd=0.205)
#Optimistic Weak: N(-0.41,0.77) pnorm(0,mean = log(0.66),sd=0.77)
#Optimistic Moderate: N(-0.41,0.40) pnorm(0,mean = log(0.66),sd=0.40)
#Optimistic Strong: N(-0.41,0.253) pnorm(0,mean = log(0.66),sd=0.253)
#Pessimistic Weak: N(0.41,0.77) pnorm(0,mean = -log(0.66),sd=0.77)
#Optimistic Moderate: N(0.41,0.40) pnorm(0,mean = -log(0.66),sd=0.40)
#Optimistic Strong: N(0.41,0.253) pnorm(0,mean = -log(0.66),sd=0.253)
#Beginning of ART Reanalysis
#Priors
m1priors <- prior(normal(0,.355), class = “b”) #Moderate strength skeptical prior
m2priors <- prior(normal(-0.4155,0.40), class = “b”)#Moderate strength optimistic prior
m3priors <- prior(normal(0.4155,0.80), class = “b”) #Weak strength skeptical prior
#Neutral prior m1 <- brm(
death ~ group,
data = db,
prior = m1priors,
family = “bernoulli”,
seed = 123 # Adding a seed makes results reproducible.
)
#Optimistic prior
m2 <- brm(
death ~ group, data = db,
prior = m2priors,
family = “bernoulli”,
seed = 123 # Adding a seed makes results reproducible.
)
#Pessimistic prior
m3 <- brm(
death ~ group,
data = db,
prior = m3priors,
family = “bernoulli”,
seed = 123 # Adding a seed makes results reproducible.
)
#Group results in a data frame
results<-as.data.frame(rbind(model_parameters(m1,ci = 0.95,exponentiate = FALSE,rope_range = c(-0.1,0.1)),
model_parameters(m2,ci = 0.95,exponentiate = FALSE,rope_range = c(-0.1,0.1)), model_parameters(m3,ci = 0.95,exponentiate = FALSE,rope_range = c(-0.1,0.1)))[c(2,4,6),])
posteriors.m1 <- insight::get_parameters(m1)[,2] posteriors.m2 <- insight::get_parameters(m2)[,2] posteriors.m3 <- insight::get_parameters(m3)[,2]
posterior.list<-list(posteriors.m1,posteriors.m2,posteriors.m3) map(posterior.list,~sum(.>log(1.25))/length(.)) map(posterior.list,~(quantile(exp(.),probs = c(0.025,0.5,0.975))))
#Plotting priors and posteriors
panelA<-ggplot(data = data.frame(x = c(-2, 2)), aes(x)) +
stat_function(fun = dnorm, n = 1000, args = list(mean = 0, sd = .355),linetype=2)+ stat_function(fun = dnorm, n = 1000, args = list(mean = summary(m1)$fixed[2,1],
sd = summary(m1)$fixed[2,2]),linetype=1)+ geom_area(stat = “function”, fun = dnorm,
args = list(mean = summary(m1)$fixed[2,1], sd = summary(m1)$fixed[2,2]),
fill = “darkgray”, xlim = c(log(1.25), 1.5),alpha=0.9)+ geom_area(stat = “function”, fun = dnorm,
args = list(mean = summary(m1)$fixed[2,1], sd = summary(m1)$fixed[2,2]),
fill = “gray”, xlim = c(log(1/1.1), log(1.1)),alpha=0.7)+ geom_vline(xintercept=0, color=”black”, linetype=1)+ geom_vline(xintercept=log(1.25), color=”black”, linetype=3)+ scale_x_continuous(expand = c(0, 0)) + scale_y_continuous(expand = c(0, 0))+ theme_minimal()+
labs(x=”log(OR)”,y=””)
panelB<-ggplot(data = data.frame(x = c(-2, 2)), aes(x)) +
stat_function(fun = dnorm, n = 1000, args = list(mean = -0.4155, sd = .42),linetype=2)+ stat_function(fun = dnorm, n = 1000, args = list(mean = summary(m2)$fixed[2,1],
sd = summary(m2)$fixed[2,2]),linetype=1)+ geom_area(stat = “function”, fun = dnorm,
args = list(mean = summary(m2)$fixed[2,1], sd = summary(m2)$fixed[2,2]),
fill = “darkgray”, xlim = c(log(1.25), 1.5),alpha=0.9)+ geom_area(stat = “function”, fun = dnorm,
args = list(mean = summary(m2)$fixed[2,1], sd = summary(m2)$fixed[2,2]),
fill = “gray”, xlim = c(log(1/1.1), log(1.1)),alpha=0.7)+ geom_vline(xintercept=0, color=”black”, linetype=1)+ geom_vline(xintercept=log(1.25), color=”black”, linetype=3)+ scale_x_continuous(expand = c(0, 0)) + scale_y_continuous(expand = c(0, 0))+ theme_minimal()+
labs(x=”log(OR)”,y=””)
panelC<-ggplot(data = data.frame(x = c(-2, 2)), aes(x)) +
stat_function(fun = dnorm, n = 1000, args = list(mean = 0.44, sd = .77),linetype=2)+ stat_function(fun = dnorm, n = 1000, args = list(mean = summary(m3)$fixed[2,1],
sd = summary(m3)$fixed[2,2]),linetype=1)+ geom_area(stat = “function”, fun = dnorm,
args = list(mean = summary(m3)$fixed[2,1], sd = summary(m3)$fixed[2,2]),
fill = “darkgray”, xlim = c(log(1.25), 1.5),alpha=0.9)+ geom_area(stat = “function”, fun = dnorm,
args = list(mean = summary(m3)$fixed[2,1], sd = summary(m3)$fixed[2,2]),
fill = “gray”, xlim = c(log(1/1.1), log(1.1)),alpha=0.7)+ geom_vline(xintercept=0, color=”black”, linetype=1)+ geom_vline(xintercept=log(1.25), color=”black”, linetype=3)+ scale_x_continuous(expand = c(0, 0)) + scale_y_continuous(expand = c(0, 0))+ theme_minimal()+
labs(x=”log(OR)”,y=””)
####Bayesian Metanalysis####
library(bayesmeta)
y<-c(summary(m1)$fixed[2,1],summary(m2)$fixed[2,1],summary(m3)$fixed[2,1]) sigma<-c(summary(m1)$fixed[2,2],summary(m2)$fixed[2,2],summary(m3)$fixed[2,2])
l1<-c(“Neutral”,”Optimistic”,”Pessimistic”)
meta1<-bayesmeta(y=y, sigma=sigma,mu.prior=c(0,0.355), label=l1,tau.prior = “DuMouchel”)
plot(meta1,which=1) plot(meta1,which=2,prior=TRUE)
plot(meta1,which=3,main=””,prior = TRUE) plot(meta1,which=4,main=””,prior = TRUE)
meta1_recorded<-forest(meta1,trans=exp, refline=1, xlab=”Odds ratio”) meta1_recorded<-as.data.frame(meta1_recorded) meta1_recorded$name<-rownames(meta1_recorded) meta1_recorded<-meta1_recorded[-5,] colnames(meta1_recorded)<-c(“Low”,”Est”,”High”,”name”) meta1_recorded<-ggplot(meta1_recorded,aes(x=Est,y=name))+
geom_point()+ geom_errorbarh(aes(xmin=Low,xmax=High),height=0)+ coord_cartesian(xlim=c(-0.5,1))+ geom_vline(xintercept=0,linetype=2)+ theme_minimal()+
labs(x=”log(OR); 95% CrI”,y=””)
meta1$I2(tau=0.1) meta1$summary[2,1]
dens.res<-data.frame(tau=seq(0,0.3,length.out = 1000), i2=meta1$I2(seq(0,0.3,length.out = 1000)))
meta2_recorded<-ggplot(dens.res,aes(x=tau,y=i2,group=1))+ geom_line()+ geom_vline(xintercept=meta1$summary[2,1],linetype=2)+ geom_hline(yintercept=meta1$I2(meta1$summary[2,1]),linetype=2)+ theme_minimal()%+replace%theme(panel.grid = element_blank(),
panel.grid.major = element_blank(),
legend.position = “”)+ labs(x=”Tau”,y=”I2")+
labs(subtitle = paste0(“For median Tau, “,
round(meta1$I2(meta1$summary[2,1])*100,2),
“%\nof heterogeneity is explained by priors”))
plot_grid(meta1_recorded,meta2_recorded,
labels=c(“A”,”B”), nrow=1)
留言
張貼留言