library(multinma)
options(mc.cores = parallel::detectCores())
This vignette describes the analysis of treatments for moderate-to-severe plaque psoriasis from an HTA report (Woolacott et al. 2006), replicating the analysis in NICE Technical Support Document 2 (Dias et al. 2011). The data are available in this package as hta_psoriasis
:
head(hta_psoriasis)
#> studyn studyc year trtn trtc sample_size PASI50 PASI75 PASI90
#> 1 1 Elewski 2004 1 Supportive care 193 12 5 1
#> 2 1 Elewski 2004 2 Etanercept 25 mg 196 59 46 21
#> 3 1 Elewski 2004 3 Etanercept 50 mg 194 54 56 40
#> 4 2 Gottlieb 2003 1 Supportive care 55 5 1 0
#> 5 2 Gottlieb 2003 2 Etanercept 25 mg 57 23 11 6
#> 6 3 Lebwohl 2003 1 Supportive care 122 13 5 1
Outcomes are ordered multinomial success/failure to achieve 50%, 75%, or 90% reduction in symptoms on the Psoriasis Area and Severity Index (PASI) scale. Some studies report ordered outcomes at all three cutpoints, others only one or two:
::filter(hta_psoriasis, studyc %in% c("Elewski", "Gordon", "ACD2058g", "Altmeyer"))
dplyr#> studyn studyc year trtn trtc sample_size PASI50 PASI75 PASI90
#> 1 1 Elewski 2004 1 Supportive care 193 12 5 1
#> 2 1 Elewski 2004 2 Etanercept 25 mg 196 59 46 21
#> 3 1 Elewski 2004 3 Etanercept 50 mg 194 54 56 40
#> 4 5 Gordon 2003 1 Supportive care 187 18 8 NA
#> 5 5 Gordon 2003 4 Efalizumab 369 118 98 NA
#> 6 6 ACD2058g 2004 1 Supportive care 170 25 NA NA
#> 7 6 ACD2058g 2004 4 Efalizumab 162 99 NA NA
#> 8 10 Altmeyer 1994 1 Supportive care 51 NA 1 NA
#> 9 10 Altmeyer 1994 6 Fumaderm 49 NA 12 NA
Here, the outcome counts are given as “exclusive” counts. That is, for a study reporting all outcomes (e.g. Elewski), the counts represent the categories 50 < PASI < 75, 75 < PASI < 90, and 90 < PASI < 100, and the corresponding columns are named by the lower end of the interval. Missing values are used where studies only report a subset of the outcomes. For a study reporting only two outcomes, say PASI50 and PASI75 as in Gordon, the counts represent the categories 50 < PASI < 75 and 75 < PASI < 100. For a study reporting only one outcome, say PASI70 as in Altmeyer, the count represents 70 < PASI < 100. We also need the count for the lowest category (i.e. no higher outcomes achieved), which is equal to the sample size minus the counts in the other observed categories.
We begin by setting up the network. We have arm-level ordered multinomial count data, so we use the function set_agd_arm()
. The function multi()
helps us to specify the ordered outcomes correctly.
<- set_agd_arm(hta_psoriasis,
pso_net study = paste(studyc, year),
trt = trtc,
r = multi(r0 = sample_size - rowSums(cbind(PASI50, PASI75, PASI90), na.rm = TRUE),
PASI50, PASI75, PASI90,inclusive = FALSE,
type = "ordered"))
pso_net#> A network with 16 AgD studies (arm-based).
#>
#> ------------------------------------------------------- AgD studies (arm-based) ----
#> Study Treatment arms
#> ACD2058g 2004 2: Supportive care | Efalizumab
#> ACD2600g 2004 2: Supportive care | Efalizumab
#> Altmeyer 1994 2: Supportive care | Fumaderm
#> Chaudari 2001 2: Supportive care | Infliximab
#> Elewski 2004 3: Supportive care | Etanercept 25 mg | Etanercept 50 mg
#> Ellis 1991 3: Supportive care | Ciclosporin | Ciclosporin
#> Gordon 2003 2: Supportive care | Efalizumab
#> Gottlieb 2003 2: Supportive care | Etanercept 25 mg
#> Gottlieb 2004 3: Supportive care | Infliximab | Infliximab
#> Guenther 1991 2: Supportive care | Ciclosporin
#> ... plus 6 more studies
#>
#> Outcome type: ordered (4 categories)
#> ------------------------------------------------------------------------------------
#> Total number of treatments: 8
#> Total number of studies: 16
#> Reference treatment is: Supportive care
#> Network is connected
Plot the network structure.
plot(pso_net, weight_edges = TRUE, weight_nodes = TRUE) +
# Nudge the legend over
::theme(legend.box.spacing = ggplot2::unit(0.75, "in"),
ggplot2plot.margin = ggplot2::margin(0.1, 0, 0.1, 0.75, "in"))
We fit both fixed effect (FE) and random effects (RE) models.
First, we fit a fixed effect model using the nma()
function with trt_effects = "fixed"
, using a probit link function link = "probit"
. We use \(\mathrm{N}(0, 10^2)\) prior distributions for the treatment effects \(d_k\), and \(\mathrm{N}(0, 100^2)\) prior distributions for the study-specific intercepts \(\mu_j\). We can examine the range of parameter values implied by these prior distributions with the summary()
method:
summary(normal(scale = 10))
#> A Normal prior distribution: location = 0, scale = 10.
#> 50% of the prior density lies between -6.74 and 6.74.
#> 95% of the prior density lies between -19.6 and 19.6.
summary(normal(scale = 100))
#> A Normal prior distribution: location = 0, scale = 100.
#> 50% of the prior density lies between -67.45 and 67.45.
#> 95% of the prior density lies between -196 and 196.
We also need to specify prior distributions for the latent cutpoints \(c_\textrm{PASI75}\) and \(c_\textrm{PASI90}\) on the underlying scale - here the PASI standardised mean difference due to the probit link (the cutpoint \(c_\textrm{PASI50}=0\)). To make these easier to reason about, we actually specify priors on the differences between adjacent cutpoints, e.g. \(c_\textrm{PASI90} - c_\textrm{PASI75}\) and \(c_\textrm{PASI75} - c_\textrm{PASI50}\). These can be given any positive-valued prior distribution, and Stan will automatically impose the necessary ordering constraints behind the scenes. We choose to give these implicit flat priors flat()
.
The model is fitted using the nma()
function.
<- nma(pso_net,
pso_fit_FE trt_effects = "fixed",
link = "probit",
prior_intercept = normal(scale = 100),
prior_trt = normal(scale = 10),
prior_aux = flat())
#> Note: Setting "Supportive care" as the network reference treatment.
Basic parameter summaries are given by the print()
method:
pso_fit_FE#> A fixed effects NMA with a ordered likelihood (probit link).
#> Inference for Stan model: ordered_multinomial.
#> 4 chains, each with iter=2000; warmup=1000; thin=1;
#> post-warmup draws per chain=1000, total post-warmup draws=4000.
#>
#> mean se_mean sd 2.5% 25% 50% 75% 97.5% n_eff Rhat
#> d[Ciclosporin] 1.91 0.01 0.34 1.29 1.67 1.89 2.13 2.60 1248 1
#> d[Efalizumab] 1.19 0.00 0.06 1.08 1.15 1.19 1.23 1.30 1867 1
#> d[Etanercept 25 mg] 1.51 0.00 0.10 1.32 1.45 1.51 1.57 1.70 2017 1
#> d[Etanercept 50 mg] 1.92 0.00 0.10 1.73 1.85 1.92 1.98 2.12 2207 1
#> d[Fumaderm] 1.48 0.01 0.47 0.64 1.16 1.45 1.78 2.49 2618 1
#> d[Infliximab] 2.33 0.00 0.26 1.84 2.15 2.31 2.50 2.87 2920 1
#> d[Methotrexate] 1.60 0.01 0.45 0.74 1.30 1.60 1.90 2.50 1639 1
#> lp__ -3405.11 0.08 3.50 -3412.80 -3407.31 -3404.83 -3402.62 -3399.14 1785 1
#> cc[PASI50] 0.00 NaN 0.00 0.00 0.00 0.00 0.00 0.00 NaN NaN
#> cc[PASI75] 0.76 0.00 0.03 0.70 0.74 0.76 0.78 0.82 5459 1
#> cc[PASI90] 1.57 0.00 0.05 1.46 1.53 1.57 1.60 1.67 6028 1
#>
#> Samples were drawn using NUTS(diag_e) at Thu Feb 24 09:37:11 2022.
#> For each parameter, n_eff is a crude measure of effective sample size,
#> and Rhat is the potential scale reduction factor on split chains (at
#> convergence, Rhat=1).
Note: the treatment effects are the opposite sign to those in TSD 2 (Dias et al. 2011). This is because we parameterise the linear predictor as \(\mu_j + d_k + c_m\), rather than \(\mu_j + d_k - c_m\). The interpretation here thus follows that of a standard binomial probit (or logit) regression; SMDs (or log ORs) greater than zero mean that the treatment increases the probability of an event compared to the comparator (and less than zero mean a reduction in probability). Here higher outcomes are positive, and all of the active treatments are estimated to increase the response (i.e. a greater reduction) on the PASI scale compared to the network reference (supportive care).
By default, summaries of the study-specific intercepts \(\mu_j\) are hidden, but could be examined by changing the pars
argument:
# Not run
print(pso_fit_FE, pars = c("d", "mu", "cc"))
The prior and posterior distributions can be compared visually using the plot_prior_posterior()
function:
plot_prior_posterior(pso_fit_FE)
Focusing specifically on the cutpoints we see that these are highly identified by the data, which is why the implicit flat priors work for these parameters.
plot_prior_posterior(pso_fit_FE, prior = "aux")
We now fit a random effects model using the nma()
function with trt_effects = "random"
. Again, we use \(\mathrm{N}(0, 10^2)\) prior distributions for the treatment effects \(d_k\), \(\mathrm{N}(0, 100^2)\) prior distributions for the study-specific intercepts \(\mu_j\), implicit flat prior distributions for the latent cutpoints, and we additionally use a \(\textrm{half-N}(2.5^2)\) prior for the heterogeneity standard deviation \(\tau\). We can examine the range of parameter values implied by these prior distributions with the summary()
method:
summary(normal(scale = 10))
#> A Normal prior distribution: location = 0, scale = 10.
#> 50% of the prior density lies between -6.74 and 6.74.
#> 95% of the prior density lies between -19.6 and 19.6.
summary(normal(scale = 100))
#> A Normal prior distribution: location = 0, scale = 100.
#> 50% of the prior density lies between -67.45 and 67.45.
#> 95% of the prior density lies between -196 and 196.
summary(half_normal(scale = 2.5))
#> A half-Normal prior distribution: location = 0, scale = 2.5.
#> 50% of the prior density lies between 0 and 1.69.
#> 95% of the prior density lies between 0 and 4.9.
Fitting the RE model
<- nma(pso_net,
pso_fit_RE trt_effects = "random",
link = "probit",
prior_intercept = normal(scale = 100),
prior_trt = normal(scale = 10),
prior_aux = flat(),
prior_het = half_normal(scale = 2.5),
adapt_delta = 0.99)
#> Note: Setting "Supportive care" as the network reference treatment.
Basic parameter summaries are given by the print()
method:
pso_fit_RE#> A random effects NMA with a ordered likelihood (probit link).
#> Inference for Stan model: ordered_multinomial.
#> 4 chains, each with iter=2000; warmup=1000; thin=1;
#> post-warmup draws per chain=1000, total post-warmup draws=4000.
#>
#> mean se_mean sd 2.5% 25% 50% 75% 97.5% n_eff Rhat
#> d[Ciclosporin] 2.04 0.01 0.45 1.29 1.73 2.01 2.30 3.05 1073 1.00
#> d[Efalizumab] 1.19 0.00 0.19 0.77 1.10 1.19 1.28 1.56 1495 1.00
#> d[Etanercept 25 mg] 1.52 0.01 0.26 0.99 1.40 1.52 1.65 2.06 1424 1.00
#> d[Etanercept 50 mg] 1.93 0.01 0.29 1.33 1.79 1.92 2.06 2.53 1123 1.01
#> d[Fumaderm] 1.49 0.01 0.63 0.36 1.08 1.46 1.87 2.80 3232 1.00
#> d[Infliximab] 2.32 0.01 0.40 1.51 2.09 2.32 2.56 3.06 3707 1.00
#> d[Methotrexate] 1.72 0.02 0.64 0.61 1.31 1.69 2.08 3.06 1502 1.00
#> lp__ -3410.70 0.31 6.74 -3424.14 -3415.44 -3410.47 -3405.94 -3398.19 481 1.00
#> tau 0.31 0.01 0.23 0.02 0.15 0.27 0.42 0.91 317 1.01
#> cc[PASI50] 0.00 NaN 0.00 0.00 0.00 0.00 0.00 0.00 NaN NaN
#> cc[PASI75] 0.76 0.00 0.03 0.70 0.74 0.76 0.78 0.82 10176 1.00
#> cc[PASI90] 1.56 0.00 0.05 1.47 1.53 1.56 1.60 1.66 9324 1.00
#>
#> Samples were drawn using NUTS(diag_e) at Thu Feb 24 09:38:03 2022.
#> For each parameter, n_eff is a crude measure of effective sample size,
#> and Rhat is the potential scale reduction factor on split chains (at
#> convergence, Rhat=1).
By default, summaries of the study-specific intercepts \(\mu_j\) and study-specific relative effects \(\delta_{jk}\) are hidden, but could be examined by changing the pars
argument:
# Not run
print(pso_fit_RE, pars = c("d", "cc", "mu", "delta"))
The prior and posterior distributions can be compared visually using the plot_prior_posterior()
function:
plot_prior_posterior(pso_fit_RE, prior = c("trt", "aux", "het"))
Model fit can be checked using the dic()
function:
<- dic(pso_fit_FE))
(dic_FE #> Residual deviance: 74.8 (on 58 data points)
#> pD: 25.4
#> DIC: 100.2
<- dic(pso_fit_RE))
(dic_RE #> Residual deviance: 63.1 (on 58 data points)
#> pD: 33.8
#> DIC: 96.9
The random effects model has a lower DIC and the residual deviance is closer to the number of data points, so is preferred in this case.
We can also examine the residual deviance contributions with the corresponding plot()
method.
plot(dic_FE)
plot(dic_RE)
Most data points are fit well, with posterior mean residual deviances close to the degrees of freedom. The Meffert 1997 study has a substantially higher residual deviance contribution, which could be investigated further to see why this study appears to be an outlier.
Dias et al. (2011) produce absolute predictions of probability of achieving responses at each PASI cutoff, assuming a Normal distribution for the baseline probit probability of PASI50 response on supportive care with mean \(-1.097\) and precision \(123\). We can replicate these results using the predict()
method. The baseline
argument takes a distr()
distribution object, with which we specify the corresponding Normal distribution. We set type = "response"
to produce predicted probabilities (type = "link"
would produce predicted probit probabilities).
<- predict(pso_fit_FE,
pred_FE baseline = distr(qnorm, mean = -1.097, sd = 123^-0.5),
type = "response")
pred_FE#> mean sd 2.5% 25% 50% 75% 97.5% Bulk_ESS Tail_ESS Rhat
#> pred[Supportive care, PASI50] 0.14 0.02 0.10 0.12 0.14 0.15 0.18 3675 3431 1
#> pred[Supportive care, PASI75] 0.03 0.01 0.02 0.03 0.03 0.04 0.05 3700 3564 1
#> pred[Supportive care, PASI90] 0.00 0.00 0.00 0.00 0.00 0.00 0.01 4056 3843 1
#> pred[Ciclosporin, PASI50] 0.78 0.10 0.57 0.71 0.79 0.85 0.94 1418 1844 1
#> pred[Ciclosporin, PASI75] 0.52 0.13 0.28 0.42 0.52 0.61 0.78 1422 1848 1
#> pred[Ciclosporin, PASI90] 0.24 0.11 0.08 0.16 0.22 0.30 0.49 1432 1850 1
#> pred[Efalizumab, PASI50] 0.54 0.04 0.45 0.51 0.54 0.57 0.62 3034 3365 1
#> pred[Efalizumab, PASI75] 0.25 0.04 0.19 0.23 0.25 0.28 0.33 3039 3542 1
#> pred[Efalizumab, PASI90] 0.07 0.02 0.04 0.06 0.07 0.08 0.11 2916 3577 1
#> pred[Etanercept 25 mg, PASI50] 0.66 0.05 0.56 0.63 0.66 0.69 0.75 2770 3324 1
#> pred[Etanercept 25 mg, PASI75] 0.37 0.05 0.27 0.33 0.36 0.40 0.47 2816 2892 1
#> pred[Etanercept 25 mg, PASI90] 0.13 0.03 0.08 0.11 0.12 0.14 0.19 2846 3012 1
#> pred[Etanercept 50 mg, PASI50] 0.79 0.04 0.71 0.77 0.79 0.82 0.86 2903 3108 1
#> pred[Etanercept 50 mg, PASI75] 0.53 0.05 0.42 0.49 0.53 0.56 0.63 2930 2763 1
#> pred[Etanercept 50 mg, PASI90] 0.23 0.04 0.16 0.20 0.23 0.26 0.32 2939 3201 1
#> pred[Fumaderm, PASI50] 0.63 0.16 0.32 0.52 0.64 0.76 0.92 2834 2182 1
#> pred[Fumaderm, PASI75] 0.37 0.17 0.11 0.24 0.34 0.48 0.74 2845 2208 1
#> pred[Fumaderm, PASI90] 0.14 0.11 0.02 0.06 0.11 0.19 0.43 2856 2170 1
#> pred[Infliximab, PASI50] 0.88 0.05 0.76 0.85 0.89 0.92 0.96 2908 2788 1
#> pred[Infliximab, PASI75] 0.68 0.10 0.48 0.61 0.68 0.74 0.85 2952 2780 1
#> pred[Infliximab, PASI90] 0.37 0.10 0.19 0.30 0.37 0.44 0.60 2987 2907 1
#> pred[Methotrexate, PASI50] 0.68 0.15 0.36 0.58 0.69 0.79 0.92 1724 2233 1
#> pred[Methotrexate, PASI75] 0.41 0.16 0.13 0.29 0.40 0.52 0.74 1723 2315 1
#> pred[Methotrexate, PASI90] 0.17 0.11 0.03 0.09 0.14 0.22 0.44 1739 2261 1
plot(pred_FE)
<- predict(pso_fit_RE,
pred_RE baseline = distr(qnorm, mean = -1.097, sd = 123^-0.5),
type = "response")
pred_RE#> mean sd 2.5% 25% 50% 75% 97.5% Bulk_ESS Tail_ESS Rhat
#> pred[Supportive care, PASI50] 0.14 0.02 0.10 0.12 0.14 0.15 0.18 4023 3849 1
#> pred[Supportive care, PASI75] 0.03 0.01 0.02 0.03 0.03 0.04 0.05 4429 3935 1
#> pred[Supportive care, PASI90] 0.00 0.00 0.00 0.00 0.00 0.00 0.01 4860 4105 1
#> pred[Ciclosporin, PASI50] 0.80 0.11 0.56 0.74 0.82 0.88 0.98 1415 897 1
#> pred[Ciclosporin, PASI75] 0.56 0.16 0.28 0.45 0.56 0.67 0.89 1413 893 1
#> pred[Ciclosporin, PASI90] 0.28 0.15 0.08 0.17 0.26 0.36 0.65 1414 868 1
#> pred[Efalizumab, PASI50] 0.53 0.08 0.36 0.49 0.54 0.58 0.69 2060 1302 1
#> pred[Efalizumab, PASI75] 0.26 0.07 0.13 0.22 0.25 0.29 0.40 2090 1270 1
#> pred[Efalizumab, PASI90] 0.07 0.03 0.03 0.06 0.07 0.09 0.14 2143 1414 1
#> pred[Etanercept 25 mg, PASI50] 0.66 0.09 0.45 0.61 0.66 0.71 0.84 2002 1032 1
#> pred[Etanercept 25 mg, PASI75] 0.37 0.10 0.19 0.32 0.37 0.42 0.59 2036 1054 1
#> pred[Etanercept 25 mg, PASI90] 0.14 0.06 0.05 0.10 0.13 0.16 0.28 2065 1066 1
#> pred[Etanercept 50 mg, PASI50] 0.79 0.09 0.58 0.75 0.80 0.84 0.92 1614 877 1
#> pred[Etanercept 50 mg, PASI75] 0.53 0.11 0.29 0.47 0.53 0.59 0.75 1594 793 1
#> pred[Etanercept 50 mg, PASI90] 0.24 0.09 0.09 0.19 0.23 0.28 0.45 1566 864 1
#> pred[Fumaderm, PASI50] 0.63 0.20 0.22 0.49 0.64 0.78 0.96 3576 2090 1
#> pred[Fumaderm, PASI75] 0.38 0.20 0.06 0.22 0.34 0.51 0.83 3603 2142 1
#> pred[Fumaderm, PASI90] 0.16 0.15 0.01 0.06 0.11 0.22 0.56 3599 2020 1
#> pred[Infliximab, PASI50] 0.87 0.08 0.66 0.84 0.89 0.93 0.98 3641 2308 1
#> pred[Infliximab, PASI75] 0.67 0.14 0.36 0.59 0.68 0.76 0.89 3634 2332 1
#> pred[Infliximab, PASI90] 0.37 0.14 0.13 0.28 0.37 0.46 0.67 3658 2420 1
#> pred[Methotrexate, PASI50] 0.70 0.18 0.30 0.58 0.72 0.84 0.98 1955 1070 1
#> pred[Methotrexate, PASI75] 0.45 0.21 0.10 0.29 0.43 0.60 0.89 1962 1084 1
#> pred[Methotrexate, PASI90] 0.21 0.17 0.02 0.09 0.16 0.28 0.67 1960 1093 1
plot(pred_RE)
If instead of information on the baseline PASI 50 response probit probability we have PASI 50 event counts, we can use these to construct a Beta distribution for the baseline probability of PASI 50 response. For example, if 56 out of 408 individuals achieved PASI 50 response on supportive care in the target population of interest, the appropriate Beta distribution for the response probability would be \(\textrm{Beta}(56, 408-56)\). We can specify this Beta distribution for the baseline response using the baseline_type = "reponse"
argument (the default is "link"
, used above for the baseline probit probability).
<- predict(pso_fit_FE,
pred_FE_beta baseline = distr(qbeta, 56, 408-56),
baseline_type = "response",
type = "response")
pred_FE_beta#> mean sd 2.5% 25% 50% 75% 97.5% Bulk_ESS Tail_ESS Rhat
#> pred[Supportive care, PASI50] 0.14 0.02 0.11 0.13 0.14 0.15 0.17 4044 3959 1
#> pred[Supportive care, PASI75] 0.03 0.01 0.02 0.03 0.03 0.04 0.05 4048 3860 1
#> pred[Supportive care, PASI90] 0.00 0.00 0.00 0.00 0.00 0.00 0.01 4507 3884 1
#> pred[Ciclosporin, PASI50] 0.78 0.10 0.57 0.72 0.79 0.85 0.94 1373 1898 1
#> pred[Ciclosporin, PASI75] 0.52 0.13 0.28 0.43 0.51 0.61 0.78 1374 1855 1
#> pred[Ciclosporin, PASI90] 0.24 0.11 0.08 0.16 0.22 0.30 0.49 1395 1949 1
#> pred[Efalizumab, PASI50] 0.54 0.04 0.46 0.51 0.54 0.56 0.62 3037 3686 1
#> pred[Efalizumab, PASI75] 0.26 0.03 0.20 0.23 0.25 0.28 0.32 2995 3379 1
#> pred[Efalizumab, PASI90] 0.07 0.02 0.05 0.06 0.07 0.08 0.10 3277 3741 1
#> pred[Etanercept 25 mg, PASI50] 0.66 0.05 0.57 0.63 0.66 0.69 0.75 2507 3049 1
#> pred[Etanercept 25 mg, PASI75] 0.37 0.05 0.28 0.33 0.37 0.40 0.47 2533 3312 1
#> pred[Etanercept 25 mg, PASI90] 0.13 0.03 0.08 0.11 0.13 0.14 0.19 2693 3128 1
#> pred[Etanercept 50 mg, PASI50] 0.79 0.04 0.72 0.77 0.79 0.82 0.86 2573 3247 1
#> pred[Etanercept 50 mg, PASI75] 0.53 0.05 0.43 0.49 0.53 0.56 0.63 2533 3153 1
#> pred[Etanercept 50 mg, PASI90] 0.23 0.04 0.16 0.20 0.23 0.26 0.31 2649 3277 1
#> pred[Fumaderm, PASI50] 0.63 0.16 0.32 0.52 0.64 0.75 0.92 2827 2222 1
#> pred[Fumaderm, PASI75] 0.37 0.17 0.11 0.24 0.34 0.47 0.74 2834 2222 1
#> pred[Fumaderm, PASI90] 0.14 0.11 0.02 0.07 0.11 0.19 0.43 2848 2289 1
#> pred[Infliximab, PASI50] 0.88 0.05 0.77 0.85 0.89 0.92 0.96 3009 2988 1
#> pred[Infliximab, PASI75] 0.68 0.10 0.49 0.61 0.68 0.75 0.85 3048 2964 1
#> pred[Infliximab, PASI90] 0.37 0.10 0.20 0.30 0.37 0.44 0.60 3106 2986 1
#> pred[Methotrexate, PASI50] 0.68 0.15 0.36 0.58 0.69 0.79 0.92 1707 2292 1
#> pred[Methotrexate, PASI75] 0.41 0.16 0.13 0.29 0.40 0.52 0.74 1702 2215 1
#> pred[Methotrexate, PASI90] 0.17 0.11 0.03 0.08 0.14 0.23 0.45 1723 2182 1
plot(pred_FE_beta)
<- predict(pso_fit_RE,
pred_RE_beta baseline = distr(qbeta, 56, 408-56),
baseline_type = "response",
type = "response")
pred_RE_beta#> mean sd 2.5% 25% 50% 75% 97.5% Bulk_ESS Tail_ESS Rhat
#> pred[Supportive care, PASI50] 0.14 0.02 0.11 0.13 0.14 0.15 0.17 4108 3777 1
#> pred[Supportive care, PASI75] 0.03 0.01 0.02 0.03 0.03 0.04 0.05 4579 3925 1
#> pred[Supportive care, PASI90] 0.00 0.00 0.00 0.00 0.00 0.00 0.01 5031 3914 1
#> pred[Ciclosporin, PASI50] 0.81 0.11 0.57 0.74 0.82 0.89 0.97 1394 911 1
#> pred[Ciclosporin, PASI75] 0.57 0.16 0.28 0.45 0.56 0.67 0.88 1393 976 1
#> pred[Ciclosporin, PASI90] 0.28 0.15 0.08 0.18 0.26 0.36 0.65 1392 876 1
#> pred[Efalizumab, PASI50] 0.54 0.08 0.36 0.49 0.54 0.58 0.69 2181 1368 1
#> pred[Efalizumab, PASI75] 0.26 0.07 0.13 0.22 0.25 0.29 0.40 2224 1377 1
#> pred[Efalizumab, PASI90] 0.07 0.03 0.03 0.06 0.07 0.09 0.14 2273 1397 1
#> pred[Etanercept 25 mg, PASI50] 0.66 0.09 0.45 0.61 0.66 0.72 0.84 2040 1056 1
#> pred[Etanercept 25 mg, PASI75] 0.37 0.10 0.19 0.32 0.37 0.42 0.59 2056 1063 1
#> pred[Etanercept 25 mg, PASI90] 0.14 0.06 0.05 0.10 0.13 0.16 0.28 2085 1025 1
#> pred[Etanercept 50 mg, PASI50] 0.79 0.08 0.59 0.75 0.80 0.84 0.92 1712 894 1
#> pred[Etanercept 50 mg, PASI75] 0.53 0.11 0.30 0.47 0.53 0.59 0.75 1721 886 1
#> pred[Etanercept 50 mg, PASI90] 0.24 0.09 0.09 0.19 0.23 0.28 0.45 1791 973 1
#> pred[Fumaderm, PASI50] 0.63 0.20 0.23 0.49 0.64 0.78 0.96 3615 2080 1
#> pred[Fumaderm, PASI75] 0.38 0.20 0.07 0.22 0.35 0.51 0.83 3635 2174 1
#> pred[Fumaderm, PASI90] 0.16 0.15 0.01 0.06 0.11 0.21 0.56 3625 2009 1
#> pred[Infliximab, PASI50] 0.87 0.08 0.66 0.84 0.89 0.93 0.98 3718 1943 1
#> pred[Infliximab, PASI75] 0.67 0.13 0.36 0.59 0.68 0.76 0.89 3716 1988 1
#> pred[Infliximab, PASI90] 0.37 0.14 0.12 0.28 0.37 0.46 0.66 3737 1949 1
#> pred[Methotrexate, PASI50] 0.70 0.18 0.30 0.59 0.72 0.84 0.98 1952 1098 1
#> pred[Methotrexate, PASI75] 0.45 0.21 0.10 0.29 0.43 0.59 0.89 1960 1049 1
#> pred[Methotrexate, PASI90] 0.21 0.17 0.02 0.09 0.16 0.28 0.66 1964 1026 1
plot(pred_RE_beta)
(Notice that these results are equivalent to those calculated above using the Normal distribution for the baseline probit probability, since these event counts correspond to the same probit probability.)
We can modify the plots using standard ggplot2
functions. For example, to plot the cutpoints together with a colour coding (instead of split into facets):
library(ggplot2)
plot(pred_RE, position = position_dodge(width = 0.75)) +
facet_null() +
aes(colour = Category) +
scale_colour_brewer(palette = "Blues")
If the baseline
argument is omitted, predicted probabilities will be produced for every study in the network based on their estimated baseline probit probability \(\mu_j\).
Treatment rankings, rank probabilities, and cumulative rank probabilities can also be produced. We set lower_better = FALSE
since higher outcome categories are better (the outcomes are positive).
<- posterior_ranks(pso_fit_RE, lower_better = FALSE))
(pso_ranks #> mean sd 2.5% 25% 50% 75% 97.5% Bulk_ESS Tail_ESS Rhat
#> rank[Supportive care] 7.99 0.12 8 8 8 8 8 1346 NA 1
#> rank[Ciclosporin] 2.74 1.28 1 2 3 4 5 3404 3047 1
#> rank[Efalizumab] 6.32 0.83 4 6 6 7 7 2290 2014 1
#> rank[Etanercept 25 mg] 4.94 1.08 3 4 5 6 7 2962 3061 1
#> rank[Etanercept 50 mg] 3.04 1.22 1 2 3 4 6 1990 1868 1
#> rank[Fumaderm] 4.91 1.95 1 3 5 7 7 3486 1253 1
#> rank[Infliximab] 1.84 1.23 1 1 1 2 5 1327 1624 1
#> rank[Methotrexate] 4.22 1.87 1 3 4 6 7 2792 2651 1
plot(pso_ranks)
<- posterior_rank_probs(pso_fit_RE, lower_better = FALSE))
(pso_rankprobs #> p_rank[1] p_rank[2] p_rank[3] p_rank[4] p_rank[5] p_rank[6] p_rank[7] p_rank[8]
#> d[Supportive care] 0.00 0.00 0.00 0.00 0.00 0.00 0.01 0.99
#> d[Ciclosporin] 0.18 0.30 0.26 0.17 0.08 0.02 0.00 0.00
#> d[Efalizumab] 0.00 0.00 0.01 0.02 0.10 0.36 0.50 0.00
#> d[Etanercept 25 mg] 0.00 0.02 0.09 0.20 0.39 0.26 0.05 0.00
#> d[Etanercept 50 mg] 0.09 0.29 0.28 0.24 0.09 0.02 0.01 0.00
#> d[Fumaderm] 0.07 0.09 0.10 0.12 0.16 0.19 0.28 0.01
#> d[Infliximab] 0.58 0.18 0.13 0.07 0.03 0.01 0.00 0.00
#> d[Methotrexate] 0.09 0.13 0.15 0.19 0.16 0.14 0.15 0.00
plot(pso_rankprobs)
<- posterior_rank_probs(pso_fit_RE, lower_better = FALSE, cumulative = TRUE))
(pso_cumrankprobs #> p_rank[1] p_rank[2] p_rank[3] p_rank[4] p_rank[5] p_rank[6] p_rank[7] p_rank[8]
#> d[Supportive care] 0.00 0.00 0.00 0.00 0.00 0.00 0.01 1
#> d[Ciclosporin] 0.18 0.47 0.73 0.90 0.98 1.00 1.00 1
#> d[Efalizumab] 0.00 0.00 0.01 0.03 0.14 0.50 1.00 1
#> d[Etanercept 25 mg] 0.00 0.02 0.10 0.30 0.69 0.95 1.00 1
#> d[Etanercept 50 mg] 0.09 0.37 0.65 0.89 0.97 0.99 1.00 1
#> d[Fumaderm] 0.07 0.16 0.26 0.37 0.53 0.71 0.99 1
#> d[Infliximab] 0.58 0.76 0.89 0.96 0.98 1.00 1.00 1
#> d[Methotrexate] 0.09 0.22 0.36 0.55 0.71 0.85 1.00 1
plot(pso_cumrankprobs)