You are on page 1of 9

####Tutorial 8: Fixed and Random Effects for Odd Ratio/Risk Ratio with Preferred

Binary Input####
# Loading library (if not yet)
library(metafor)
library(xlsx)

# Read excel data, print it


MindfulDat<- read.xlsx("C:\\Users\\Surya Dila\\Desktop\\R tutorial M
Brannick\\8\\Mindful.xlsx", sheetName = "Sheet1")
MindfulDat

# Meta analysis of binary data (preferred format), print it


MindfulRes1 <- rma(ai=A, bi=B, ci=C, di=D, measure="OR", method="DL",
data=MindfulDat)
MindfulRes1
MindfulRes2 <- rma(ai=A, bi=B, ci=C, di=D, measure="RR", method="DL",
data=MindfulDat)
MindfulRes2

# Meta analysis when one or more zero value in 2x2 cells (Three choices: leave it
alone (reported as missing), add small value to all cells (ex: add 0.5 to all
cells), or add small value only to zero value cell)
MindfulRes3 <- rma(ai=A, bi=B, ci=C, di=D, measure="OR", method="DL", add=.5, to=
"all", data=MindfulDat)
MindfulRes3
MindfulRes4 <- rma(ai=A, bi=B, ci=C, di=D, measure="OR", method="DL", add=.5, to=
"only0", data=MindfulDat)
MindfulRes4
MindfulRes5 <- rma(ai=A, bi=B, ci=C, di=D, measure="OR", method="REML", add=.5, to=
"only0", data=MindfulDat)
MindfulRes5
MindfulRes6 <- rma(ai=A, bi=B, ci=C, di=D, measure="OR", method="FE", add=.5, to=
"only0", data=MindfulDat)
MindfulRes6

####Tutorial 9: Basic Confidence and Prediction Interval####


# Loading library (if not yet)
library(metafor)
library(xlsx)

# Formula for Higgins Prediction Interval


Higgins.PI <- function(M, Tausq, SEM, k){
df1 <- k-2
SEPI <- sqrt(Tausq+SEM^2)
PI.lb <- M-qt(.975, df=df1)*SEPI
PI.ub <- M+qt(.975, df=df1)*SEPI
cbind(PI.lb,PI.ub)
}

# Read excel data, print it


McNattDat <- read.xlsx("C:\\Users\\Surya Dila\\Desktop\\R tutorial M
Brannick\\9\\McNattData.xlsx", sheetName="Data")
McNattDat

# Generic Meta Analysis, print it


McNattRes1 <- rma(yi=d, vi=v, method="DL", data=McNattDat)
McNattRes1

# Confidence Interval for REVC (Random Effect Variance Component)


confint(McNattRes1)

# Prediction Interval for REVC


predict(McNattRes1)

# Prediction Interval using Higgins formula (input the value based on the results
of previous analysis)
Higgins.PI(M, tausq, SEM, k)

####Tutorial 10: Moderators Analysis (categorical/continues covariates)####


# Load libray (if not yet)
library(metafor)
library(xlsx)

# Read excel data, print it


McLeodDat <- read.xlsx("C:\\Users\\Surya Dila\\Desktop\\R tutorial M Brannick\\3
and 10\\McLeod2007.xlsx", sheetName = "Data")
McLeodDat

# Meta analysis, print it


# Correlation
McLeodRes1 <- rma(ni=N, ri=r, method="DL", measure="ZCOR", data=McLeodDat)
McLeodRes1
# Introducing categorical covariate, Dx to the model [the R code for categorical
covariate >> factor()]
McLeodRes2 <- rma(ni=N, ri=r, method="DL", measure="ZCOR", mods = ~factor(Dx),
data=McLeodDat)
McLeodRes2
# Knapp and Hartung adjustment
McLeodRes3 <- rma(ni=N, ri=r, method="DL", measure="ZCOR", mods = ~factor(Dx),
knha=TRUE, data=McLeodDat)
McLeodRes3

