This vignette provides a short example of a Bayesian NMA for HR data.
The model fit relies on the gemtc
package, pre- and
post-processing is done with gemtcPlus
.
## Warning in (function (network, type = "consistency", factor = 2.5, n.chain = 4,
## : Likelihood can not be inferred. Defaulting to normal.
## Compiling model graph
## Resolving undeclared variables
## Allocating nodes
## Graph information:
## Observed stochastic nodes: 7
## Unobserved stochastic nodes: 5
## Total graph size: 132
##
## Initializing model
##
## Results on the Mean Difference scale
##
## Iterations = 1:6000
## Thinning interval = 1
## Number of chains = 3
## Sample size per chain = 6000
##
## 1. Empirical mean and standard deviation for each variable,
## plus standard error of the mean:
##
## Mean SD Naive SE Time-series SE
## d.B.A -0.12835 0.05539 0.0004129 0.0004129
## d.C.B 0.19726 0.08320 0.0006201 0.0006313
## d.C.D 0.03578 0.12182 0.0009080 0.0008890
## d.C.E -0.09242 0.06593 0.0004914 0.0004910
## d.D.F 0.20852 0.19508 0.0014540 0.0014541
##
## 2. Quantiles for each variable:
##
## 2.5% 25% 50% 75% 97.5%
## d.B.A -0.23636 -0.16594 -0.12837 -0.09106 -0.01975
## d.C.B 0.03411 0.14194 0.19794 0.25263 0.36011
## d.C.D -0.20209 -0.04794 0.03582 0.11856 0.27699
## d.C.E -0.22187 -0.13704 -0.09198 -0.04728 0.03591
## d.D.F -0.17147 0.07815 0.20894 0.33972 0.59366
##
## -- Model fit (residual deviance):
##
## Dbar pD DIC
## 5.481882 4.980620 10.462501
##
## 7 data points, ratio 0.7831, I^2 = 0%
## DIC pD resDev dataPoints
## 1 10.46 4.98 5.48 7
Update model plan and re-run fit.
#Plan model
model_plan <- plan_hr(bth.model = "RE",
n.chain = 3,
n.iter = 6000,
thin = 1,
n.adapt = 1000,
link = "identity",
linearModel = "random",
bth.prior = mtc.hy.prior(type = "var", distr = "dlnorm",-4.18, 1 / 1.41 ^ 2)
)
## Warning in (function (network, type = "consistency", factor = 2.5, n.chain = 4,
## : Likelihood can not be inferred. Defaulting to normal.
## Compiling model graph
## Resolving undeclared variables
## Allocating nodes
## Graph information:
## Observed stochastic nodes: 7
## Unobserved stochastic nodes: 5
## Total graph size: 132
##
## Initializing model
The ggmcmc
package provides ggplot2 versions of all
major convergence plots and diagnostics.
Figure Traceplot
Figure Densityplot
Figure Brooks-Gelman-Rubin convergence diagnostic (Rhat)
Figure Auto-correlation plot
Figure Running means
The contrasts in this model are log-hazard ratios (which correspond to differences in log-hazard rates).
Unfortunately, gemtc
does not provide an estimate of the
effective sample size (n.eff
). Instead, a time-series SE is
given. As a rule of thumb, the length of the MCMC is sufficient if the
time-series SE is smaller than 2%(-5%) of the posterior SD.
##
## Results on the Mean Difference scale
##
## Iterations = 1:6000
## Thinning interval = 1
## Number of chains = 3
## Sample size per chain = 6000
##
## 1. Empirical mean and standard deviation for each variable,
## plus standard error of the mean:
##
## Mean SD Naive SE Time-series SE
## d.B.A -0.12835 0.05539 0.0004129 0.0004129
## d.C.B 0.19726 0.08320 0.0006201 0.0006313
## d.C.D 0.03578 0.12182 0.0009080 0.0008890
## d.C.E -0.09242 0.06593 0.0004914 0.0004910
## d.D.F 0.20852 0.19508 0.0014540 0.0014541
##
## 2. Quantiles for each variable:
##
## 2.5% 25% 50% 75% 97.5%
## d.B.A -0.23636 -0.16594 -0.12837 -0.09106 -0.01975
## d.C.B 0.03411 0.14194 0.19794 0.25263 0.36011
## d.C.D -0.20209 -0.04794 0.03582 0.11856 0.27699
## d.C.E -0.22187 -0.13704 -0.09198 -0.04728 0.03591
## d.D.F -0.17147 0.07815 0.20894 0.33972 0.59366
##
## -- Model fit (residual deviance):
##
## Dbar pD DIC
## 5.481882 4.980620 10.462501
##
## 7 data points, ratio 0.7831, I^2 = 0%
In the example here, the chain length seems borderline (sufficient for posterior means and medians, but rather a bit too small for stable 95% credible intervals).
To judge overall model fit, the residual deviance should be compared
to the number of independent data points (which can be done via a small
utility function in gemtcPlus
).
## DIC pD resDev dataPoints
## 1 10.46 4.98 5.48 7
Assume new treatment is “A” and is to be compared vs all other treatments.
Table Hazard ratios A vs other treatments
## Comparator Med CIlo CIup
## 1 B 0.88 0.79 0.98
## 2 C 1.07 0.88 1.30
## 3 D 1.03 0.76 1.41
## 4 E 1.17 0.93 1.48
## 5 F 0.84 0.51 1.37
Table Probability A better than other treatments (better meaning smaller HR)
## New Comparator probNewBetter
## 1 A B 0.989
## 5 A F 0.756
## 3 A D 0.415
## 2 A C 0.244
## 4 A E 0.090
Figure Forest plot A vs other treatments
Table Cross-tabulation of HRs
ctab <- round(exp(relative.effect.table(model)), 2)
pander::pandoc.table(as.data.frame(ctab), split.tables = Inf)
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
A | A | 1.14 (1.02, 1.27) | 0.93 (0.77, 1.14) | 0.97 (0.71, 1.32) | 0.85 (0.67, 1.08) | 1.19 (0.73, 1.94) |
B | 0.88 (0.79, 0.98) | B | 0.82 (0.7, 0.97) | 0.85 (0.64, 1.14) | 0.75 (0.61, 0.92) | 1.05 (0.65, 1.68) |
C | 1.07 (0.88, 1.3) | 1.22 (1.03, 1.43) | C | 1.04 (0.82, 1.32) | 0.91 (0.8, 1.04) | 1.28 (0.82, 2.01) |
D | 1.03 (0.76, 1.41) | 1.18 (0.88, 1.57) | 0.96 (0.76, 1.22) | D | 0.88 (0.69, 1.13) | 1.23 (0.84, 1.81) |
E | 1.17 (0.93, 1.48) | 1.34 (1.08, 1.64) | 1.1 (0.96, 1.25) | 1.14 (0.89, 1.45) | E | 1.4 (0.89, 2.19) |
F | 0.84 (0.51, 1.37) | 0.95 (0.59, 1.54) | 0.78 (0.5, 1.22) | 0.81 (0.55, 1.19) | 0.71 (0.46, 1.12) | F |
rk <- rank.probability(model, preferredDirection = -1)
mrk <- reshape2::melt(rk[,], varnames = c("Treatment", "Rank"), value.name = "Probability")
fig <- ggplot(data = mrk) +
geom_line(aes(Rank, Probability, color = Treatment, linetype = Treatment), size = 1.5) +
theme_bw()
Figure Rankogram
Table Rank probabilities
## Rank probability; preferred direction = -1
## Rank 1 Rank 2 Rank 3 Rank 4 Rank 5 Rank 6
## A 7.061111e-02 0.120333333 0.253888889 0.34872222 0.201944444 0.004500000
## B 5.555556e-05 0.001333333 0.007222222 0.12822222 0.455000000 0.408166667
## C 4.072222e-02 0.423777778 0.355500000 0.15322222 0.025722222 0.001055556
## D 1.165000e-01 0.211666667 0.255555556 0.24111111 0.154833333 0.020333333
## E 7.158333e-01 0.196111111 0.069555556 0.01583333 0.002666667 0.000000000
## F 5.627778e-02 0.046777778 0.058277778 0.11288889 0.159833333 0.565944444
## model {
## # Likelihood for arm-based data
## ## OMITTED
## # Likelihood for contrast-based data (univariate for 2-arm trials)
## for(i in studies.r2) {
## for (k in 2:na[i]) {
## mest[i, k] <- delta[i, k]
## }
## m[i, 2] ~ dnorm(mest[i, 2], prec[i, 2])
## prec[i, 2] <- 1 / (e[i, 2] * e[i, 2])
##
## dev[i, 1] <- pow(m[i, 2] - mest[i, 2], 2) * prec[i, 2]
## }
## # Likelihood for contrast-based data (multivariate for multi-arm trials)
## ## OMITTED
##
## # Fixed effect model
## for (i in studies) {
## delta[i, 1] <- 0
## for (k in 2:na[i]) {
## delta[i, k] <- d[t[i, 1], t[i, k]]
## }
## }
##
## # Relative effect matrix
## d[1, 1] <- 0
## d[1, 2] <- -d.B.A
## d[1, 3] <- -d.B.A + -d.C.B
## d[1, 4] <- -d.B.A + -d.C.B + d.C.D
## d[1, 5] <- -d.B.A + -d.C.B + d.C.E
## d[1, 6] <- -d.B.A + -d.C.B + d.C.D + d.D.F
## for (i in 2:nt) {
## for (j in 1:nt) {
## d[i, j] <- d[1, j] - d[1, i]
## }
## }
##
## prior.prec <- pow(re.prior.sd, -2)
##
## # Study baseline priors
## ## OMITTED
##
## # Effect parameter priors
## d.B.A ~ dnorm(0, prior.prec)
## d.C.B ~ dnorm(0, prior.prec)
## d.C.D ~ dnorm(0, prior.prec)
## d.C.E ~ dnorm(0, prior.prec)
## d.D.F ~ dnorm(0, prior.prec)
##
## }
BEE repository: /tmp/Rtmp9XTquv/Rbuild14e01251655f/gemtcPlus/vignettes
## [1] "Fri Oct 11 04:20:22 2024"
## R version 4.4.1 (2024-06-14)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 24.04.1 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
## LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so; LAPACK version 3.12.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=en_US.UTF-8 LC_COLLATE=C
## [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
## [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
##
## time zone: Etc/UTC
## tzcode source: system (glibc)
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] ggmcmc_1.5.1.1 ggplot2_3.5.1 tidyr_1.3.1 gemtcPlus_1.0.0
## [5] R2jags_0.8-5 rjags_4-16 gemtc_1.0-2 coda_0.19-4.1
## [9] dplyr_1.1.4 rmarkdown_2.28
##
## loaded via a namespace (and not attached):
## [1] gtable_0.3.5 xfun_0.48 bslib_0.8.0
## [4] GGally_2.2.1 CompQuadForm_1.4.3 lattice_0.22-6
## [7] tzdb_0.4.0 numDeriv_2016.8-1.1 mathjaxr_1.6-0
## [10] vctrs_0.6.5 tools_4.4.1 generics_0.1.3
## [13] parallel_4.4.1 tibble_3.2.1 fansi_1.0.6
## [16] highr_0.11 pkgconfig_2.0.3 Matrix_1.7-0
## [19] RColorBrewer_1.1-3 truncnorm_1.0-9 lifecycle_1.0.4
## [22] farver_2.1.2 compiler_4.4.1 stringr_1.5.1
## [25] munsell_0.5.1 htmltools_0.5.8.1 sys_3.4.3
## [28] buildtools_1.0.0 sass_0.4.9 yaml_2.3.10
## [31] crayon_1.5.3 pillar_1.9.0 nloptr_2.1.1
## [34] jquerylib_0.1.4 MASS_7.3-61 cachem_1.1.0
## [37] meta_7.0-0 metadat_1.2-0 boot_1.3-31
## [40] abind_1.4-8 nlme_3.1-166 ggstats_0.7.0
## [43] network_1.18.2 tidyselect_1.2.1 digest_0.6.37
## [46] slam_0.1-53 stringi_1.8.4 reshape2_1.4.4
## [49] pander_0.6.5 purrr_1.0.2 labeling_0.4.3
## [52] maketools_1.3.1 forcats_1.0.0 splines_4.4.1
## [55] fastmap_1.2.0 grid_4.4.1 colorspace_2.1-1
## [58] cli_3.6.3 metafor_4.6-0 magrittr_2.0.3
## [61] utf8_1.2.4 readr_2.1.5 withr_3.0.1
## [64] scales_1.3.0 igraph_2.0.3 lme4_1.1-35.5
## [67] hms_1.1.3 evaluate_1.0.1 knitr_1.48
## [70] Rglpk_0.6-5.1 rlang_1.1.4 Rcpp_1.0.13
## [73] glue_1.8.0 xml2_1.3.6 reshape_0.8.9
## [76] minqa_1.2.8 jsonlite_1.8.9 R6_2.5.1
## [79] plyr_1.8.9 statnet.common_4.10.0 R2WinBUGS_2.1-22.1