# Note that this work was done in R-3.0.2 and OpenBUGS 3.2.1 rm(list=objects()) # clear workspace # load relevant libraries library(R2OpenBUGS) library(metafor) # for forest plots and classical meta-analysis ## bring in WOMAC pain week 2 data data<-read.csv("Naproxen_WOMAC_week2_b.csv",na.strings=".") # Study WPCFP SEWPCFP Flare # 1 Internal Study 1 -1.05000 0.1528635 1 # 2 Internal Study 2 -1.00000 0.2403829 0 # 3 Schnitzer et al. 2005 -1.31000 0.1550000 1 # 4 Internal Study 3 -0.85000 0.4305848 1 # 5 Internal Study 4 -0.49000 0.1938418 0 # 6 Internal Study 5 -1.47760 0.3068106 0 # 7 Internal Study 6 -0.95000 0.1531060 1 # 8 Internal Study 7 -1.00000 0.1725125 1 # 9 Internal Study 8 -1.10000 0.3288237 0 # 10 Internal Study 9 -0.83000 0.2249078 1 # 11 Internal Study 10 -0.80138 0.2253445 1 # 12 Baerwald et al. 2010 -1.23000 0.2214520 1 # 13 Schnitzer et al. 2010 -1.27000 0.2156965 1 ######################################## # Forest plot as presented in Figure 3 # ######################################## forest(data$WPCFP,data$SEWPCFP,slab=data$Study, xlab="Difference in Mean WOMAC pain for Naproxen-placebo at Week 2") text(-6, 15, "Study", cex=0.95, adj=0, font=2) text(2, 15, "Mean + 95%CI",cex=0.95, adj=0, font=2) ########################### ### Fixed effects model ### ########################### linebugs1<-function(){ for (i in 1:num) { prec.y[i] <- 1/(se_wp[i] * se_wp[i]) # define precision based on observe within study arm SEs y[i] ~ dnorm(d, prec.y[i]) # Define likelihood pred[i] ~ dnorm(d, prec.y[i]) # predictive distribution } d~dnorm(0,0.0001) # prior for treatment difference. Low precision, centred around 0 } ## Write out the model based on the "linebugs" function above write.model(linebugs1,"linemodel1.txt") ## Prepare data in list format - only keep columns that will be used within the model num=nrow(data) linedata1<-list(y=data$WPCFP,se_wp=data$SEWPCFP,num=num) ## Initial values for MCMC. ## Each random variable in the BUGS model should have an initial value. Here taking random sample from ## normal distributin lineinits1<-function(){ list(d=rnorm(1,0,2)) } ## Run the model using OpenBUGS ## debug=T opens the OpenBUGS window and allows you to review, debug, interact with the OpenBUGS run. ## Must close the OpenBUGS window to return to R. ## total iterations 10000 if which 5000 are the burnin. Posterior distributions formed from the final ## 5000 iterations. Using 3 chains (MCMC initial values) WOMAC.FE<-bugs(linedata1,lineinits1,c("d"),"linemodel1.txt",n.iter=10000,n.burnin=5000, n.chains=3,debug=T,codaPkg=F) ############################## # Random effects model # ############################## linebugs2<-function(){ for (i in 1:num) { prec.y[i] <- 1/(se_wp[i] * se_wp[i]) # define precision based on observe within study arm SEs y[i] ~ dnorm(mu[i], prec.y[i]) # define likelihood mu[i]~ dnorm(d, prec.bsv) # random effects distribution for the treatment difference. } d~dnorm(0,0.0001) # prior for treatment difference. Low precision, centred around 0 tau ~ dunif(0.0001, 20) # uniform prior for between study SD tau.sq <- tau * tau prec.bsv <- 1/(tau.sq) # define precision in terms of tau pred~dnorm(d,prec.bsv) # predictive distribution } ## Write out the model based on the "linebugs" function above write.model(linebugs2,"linemodel2.txt") ## Prepare data in list format - only keep columns that will be used within the model num=nrow(data) linedata2<-list(y=data$WPCFP,se_wp=data$SEWPCFP,num=num) ## Initial values for MCMC. ## Each random variable in the BUGS model should have an initial value # taking random samples from normal/uniform distribuion as appropriate lineinits2<-function(){ list(d=rnorm(1,0,2),tau=runif(1,0.01,20),pred=rnorm(1,0,2)) } ## Run the model using OpenBUGS ## debug=T opens the OpenBUGS window and allows you to review, debug, interact with the OpenBUGS run. ## Must close the OpenBUGS window to return to R. ## total iterations 10000 if which 5000 are the burnin. Posterior distributions formed from the final ## 5000 iterations. Using 3 chains (MCMC initial values) WOMAC.RE<-bugs(linedata2,lineinits2,c("d","tau","pred"),"linemodel2.txt",n.iter=10000,n.burnin=5000, n.chains=3,debug=T,codaPkg=F) ################# meta-regression ################ ################################################## # meta-regressin model linebugs_MR<-function(){ for (i in 1:num) { prec.y[i] <- 1/(se_wp[i] * se_wp[i]) # define precision based on observe within study arm SEs y[i] ~ dnorm(mu[i], prec.y[i]) # define likelihood mu[i]<- delta[i] + FLCOV*Flare[i] # functional form of mu[i] delta[i]~ dnorm(d,prec.bsv) # random effects distribution for the treatment difference with no flare } d~dnorm(0,0.0001) # prior for treatment difference. Low precision, centred around 0 FLCOV~dnorm(0,0.0001) # prior for 'flare' covariate. Low precision, centred around 0 tau ~ dunif(0.0001, 20) # uniform prior for between study SD tau.sq <- tau * tau prec.bsv <- 1/(tau.sq) # define precision in terms of tau pred~dnorm(d,prec.bsv) # predictive distribution } ## Write out the model based on the "linebugs" function above write.model(linebugs_MR,"linemodel_MR.txt") ## Prepare data in list format - only keep columns that will be used within the model linedata_MR<-list(y=data$WPCFP,se_wp=data$SEWPCFP,Flare=data$Flare,num=num) ## Initial values for MCMC. ## Each random variable in the BUGS model should have an initial value # taking random samples from normal/uniform distribuion as appropriate lineinits_MR<-function(){ list(d=rnorm(1,0,2),tau=runif(1,0.01,20),pred=rnorm(1,0,2),FLCOV=rnorm(1,0,2)) } ## Run the model using OpenBUGS ## debug=T opens the OpenBUGS window and allows you to review, debug, interact ## with the OpenBUGS run. ## Must close the OpenBUGS window to return to R. WOMAC.MR<-bugs(linedata_MR,lineinits_MR,c("d","tau","pred","FLCOV"),"linemodel_MR.txt",n.iter=10000,n.burnin=5000, n.chains=3,debug=T,codaPkg=F) #################################################### ## compare with classical approach using metafor # #################################################### # fixed effects analysis WP_FE <- rma(yi=WPCFP, sei=SEWPCFP, data=data, method="FE", slab=Study) funnel(WP_FE, xlab="Naproxen - placebo for mean WOMAC pain") # rank test: Begg and Mazumdar (1994) ranktest(WP_FE) # regression test - Eggers test regtest(WP_FE, model = "rma", predictor = "sei", ni = NULL) # random effects WP_RE <- rma(yi=WPCFP, sei=SEWPCFP, data=data, method="REML", slab=Study) # Get 95% confidence intervals for tau, tau^2, I^2 and H^2 confint(WP_RE) # derive prediction interval predv<-predict(WP_RE) # pred se ci.lb ci.ub cr.lb cr.ub # -1.0232 0.0725 -1.1652 -0.8811 -1.3494 -0.6970 # calculate the standard error incorporating the between study variability reml_predse <- sqrt(predv$se^2 + WP_RE$tau2) # tau2: estimate of total amount of heterogeneity # meta-regression WP_MR<-rma(yi=WPCFP, sei=SEWPCFP, mods=Flare, data=data, method="REML", slab=Study) funnel(WP_MR) plot(WP_MR) # -0.92 (-1.20, -0.63) # FLARE: -0.14 (-0.47, 0.18) # tau: 0.1371 ####################################################################### # forest plot with classical and Bayesian estimates on the same plot. # ####################################################################### # pull out relevant summary statistics fe_summ<-WOMAC.FE$summary # print out fe_summ # mean sd 2.5% 25% 50% 75% 97.5% Rhat n.eff #d -1.025216 0.05697417 -1.136 -1.064 -1.026 -0.98670 -0.9132925 1.001054 13000 #deviance 3.271001 1.42959277 2.262 2.368 2.721 3.60625 7.3762498 1.001005 15000 fe_est<-fe_summ[1,1] # row 1 column 1 [1,1] =-1.025216 fe_se<-fe_summ[1,2] # row 1 column 1 [1,2] =0.05697417 #Random effects re_summ<-WOMAC.RE$summary # print out re_summ # mean sd 2.5% 25% 50% 75% 97.5% Rhat n.eff #d -1.0245208 0.0792181 -1.184000000 -1.0740000 -1.02400 -0.9751 -0.8689000 1.001031 24000 #tau 0.1661245 0.0978066 0.009971948 0.0967875 0.15675 0.2226 0.3881025 1.032181 340 #pred -1.0253628 0.2083730 -1.459000000 -1.1300000 -1.02300 -0.9219 -0.5862900 1.000960 30000 #deviance -2.3352140 4.3680104 -10.160000000 -5.6880000 -2.49550 1.0160 5.9210750 1.002111 1700 re_est<-re_summ[1,1] # row 1, column 1 [1,1]=-1.0245208 re_se<-re_summ[1,2] # row 1, column 2 [1,2]=0.0792181 ## prediction interval: repred<-re_summ[3,1] # row 3, column 1 [3,1]=-1.0253628 re_pred_se<-re_summ[3,2] # row 3, column 2 [3,2]=0.2083730 # forest plot of original data with BUGS estimates # use forest function with the addpoly function to add the classical and Bayesian estimates forest(WP_FE, order=rev(order(data$WPCFP)), at=-3:1, ylim=c(-7,16), refline=0, xlab="Mean Difference", mlab="Frequentist fixed effects estimate") text(-4.5, 15, "Study", cex=0.95, adj=0, font=2) text(1, 15, "Mean + 95%CI",cex=0.95, adj=0, font=2) # add REML estimate and CI addpoly(x=coef(summary(WP_RE))$estimate, sei=coef(summary(WP_RE))$se, row=-2,col="red", mlab="Frequentist random effects estimate",cex=1) # add REML estimate and prediction interval addpoly(x=coef(summary(WP_RE))$estimate, sei=reml_predse, row=-3,col="blue",mlab="Frequentist prediction interval",cex=1) # add BUGS FE estimate and CI addpoly(x=fe_est, sei=fe_se, row=-5,col="black",mlab="Bayesian fixed effects estimate",cex=1) # add BUGS RE estimate and CI addpoly(x=re_est, sei=re_se, row=-6,col="red",mlab="Bayesian random effects estimate",cex=1) # add BUGS RE prediction interval addpoly(x=repred, sei=re_pred_se, row=-7,col="blue",mlab="Bayesian prediction interval",cex=1) # Note old R.12 and earlier use coef(WP_RE)$estimate # now need to use coef(summary(WP_RE))$estimate