# Omnibus test for moderator (analog to R-square in regression)


McLeodRes4 <- rma(ni=N, ri=r, method="DL", measure="ZCOR", mods = ~factor(Dx)-1,
knha=TRUE, data=McLeodDat)
McLeodRes4

# Introducing continues covariate, Age (no need special identification in writing R


code)
McLeodRes5 <- rma(ni=N, ri=r, method="DL", measure="ZCOR", mods=~factor(Dx)+Age,
data=McLeodDat)
McLeodRes5

####Tutorial 11: Funnel Plots (ordinary, trim and fill)####


# Load library, (if not yet)
library(metafor)
library(xlsx)

# Read, print McDaniel data (I think it is with McLeod data, so load McLeod excel
file first if below code is not work)
dat.mcdaniel1994

# Meta Analysis of Correlation using ZCOR, print it


McDanielRes1 <- rma(ri=ri, ni=ni, method="DL", measure="ZCOR",
data=dat.mcdaniel1994)
McDanielRes1

# Ordinary funnel plot & prediction interval


funnel(McDanielRes1)
predict(McDanielRes1)

# Trim and fill, trim & fill funnel plot, prediction interval, print it
McDanielRes2 <- trimfill(McDanielRes1)
McDanielRes2
funnel(McDanielRes2)
predict(McDanielRes2)

# Meta Analysis of Correlation using COR, print it


McDanielRes3 <- rma(ri=ri, ni=ni, method="DL", measure="COR",
data=dat.mcdaniel1994)
McDanielRes3
funnel(McDanielRes3)
predict(McDanielRes3)
# Notice that the funnel plot indicating more heterogeneity
McDanielRes4 <- trimfill(McDanielRes3)
McDanielRes4
funnel(McDanielRes4)
predict(McDanielRes4)

####Tutorial 12: Forest Plots (Ordinary, sorted, moderator, cumulative)####


# Load library (if not yet)
library(metafor)
library(xlsx)

# EXAMPLE 1
# Load excel file of McLeod, print it
McLeodDat <- read.xlsx("C:\\Users\\Surya Dila\\Desktop\\R tutorial M Brannick\\3
and 10\\McLeod2007.xlsx", sheetName = "Data")
McLeodDat

# Meta analysis, print it


McLeodRes1 <- rma(ni=N, ri=r, method="DL", measure="ZCOR", data=McLeodDat)
McLeodRes1

# Forest plot (unsorted format)


forest(McLeodRes1)

# Sorted by the effect size (in this case, r), print it


McLeod.ES <- McLeodDat[order(McLeodDat$r), ]
McLeod.ES

# Meta analysis with ordered data, print it (overall summary should be the same, of
course!)
McLeodRes2 <- rma(ni=N, ri=r, method="DL", measure="ZCOR", data=McLeod.ES)
McLeodRes2

# Forest plot (sorted by r)


forest(McLeodRes2)

# Sorted by precision (v)


McLeod.V <- McLeodDat[order(McLeodDat$v), ]
McLeod.V
McLeodRes3 <- rma(ri=r, ni=N, method="DL", measure="ZCOR", data=McLeod.V)
forest(McLeodRes3)

# Sorted by moderator (example, Dx), then ES, test for moderator; forest by
moderator & ES (with test results)
McLeod.Dx.ES <- McLeodDat[order(McLeodDat$Dx,McLeodDat$r), ]
McLeodRes4 <- rma(ni=N, ri=r, method="DL", measure="ZCOR", mods=~factor(Dx),
data=McLeod.ES)
McLeodRes4

# EXAMPLE 2
# Load libray (if not yet)
library(metafor)
library(xlsx)

# Load Rock excel file, print it


