### copy data into 'dat' and examine data
dat <- dat.viechtbauer2021
dat
if (FALSE) {
### load metafor package
library(metafor)
### calculate log odds ratios and corresponding sampling variances
dat <- escalc(measure="OR", ai=xTi, n1i=nTi, ci=xCi, n2i=nCi, add=1/2, to="all", data=dat)
dat
### number of studies
k <- nrow(dat)
### fit models
res.CE <- rma(yi, vi, data=dat, method="CE") # same as method="EE"
res.CE
res.RE <- rma(yi, vi, data=dat, method="DL")
res.RE
res.MR <- rma(yi, vi, mods = ~ dose, data=dat, method="FE")
res.MR
res.ME <- rma(yi, vi, mods = ~ dose, data=dat, method="DL")
res.ME
### forest and bubble plot
par(mar=c(5,4,1,2))
forest(dat$yi, dat$vi, psize=0.8, efac=0, xlim=c(-4,6), ylim=c(-3,23),
cex=1, width=c(5,5,5), xlab="Log Odds Ratio (LnOR)",
header=c("Trial", "LnOR [95% CI]"))
addpoly(res.CE, row=-1, mlab="CE Model")
addpoly(res.RE, row=-2, mlab="RE Model")
abline(h=0)
tmp <- regplot(res.ME, xlim=c(0,250), ylim=c(-1,1.5), predlim=c(0,250), shade=FALSE, digits=1,
xlab="Dosage (mg per day)", psize="seinv", plim=c(NA,5), bty="l", las=1,
lty=c("solid", "dashed"), label=TRUE, labsize=0.8, offset=c(1,0.7))
res.sub <- rma(yi, vi, mods = ~ dose, data=dat, method="DL", subset=-6)
abline(res.sub, lty="dotted")
points(tmp$xi, tmp$yi, pch=21, cex=tmp$psize, col="black", bg="darkgray")
par(mar=c(5,4,4,2))
### number of standardized deleted residuals larger than +-1.96 in each model
sum(abs(rstudent(res.CE)$z) >= qnorm(0.975))
sum(abs(rstudent(res.MR)$z) >= qnorm(0.975))
sum(abs(rstudent(res.RE)$z) >= qnorm(0.975))
sum(abs(rstudent(res.ME)$z) >= qnorm(0.975))
### plot of the standardized deleted residuals for the RE and ME models
plot(NA, NA, xlim=c(1,20), ylim=c(-4,4), xlab="Study", ylab="Standardized (Deleted) Residual",
xaxt="n", main="Random-Effects Model", las=1)
axis(side=1, at=1:20)
abline(h=c(-1.96,1.96), lty="dotted")
abline(h=0)
points(1:20, rstandard(res.RE)$z, type="o", pch=19, col="gray70")
points(1:20, rstudent(res.RE)$z, type="o", pch=19)
legend("top", pch=19, col=c("gray70","black"), lty="solid",
legend=c("Standardized Residuals","Standardized Deleted Residuals"), bty="n")
plot(NA, NA, xlim=c(1,20), ylim=c(-4,4), xlab="Study", ylab="Standardized (Deleted) Residual",
xaxt="n", main="Mixed-Effects Model", las=1)
axis(side=1, at=1:20)
abline(h=c(-1.96,1.96), lty="dotted")
abline(h=0)
points(1:20, rstandard(res.ME)$z, type="o", pch=19, col="gray70")
points(1:20, rstudent(res.ME)$z, type="o", pch=19)
legend("top", pch=19, col=c("gray70","black"), lty="solid",
legend=c("Standardized Residuals","Standardized Deleted Residuals"), bty="n")
### Baujat plots
baujat(res.CE, main="Common-Effects Model", xlab="Squared Pearson Residual", ylim=c(0,5), las=1)
baujat(res.ME, main="Mixed-Effects Model", ylim=c(0,2), las=1)
### GOSH plots (skipped because this takes quite some time to run)
if (FALSE) {
res.GOSH.CE <- gosh(res.CE, subsets=10^7)
plot(res.GOSH.CE, cex=0.2, out=6, xlim=c(-0.25,1.25), breaks=c(200,100))
res.GOSH.ME <- gosh(res.ME, subsets=10^7)
plot(res.GOSH.ME, het="tau2", out=6, breaks=50, adjust=0.6, las=1)
}
### plot of treatment dosage against the standardized residuals
plot(dat$dose, rstandard(res.ME)$z, pch=19, xlab="Dosage (mg per day)",
ylab="Standardized Residual", xlim=c(0,250), ylim=c(-2.5,2.5), las=1)
abline(h=c(-1.96,1.96), lty="dotted", lwd=2)
abline(h=0)
title("Standardized Residual Plot")
text(dat$dose[6], rstandard(res.ME)$z[6], "6", pos=4, offset=0.4)
### quadratic polynomial model
rma(yi, vi, mods = ~ dose + I(dose^2), data=dat, method="DL")
### lack-of-fit model
resLOF <- rma(yi, vi, mods = ~ dose + factor(dose), data=dat, method="DL", btt=3:9)
resLOF
### scatter plot to illustrate the lack-of-fit model
regplot(res.ME, xlim=c(0,250), ylim=c(-1.0,1.5), xlab="Dosage (mg per day)", ci=FALSE,
predlim=c(0,250), psize=1, pch=19, col="gray60", digits=1, lwd=1, bty="l", las=1)
dosages <- sort(unique(dat$dose))
lines(dosages, fitted(resLOF)[match(dosages, dat$dose)], type="o", pch=19, cex=2, lwd=2)
points(dat$dose, dat$yi, pch=19, col="gray60")
legend("bottomright", legend=c("Linear Model", "Lack-of-Fit Model"), pch=c(NA,19), col="black",
lty="solid", lwd=c(1,2), pt.cex=c(1,2), seg.len=4, bty="n")
### checking normality of the standardized deleted residuals
qqnorm(res.ME, type="rstudent", main="Standardized Deleted Residuals", pch=19, label="out",
lwd=2, pos=24, ylim=c(-4,3), lty=c("solid", "dotted"), las=1)
### checking normality of the random effects
sav <- qqnorm(ranef(res.ME)$pred, main="BLUPs of the Random Effects", cex=1, pch=19,
xlim=c(-2.2,2.2), ylim=c(-0.6,0.6), las=1)
abline(a=0, b=sd(ranef(res.ME)$pred), lwd=2)
text(sav$x[6], sav$y[6], "6", pos=4, offset=0.4)
### hat values for the CE and RE models
plot(NA, NA, xlim=c(1,20), ylim=c(0,0.21), xaxt="n", las=1, xlab="Study", ylab="Hat Value")
axis(1, 1:20, cex.axis=1)
points(hatvalues(res.CE), type="o", pch=19, col="gray70")
points(hatvalues(res.RE), type="o", pch=19)
abline(h=1/20, lty="dotted", lwd=2)
title("Hat Values for the CE/RE Models")
legend("topright", pch=19, col=c("gray70","black"), lty="solid",
legend=c("Common-Effects Model", "Random-Effects Model"), bty="n")
### heatmap of the hat matrix for the ME model
cols <- colorRampPalette(c("blue", "white", "red"))(101)
h <- hatvalues(res.ME, type="matrix")
image(1:nrow(h), 1:ncol(h), t(h[nrow(h):1,]), axes=FALSE,
xlab="Influence of the Observed Effect of Study ...", ylab="On the Fitted Value of Study ...",
col=cols, zlim=c(-max(abs(h)),max(abs(h))))
axis(1, 1:20, tick=FALSE)
axis(2, 1:20, labels=20:1, las=1, tick=FALSE)
abline(h=seq(0.5,20.5,by=1), col="white")
abline(v=seq(0.5,20.5,by=1), col="white")
points(1:20, 20:1, pch=19, cex=0.4)
title("Heatmap for the Mixed-Effects Model")
### plot of leverages versus standardized residuals for the ME model
plot(hatvalues(res.ME), rstudent(res.ME)$z, pch=19, cex=0.2+3*sqrt(cooks.distance(res.ME)),
las=1, xlab="Leverage (Hat Value)", ylab="Standardized Deleted Residual",
xlim=c(0,0.35), ylim=c(-3.5,2.5))
abline(h=c(-1.96,1.96), lty="dotted", lwd=2)
abline(h=0, lwd=2)
ids <- c(3,6,9)
text(hatvalues(res.ME)[ids] + c(0,0.013,0.010), rstudent(res.ME)$z[ids] - c(0.18,0,0), ids)
title("Leverage vs. Standardized Deleted Residuals")
### plot of the Cook's distances for the ME model
plot(1:20, cooks.distance(res.ME), ylim=c(0,1.6), type="o", pch=19, las=1, xaxt="n", yaxt="n",
xlab="Study", ylab="Cook's Distance")
axis(1, 1:20, cex.axis=1)
axis(2, seq(0,1.6,by=0.4), las=1)
title("Cook's Distances")
### plot of the leave-one-out estimates of tau^2 for the ME model
x <- influence(res.ME)
plot(1:20, x$inf$tau2.del, ylim=c(0,0.15), type="o", pch=19, las=1, xaxt="n", xlab="Study",
ylab=expression(paste("Estimate of ", tau^2, " without the ", italic(i), "th study")))
abline(h=res.ME$tau2, lty="dashed")
axis(1, 1:20)
title("Residual Heterogeneity Estimates")
### plot of the covariance ratios for the ME model
plot(1:20, x$inf$cov.r, ylim=c(0,2.0), type="o", pch=19, las=1, xaxt="n",
xlab="Study", ylab="Covariance Ratio")
abline(h=1, lty="dashed")
axis(1, 1:20)
title("Covariance Ratios")
### fit mixed-effects model without studies 3 and/or 6
rma(yi, vi, mods = ~ dose, data=dat, method="DL", subset=-3)
rma(yi, vi, mods = ~ dose, data=dat, method="DL", subset=-6)
rma(yi, vi, mods = ~ dose, data=dat, method="DL", subset=-c(3,6))
}
Run the code above in your browser using DataLab