Comment on “Bayesian additional evidence for decision making under small sample uncertainty”
## reproduce BAE calculations from Sondhi et al. (2021)
## ----------------------------------------------------------------------------- ## data from Sondhi et al. (2021) hr <- 0.42 hrCI <- c(0.14, 1.23) x <- log(hr) za <- qnorm(p = 0.975) se <- (log(hrCI)[2] - log(hrCI)[1])/(2*za) p <- 2*pnorm(q = abs(x)/se, lower.tail = FALSE) ## prior evidence from Innocenti et al. (2019) hr2 <- 0.13 hr2CI <- c(0.06, 0.30) x2 <- log(0.13) se2 <- (log(hr2CI[2]) - log(hr2CI[1]))/(2*za) ## Bayesian additional evidence based on effect size and standard error baeES <- function(x, se, alpha) { bae <- sign(x)*sqrt(2)*qnorm(p = 1 - alpha/2)*se - x return(bae) } ## Bayesian additional evidence based on confidence interval limits baeCI <- function(L, U) { x <- mean(c(L, U)) bae <- (sign(x)*sqrt(2)*(U - L) - (U + L))/2 return(bae) } ## compute BAE for data from Sondhi et al. (2021) bae <- baeCI(L = log(hrCI)[1], U = log(hrCI)[2]) ## functions to compute prior parameters of the 3 reverse-Bayes approaches ## ----------------------------------------------------------------------------- ## determine advocacy prior such that (1 - alpha) posterior credible interval ## fixed to zero and prior coefficient of variation fixed to 1/z_(alpha/2) advPriorCV <- function(x, se, alpha) { ## x: data ## se: standard error of data ## alpha: significance level z <- x/se za <- qnorm(p = 1 - alpha/2) if (abs(z) >= za) { out <- out <- c("mean" = NaN, "var" = NaN) } else { meanPrior <- 2*x/(1 - z^2/za^2) varPrior <- meanPrior^2/za^2 out <- c("mean" = meanPrior, "var" = varPrior) } return(out) } ## determine advocacy prior such that (1 - alpha) posterior credible interval ## fixed to zero and prior variance fixed to variance of data advPriorVar <- function(x, se, alpha) { ## x: data ## se: standard error of data ## alpha: significance level z <- x/se za <- qnorm(p = 1 - alpha/2) if (abs(z) >= za) { out <- out <- c("mean" = NaN, "var" = NaN) } else { meanPrior <- sign(x)*sqrt(2)*za*se - x varPrior <- se^2 out <- c("mean" = meanPrior, "var" = varPrior) } return(out) } ## determine advocacy prior such that (1 - alpha) posterior credible interval ## fixed to zero and prior mean fixed to value of data advPriorMean <- function(x, se, alpha) { ## x: data ## se: standard error of data ## alpha: significance level z <- x/se za <- qnorm(p = 1 - alpha/2) if (abs(z) >= za) { out <- out <- c("mean" = NaN, "var" = NaN) } else { meanPrior <- x varPrior <- se^2/(za^2/z^2 - 1) out <- c("mean" = meanPrior, "var" = varPrior) } return(out) } ## compute posterior credible interval to check correctness of functions postCrI <- function(x, se, meanPrior, varPrior, alpha) { postVar <- 1/(1/se^2 + 1/varPrior) postMean <- (x/se^2 + meanPrior/varPrior)*postVar za <- qnorm(p = 1 - alpha/2) crI <- postMean + c(-1, 1)*za*sqrt(postVar) names(crI) <- c("lower", "upper") return(crI) } ## create similar figure as in Sondhi et al. (2021) ## ----------------------------------------------------------------------------- ## significance level alpha <- 0.05 ## bae bae <- baeES(x = x, se = se, alpha = alpha) bae <- baeCI(L = log(hrCI[1]), U = log(hrCI[2])) baePost <- postCrI(x = x, se = se, meanPrior = bae, varPrior = se^2, alpha = alpha) ## AnCred anCredPars <- advPriorCV(x = x, se = se, alpha = alpha) anCredPost <- postCrI(x = x, se = se, meanPrior = anCredPars[1], varPrior = anCredPars[2], alpha = alpha) ## fixed mean fmPars <- advPriorMean(x = x, se = se, alpha = alpha) fmPost <- postCrI(x = x, se = se, meanPrior = fmPars[1], varPrior = fmPars[2], alpha = alpha) ## CIs lower <- c(x - za*se, bae - za*se, anCredPars[1] - za*sqrt(anCredPars[2]), fmPars[1] - za*sqrt(fmPars[2]), baePost[1], anCredPost[1], fmPost[1], x2 - za*se2) est <- c(x, bae, anCredPars[1], fmPars[1], mean(baePost), mean(anCredPost), mean(fmPost), x2) upper <- c(x + za*se, bae + za*se, anCredPars[1] + za*sqrt(anCredPars[2]), fmPars[1] + za*sqrt(fmPars[2]), baePost[2], anCredPost[2], fmPost[2], x2 + za*se2) colpalette <- c("#000000", "#1B9E77", "#D95F02", "#7570B3", "#000000") cols <- colpalette[c(1, 2, 3, 4, 2, 3, 4, 5)] xseq <- c(1, 2.8, 3, 3.2, 1.8, 2, 2.2, 4) xbks <- c(1, 2, 3, 4) xlab <- c("Data", "Posterior", "Advocacy Prior", "Additional data") ybks <- c(log(10), log(1), log(1/10), log(1/100), log(1/1000)) plot(x = xseq, y = est, type = "n", ylim = c(min(lower), log(5)), xlim = c(0.8*min(xbks), 1.1*max(xbks)), xaxt = "n", yaxt = "n", xlab = "", ylab = "", las = 2) mtext(side = 2, text = "Hazard Ratio", line = 3.3) abline(h = 0, lty = 2, col = adjustcolor(col = 1, alpha = 0.5), lwd = 1.5) axis(side = 2, at = ybks, labels = pCalibrate::formatBF(exp(ybks)), las = 2) axis(side = 1, at = xbks, labels = xlab) abline(h = ybks, lty = 1, col = adjustcolor(col = 1, alpha = 0.1)) box() arrows(x0 = xseq, y0 = lower, y1 = upper, angle = 90, code = 3, length = 0.1, lwd = 1.2, col = cols) points(x = xseq, y = est, pch = 20, cex = 1.2, col = cols) legend("bottomright", c("BAE", "AnCred", "fixed mean"), pch = 20, col = colpalette[2:4], bg = "white") ## plot partition of the prior parameter space ## ----------------------------------------------------------------------------- ## BAE for different prior variances than the one observed in the data bae2 <- function(x, se, alpha, g) { ## g: the relative prior variance bae <- (sign(x)*qnorm(p = 1 - alpha/2)*se*sqrt(g/(1 + g)) - x*g/(1 + g))*(1 + g) return(bae) } ## prior parameter space data priorsDF <- data.frame(mean = c(anCredPars[1], bae, fmPars[1]), var = c(anCredPars[2], se^2, fmPars[2]), type = c("AnCred", "BAE", "fixed mean"), color = colpalette[c(3, 2, 4)]) ## plot prior parameter space loggseq <- seq(log(0.01), log(25), length.out = 500) gbks <- c(0.1, 0.2, 0.5, 1, 2, 5, 10, 20) baeseq <- bae2(x = x, se = se, alpha = alpha, g = exp(loggseq)) plot(x = loggseq, y = baeseq/x, type = "l", las = 1, xaxt = "n", xlab = bquote("relative prior variance" ~ italic(g) == tau^2/sigma^2), ylab = "", xlim = log(c(0.1, 20)), ylim = c(0, 6), lwd = 1.8) axis(side = 1, at = log(gbks), labels = gbks) mtext(side = 2, text =bquote("relative prior mean" ~ mu/hat(theta)), line = 2) ## draw non-credibiliy region polygon(x = c(head(loggseq)[1], loggseq, tail(loggseq)[1]), y = c(10, baeseq, 10)/x, density = 10, angle = 135, border = NA, col = adjustcolor(col = "black", alpha = 0.3), lty = 2, lwd = 1) ## draw credibiliy region polygon(x = c(head(loggseq)[1], loggseq, tail(loggseq)[1]), y = c(-100, baeseq, -100)/x, density = 10, angle = 45, border = NA, col = adjustcolor(col = "black", alpha = 0.3), lty = 3, lwd = 1.5) ## draw significance region lines(x = loggseq, y = -qnorm(p = 1 - alpha/2)*sqrt(exp(loggseq)*se^2)/x, col = adjustcolor(colpalette[3], alpha = 0.5)) ## draw fixed mean/variance abline(h = 1, col = adjustcolor(colpalette[4], alpha = 0.5)) abline(v = 0, col = adjustcolor(colpalette[2], alpha = 0.5)) ## draw tipping points points(x = log(priorsDF[,2]/se^2), y = priorsDF[,1]/x, col = priorsDF[,4], pch = 20, cex = 1.6) legend("topleft", c("BAE", "AnCred", "fixed mean"), pch = 20, col = colpalette[2:4], bg = "white") text(x = log(0.28), y = 1.5, labels = bquote("posterior credible at" ~ alpha == .(alpha)), cex = 1.1) text(x = log(5), y = 0.5, labels = bquote("posterior not credible at" ~ alpha == .(alpha)), cex = 1.1)
留言
張貼留言