RocksDat <- read.xlsx("C:\\Users\\Surya Dila\\Desktop\\CMA workshop-Michael
Brannick\\Datasets example\\RocksLMX_CC-2.xlsx", sheetName="Data")
RocksDat

# Sorted by date (year)


RocksDat.Yr <- RocksDat[order(RocksDat$Year), ]
RocksRes1 <- rma(ni=N, ri=r, method="DL", measure="ZCOR", data=RocksDat.Yr)
RocksRes1
forest(RocksRes1)

# Cummulative analysis
RocksCU <- cumul(RocksRes1, order = order(RocksDat.Yr$Year))
forest(RocksCU)

####Tutorial 13: Forest Plots (Making them look the way you want)####
##I use McLeod data (correlation) instead of sleep data (binary) because I don't
have it. But I just want to practice how to labeling the forest plot##
# Load library (if not yet loaded)
library(metafor)
library(xlsx)

# Load excel file


McLeodDat <- McLeodDat <- read.xlsx("C:\\Users\\Surya Dila\\Desktop\\R tutorial M
Brannick\\3 and 10\\McLeod2007.xlsx", sheetName = "Data")
McLeodDat

# Sort by Dx and r
McLeod.Dx.r <- McLeodDat[order(McLeodDat$Dx,McLeodDat$r), ]
McLeod.Dx.r

# Meta analysis
McLeodRes1 <- rma(ri=r, ni=N, method="DL", measure="ZCOR", data=McLeod.Dx.r)
McLeodRes1

# Forest plot
forest(McLeodRes1)

# Meta analysis of subset of study (example, study 38 till 45)


McLeodDat.8 <- McLeod.Dx.r[38:45, ]
McLeodRes8 <- rma(ri=r, ni=N, method="DL", measure="ZCOR", data=McLeodDat.8)

# Meta analysis and forest plot introducing categorical moderator (Parent)


McLeodRes8 <- rma(ri=r, ni=N, method="DL", measure="ZCOR", mods = ~factor(Parent),
data=McLeodDat.8)
forest(McLeodRes8)

# Writing study labels (slab=...)


forest(McLeodRes8, slab=paste(McLeodDat.8$Author, McLeodDat.8$Year, sep=", "))
# Converting to odds from log(odds) (atransf=...)
forest(McLeodRes8, slab=paste(McLeodDat.8$Author, McLeodDat.8$Year, sep=", "),
atransf=exp)

# Change ES label from "Fisher z Tranformed Correlation Coefficient" to "Odds


Ratio" (xlab=...)
forest(McLeodRes8, slab=paste(McLeodDat.8$Author, McLeodDat.8$Year, sep=", "),
atransf=exp, xlab="Odds Ratio")

# Make scales the same for both side of graphs (at=...)


forest(McLeodRes8, slab=paste(McLeodDat.8$Author, McLeodDat.8$Year, sep=", "),
atransf=exp, xlab="Odds Ratio", at=c(-1.5, 0, 1.5, 3))

# Add labels to top of figure


forest(McLeodRes8, atransf=exp, xlab="Odds Ratio", slab=paste(McLeodDat.8$Author,
McLeodDat.8$Year, sep=", "), xlim=c(-6,6), at=c(-1.5, 0, 1.5, 3))
op <- par(cex=1, font=2)
text (4.5, 10, "OR [95% CI]")
text (-4.5, 10, "Author, Date")
title("Figure 1: Forest Plot of McLeod Data")
par(op)

# Add labels to top of figure (alternative 1)


forest(McLeodRes8, atransf=exp, xlab="Odds Ratio", slab=paste(McLeodDat.8$Author,
McLeodDat.8$Year, sep=", "), xlim=c(-16,6), at=c(-1.5, 0, 1.5, 3))
text (4, 10, "OR [95% CI]", pos=2, font=2, cex=.9)
text (-15, 10, "Author, Date", pos=4, font=2, cex=.9)
title("Figure 1: Forest Plot of McLeod Data")
# Note: you have to play with the numbers for placement: trial and error; start
with zero, zero to be in the graph and work from there

# Add labels (example by Wolfgang Viechtbauer)


library(metafor)

data(dat.bcg)
dat <- dat.bcg

res <- rma(ai=tpos, bi=tneg, ci=cpos, di=cneg, data=dat, measure="RR")

windows(width=6.5, height=4.0, pointsize=10)


par(mar=c(4,0,4,0))
forest(res, slab=paste(dat$author, ", ", dat$year, sep=""),
xlim=c(-16,6), at=log(c(.05,.25,1,4)), atransf=exp,
ilab=cbind(dat$tpos, dat$tneg, dat$cpos, dat$cneg),
ilab.xpos=c(-9.5,-8,-6,-4.5), cex=.8, ylim=c(-1.5,16), efac=1.8)
text(c(-9.5,-8,-6,-4.5), 14.7, c("TB+", "TB-", "TB+", "TB-"), font=2, cex=.8)
text(c(-8.75,-5.25), 15.7, c("Vaccinated", "Control"), font=2, cex=.8)
text(-16, 14.7, "Author(s) and Year", pos=4, font=2, cex=.8)
text(6, 14.7, "Relative Risk [95% CI]", pos=2, font=2, cex=.8)
title("Figure 1: Forest Plot of the BCG Vaccine Data")

########################################################################
# So, just use the text() function to add those column headings. With the ilab and
ilab.xpos arguments, you can add the information for those columns to the plot.
# Note: you have to play with the numbers for placement: trial and error; start
with zero, zero to be in the graph and work from there

#### Errors I have been faced ####


- Note that R is case sensitive
- Error in loading excel file using library(xlsx) >> (1) you must include the local
disk, for example: C: or D:; (2) use "\\" or / to separate the path; (3) check the
correct path of your file by right click the excel file, choose properties, then
copy the path, add your file name; (4) file name should exactly the same containing
.xlsx
- Error in forest.default(McLeodDat.8, slab = paste(McLeodDat.8$Author, :
Must specify either 'vi', 'sei', or ('ci.lb', 'ci.ub') pairs. >> forest(...) must
be contain study result, not study data. I write McLeodDat.8 instead McLeodRes8
- text (coordinate X, coordinate Y) >> minus sign (-) to move the text to left,
plus sign (+) to move the text to right (X). Minus and plus sign (- and +) to move
down and up the text respectively (Y)
- font=... >> 1 is ordinary text, 2 is bold (the most commonly used), 3 is italic,
4 is italic & bold, and soon (check with your own trial and error)
- cex=...(decimal number) >> I think this is determine font size, .8 or .9 is the
largest size? I found it after trial and error of some numbers, I don't know
exactly
- pos=... >> I think it is "position", I found these combination (pos=2 for ES
title, pos=4 for study title) the most perfect one
- xlim (-x, x) >> to adjust the position of the forest, the scale and the label
below it (in horizontal axis)
- Begin with op <- par(cex=..., font=..), provide the text coordinates and finish
with par(op) >> to add text whereever you want in the forest plot (depend on
coordinates you give, a trial and error attempts)
- ilab.xpos=... >> There are 4 coordinates, all determine the x location of "event-
non event" of intervention and "event-non event" of control group
- ylim=c(-y, y) >> to adjust the content of forest plot position in vertical axis

####Trial for S 103 ORC####


# Load library
library(metafor)
library(xlsx)

# Load excel files that already organized as preferred input format, print it
S103Dat <- read.xlsx("D:\\Researcher\\Online Research Club (SuryaDila)\\Study
103\\Task 14 (data extraction period 1)\\Full assignments results\\Study 103 Data
Extraction\\Data extraction results\\Study 103.xlsx", sheetName="1-4mo")
S103Dat

# Meta analysis (first try random effect, to look the heterogeneity)


S103Res1 <- rma(ai=TEvent, bi=TNonEvent, ci=CEvent, di=CNonEvent, method="DL",
measure="OR", data=S103Dat)
S103Res1

# Because no heterogeneity, so I tried fixed effect meta analysis


S103Res1 <- rma(ai=TEvent, bi=TNonEvent, ci=CEvent, di=CNonEvent, method="FE",
measure="OR", data=S103Dat)
S103Res1

# Try looking the forest plot


S103Res1 <- rma(ai=TEvent, bi=TNonEvent, ci=CEvent, di=CNonEvent, method="FE",
measure="OR", data=S103Dat)
forest(S103Res1, atransf=exp, xlab="Odds Ratio",
slab=paste(S103Dat$Author,S103Dat$Year, sep=", "), at=c(-1.5, 0, 1.5, 3))

# Trial forest
# decrease margins so the full space is used
par(mar=c(4,4,1,2))
# fit fixed-effect model (use slab argument to define study labels)
S103Res1 <- rma(ai=TEvent, bi=TNonEvent, ci=CEvent, di=CNonEvent, data=S103Dat,
measure="OR",
slab=paste(Author, Year, sep=", "), method="FE")

### set up forest plot (with 2x2 table counts added; rows argument is used
### to specify exactly in which rows the outcomes will be plotted)
forest(S103Res1, xlim=c(-16, 6), at=log(c(0.05, 0.25, 1, 4)), atransf=exp,
ilab=cbind(S103Dat$TEvent, S103Dat$TNonEvent, S103Dat$CEvent,
S103Dat$CNonEvent),
ilab.xpos=c(-9.5,-8,-6,-4.5), cex=0.75, ylim=c(-8, 8),
xlab="Odds Ratio", mlab="", psize=1)

### add text with Q-value, dfs, p-value, and I^2 statistic
text(-16, -1, pos=4, cex=0.75, bquote(paste("FE Model (Q = ",
.(formatC(S103Res1$QE, digits=2, format="f")), ", df = ", .(S103Res1$k -
S103Res1$p),
", p = ", .(formatC(S103Res1$QEp, digits=2, format="f")), "; ", I^2, " = ",
.(formatC(S103Res1$I2, digits=1, format="f")), "%)")))

### set font expansion factor (as in forest() above) and use bold italic
### font and save original settings in object 'op'
op <- par(cex=0.75, font=4)

### switch to bold font


par(font=2)

### add column headings to the plot


text(c(-9.5,-8,-6,-4.5), 6.5, c("Malaria+", "Malaria-", "Malaria+", "Malaria-"))
text(c(-8.75,-5.25), 7.5, c("Treated", "Control"))
text(-16, 6.5, "Author(s) and Year", pos=4)
text(6, 6.5, "Odds Ratio [95% CI]", pos=2)

### set par back to the original settings


par(op)

###################################################################################
################
windows(width=6.5, height=4.0, pointsize=10)
par(mar=c(4,0,4,0))
forest(S103Res1, slab=paste(S103Dat$Author, ", ", S103Dat$Year, sep=""),
xlim=c(-16,6), at=log(c(.05,.25,1,4)), atransf=exp,
ilab=cbind(S103Dat$tmalaria, S103Dat$tnomalaria, S103Dat$cmalaria,
S103Dat$cnomalaria),
ilab.xpos=c(-9.5,-8,-6,-4.5), cex=.8, ylim=c(-1.5,16), efac=1.8)
text(c(-9.5,-8,-6,-4.5), 14.7, c("malaria+", "malaria-", "malaria+", "malaria-"),
font=2, cex=.8)
text(c(-8.75,-5.25), 15.7, c("Treated", "Control"), font=2, cex=.8)
text(-16, 14.7, "Author(s) and Year", pos=4, font=2, cex=.8)
text(6, 14.7, "Odds Ratio [95% CI]", pos=2, font=2, cex=.8)
###################################################################################
#################

#### Example R code for forest plot with subgroups ####


library(metafor)

### decrease margins so the full space is used


par(mar=c(4,4,1,2))
### fit random-effects model (use slab argument to define study labels)
res <- rma(ai=tpos, bi=tneg, ci=cpos, di=cneg, data=dat.bcg, measure="RR",
slab=paste(author, year, sep=", "), method="REML")

### set up forest plot (with 2x2 table counts added; rows argument is used
### to specify exactly in which rows the outcomes will be plotted)
forest(res, xlim=c(-16, 6), at=log(c(0.05, 0.25, 1, 4)), atransf=exp,
ilab=cbind(dat.bcg$tpos, dat.bcg$tneg, dat.bcg$cpos, dat.bcg$cneg),
ilab.xpos=c(-9.5,-8,-6,-4.5), cex=0.75, ylim=c(-1, 27),
order=order(dat.bcg$alloc), rows=c(3:4,9:15,20:23),
xlab="Risk Ratio", mlab="", psize=1)

### add text with Q-value, dfs, p-value, and I^2 statistic
text(-16, -1, pos=4, cex=0.75, bquote(paste("RE Model for All Studies (Q = ",
.(formatC(res$QE, digits=2, format="f")), ", df = ", .(res$k - res$p),
", p = ", .(formatC(res$QEp, digits=2, format="f")), "; ", I^2, " = ",
.(formatC(res$I2, digits=1, format="f")), "%)")))

### set font expansion factor (as in forest() above) and use bold italic
### font and save original settings in object 'op'
op <- par(cex=0.75, font=4)

### add text for the subgroups


text(-16, c(24,16,5), pos=4, c("Systematic Allocation",
"Random Allocation",
"Alternate Allocation"))

### switch to bold font


par(font=2)

### add column headings to the plot


text(c(-9.5,-8,-6,-4.5), 26, c("TB+", "TB-", "TB+", "TB-"))
text(c(-8.75,-5.25), 27, c("Vaccinated", "Control"))
text(-16, 26, "Author(s) and Year", pos=4)
text(6, 26, "Risk Ratio [95% CI]", pos=2)

### set par back to the original settings


par(op)

### fit random-effects model in the three subgroups


res.s <- rma(ai=tpos, bi=tneg, ci=cpos, di=cneg, data=dat.bcg, measure="RR",
subset=(alloc=="systematic"), method="REML")
res.r <- rma(ai=tpos, bi=tneg, ci=cpos, di=cneg, data=dat.bcg, measure="RR",
subset=(alloc=="random"), method="REML")
res.a <- rma(ai=tpos, bi=tneg, ci=cpos, di=cneg, data=dat.bcg, measure="RR",
subset=(alloc=="alternate"), method="REML")

### add summary polygons for the three subgroups


addpoly(res.s, row=18.5, cex=0.75, atransf=exp, mlab="")
addpoly(res.r, row= 7.5, cex=0.75, atransf=exp, mlab="")
addpoly(res.a, row= 1.5, cex=0.75, atransf=exp, mlab="")

### add text with Q-value, dfs, p-value, and I^2 statistic for subgroups
text(-16, 18.5, pos=4, cex=0.75, bquote(paste("RE Model for Subgroup (Q = ",
.(formatC(res.s$QE, digits=2, format="f")), ", df = ", .(res.s$k - res.s$p),
", p = ", .(formatC(res.s$QEp, digits=2, format="f")), "; ", I^2, " = ",
.(formatC(res.s$I2, digits=1, format="f")), "%)")))
text(-16, 7.5, pos=4, cex=0.75, bquote(paste("RE Model for Subgroup (Q = ",
.(formatC(res.r$QE, digits=2, format="f")), ", df = ", .(res.r$k - res.r$p),
", p = ", .(formatC(res.r$QEp, digits=2, format="f")), "; ", I^2, " = ",
.(formatC(res.r$I2, digits=1, format="f")), "%)")))
text(-16, 1.5, pos=4, cex=0.75, bquote(paste("RE Model for Subgroup (Q = ",
.(formatC(res.a$QE, digits=2, format="f")), ", df = ", .(res.a$k - res.a$p),
", p = ", .(formatC(res.a$QEp, digits=2, format="f")), "; ", I^2, " = ",
.(formatC(res.a$I2, digits=1, format="f")), "%)")))

ADVANCED R E-book: http://adv-r.had.co.nz/

You might also like