The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.
The self-adapting mixture prior (SAMprior) package is designed to enhance the effectiveness and practicality of clinical trials by leveraging historical information or real-world data [1]. The package incorporates historical data into a new trial using an informative prior constructed based on historical data while mixing a non-informative prior to enhance the robustness of information borrowing. It utilizes a data-driven way to determine a self-adapting mixture weight that dynamically favors the informative (non-informative) prior component when there is little (substantial) evidence of prior-data conflict. Operating characteristics are evaluated and compared to the robust Meta-Analytic-Predictive (rMAP) prior [2], which assigns a fixed weight of 0.5.
Consider a randomized clinical trial to compare a treatment with a control in patients with ankylosing spondylitis. The primary efficacy endpoint is binary, indicating whether a patient achieves 20% improvement at week six according to the Assessment of SpondyloArthritis International Society criteria [3]. Nine historical data available to the control were used to construct the MAP prior:
| study | n | r |
|---|---|---|
| Baeten (2013) | 6 | 1 |
| Deodhar (2016) | 122 | 35 |
| Deodhar (2019) | 104 | 31 |
| Erdes (2019) | 23 | 10 |
| Huang (2019) | 153 | 56 |
| Kivitz (2018) | 117 | 55 |
| Pavelka (2017) | 76 | 28 |
| Sieper (2017) | 74 | 21 |
| Van der Heijde (2018) | 87 | 35 |
SAM prior is constructed by mixing an informative prior \(\pi_1(\theta)\), constructed based on
historical data, with a non-informative prior \(\pi_0(\theta)\) using the mixture weight
\(w\) determined by
SAM_weight function according to the
degree of prior-data conflict [1]. The following sections describe how
to construct SAM prior in details.
To construct informative priors based on the aforementioned nine
historical data, we apply gMAP function
from RBesT to perform meta-analysis. This informative prior results in a
representative form from a large MCMC samples, and it can be converted
to a parametric representation with the
automixfit function using
expectation-maximization (EM) algorithm [4]. This informative prior is
also called MAP prior.
# load R packages
library(ggplot2)
theme_set(theme_bw()) # sets up plotting theme
set.seed(22)
map_ASAS20 <- gMAP(cbind(r, n-r) ~ 1 | study,
family = binomial,
data = ASAS20,
tau.dist = "HalfNormal",
tau.prior = 1,
beta.prior = 2)## Assuming default prior location for beta: 0
## Warning: Bulk Effective Samples Size (ESS) is too low, indicating posterior means and medians may be unreliable.
## Running the chains for more iterations may help. See
## https://mc-stan.org/misc/warnings.html#bulk-ess
## Warning: Tail Effective Samples Size (ESS) is too low, indicating posterior variances and tail quantiles may be unreliable.
## Running the chains for more iterations may help. See
## https://mc-stan.org/misc/warnings.html#tail-ess
## Final MCMC sample equivalent to less than 1000 independent draws.
## Please consider increasing the MCMC simulation size.
## EM for Beta Mixture Model
## Log-Likelihood = 647.1587
##
## Univariate beta mixture
## Mixture Components:
## comp1 comp2
## w 0.5832492 0.4167508
## a 47.4117638 8.8340818
## b 85.9006890 15.6137354
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## ℹ The deprecated feature was likely used in the RBesT package.
## Please report the issue at <https://github.com/Novartis/RBesT/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
The resulting MAP prior is approximated by a mixture of conjugate priors, given by \(\pi_1(\theta) = 0.63 Beta(42.5, 77.2) + 0.37 Beta(7.2, 12.4)\), with \(\hat{\theta}_h \approx 0.36\).
Let \(\theta\) and \(\theta_h\) denote the response rates associated with the current arm data \(D\) and historical \(D_h\), respectively. Let \(\delta\) denote the clinically significant difference such that is \(|\theta_h - \theta| \ge \delta\), then \(\theta_h\) is regarded as clinically distinct from \(\theta\), and it is therefore inappropriate to borrow any information from \(D_h\). Consider two hypotheses:
\[ H_0: \theta = \theta_h, ~~ H_1: \theta = \theta_h + \delta ~ \text{or} ~ \theta = \theta_h - \delta. \] \(H_0\) represents that \(D_h\) and \(D\) are consistent (i.e., no prior-data conflict) and thus information borrowing is desirable, whereas \(H_1\) represents that the response rate of \(D\) differs from \(D_h\) to such a degree that no information should be borrowed.
The SAM prior uses the likelihood ratio test (LRT) statistics \(R\) to quantify the degree of prior-data conflict and determine the extent of information borrowing. \[ R = \frac{P(D | H_0, \theta_h)}{P(D | H_1, \theta_h)} = \frac{P(D | \theta = \theta_h)}{\max \{ P(D | \theta = \theta_h + \delta), P(D | \theta = \theta_h - \delta) \}} , \] where \(P(D | \cdot)\) denotes the likelihood function. An alternative Bayesian choice is the posterior probability ratio (PPR): \[ R = \frac{P(D | H_0, \theta_h)}{P(D | H_1, \theta_h)} = \frac{P(H_0)}{P(H_1)} \times BF , \] where \(P(H_0)\) and \(P(H_1)\) is the prior probabilities of \(H_0\) and \(H_1\) being true. \(BF\) is the Bayes Factor that in this case is the same as LRT.
The SAM prior, denoted as \(\pi_{\text{sam}}(\theta)\), is then defined as a mixture of an informative prior \(\pi_1(\theta)\), constructed based on \(D_h\), with a non-informative prior \(\pi_0(\theta)\): \[\pi_{\text{sam}}(\theta) = w \pi_1(\theta) + (1 - w) \pi_0(\theta)\] where the mixture weight \(w\) is calculated as: \[w = \frac{R}{1 + R}.\] As the level of prior-data conflict increases, the likelihood ratio \(R\) decreases, resulting in a decrease in the weight \(w\) assigned to the informative prior and a decrease in information borrowing. As a result, \(\pi_{\text{sam}}(\theta)\) is data-driven and has the ability to self-adapt the information borrowing based on the degree of prior-data conflict.
To calculate mixture weight \(w\) of
the SAM prior, we assume the sample size enrolled in the control arm is
\(n = 35\), with \(r = 10\) responses, then we can apply
function SAM_weight in SAMprior as
follows:
n <- 35; r = 10
wSAM_LRT <- SAM_weight(if.prior = map_automix,
delta = 0.2,
n = n, r = r)
cat('SAM weight: ', wSAM_LRT)## SAM weight: 0.8019795
The default method to calculate \(w\) is using LRT, which is fully data-driven. However, if investigators want to incorporate prior information on prior-data conflict to determine the mixture weight \(w\), this can be achieved by using PPR method as follows:
wSAM_PPR <- SAM_weight(if.prior = map_automix,
delta = 0.2,
method.w = 'PPR',
prior.odds = 3/7,
n = n, r = r)
cat('SAM weight: ', wSAM_PPR)## SAM weight: 0.6344637
The prior.odds indicates the prior
probability of \(H_0\) over the prior
probability of \(H_1\). In this case
(e.g., prior.odds = 3/7), the prior
information favors the presence prior-data conflict and it results in a
decreased mixture weight.
When historical information is congruent with the current control arm, SAM weight reaches to the highest peak. As the level of prior-data conflict increases, SAM weight decreases. This demonstrates that SAM prior is data-driven and self-adapting, favoring the informative (non-informative) prior component when there is little (substantial) evidence of prior-data conflict.
## Warning: `qplot()` was deprecated in ggplot2 3.4.0.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
To construct the SAM prior, we mix the derived informative prior
\(\pi_1(\theta)\) with a vague prior
\(\pi_0(\theta)\) using pre-determined
mixture weight by SAM_prior function in
SAMprior as follows:
SAM.prior <- SAM_prior(if.prior = map_automix,
nf.prior = mixbeta(nf.prior = c(1,1,1)),
weight = wSAM_LRT)
SAM.prior## Univariate beta mixture
## Mixture Components:
## comp1 comp2 nf.prior
## w 0.4677539 0.3342256 0.1980205
## a 47.4117638 8.8340818 1.0000000
## b 85.9006890 15.6137354 1.0000000
where the non-informative prior \(\pi_0(\theta)\) follows a uniform distribution.
In this section, we aim to investigate the operating characteristics of the SAM prior, constructed based on the historical data in the context of ankylosing spondylitis trial. The incorporation of historical information is expected to be beneficial in reducing the required sample size for the current arms. To achieve this, we assume a 1:2 ratio between the control and treatment arms.
We compare the operating characteristics of the SAM prior and rMAP prior with pre-specified fixed weight under various scenarios. Specifically, we will evaluate the relative bias and relative mean squared error (MSE) of these methods. The relative bias and relative MSE are defined as the differences between the bias/MSE of a given method and the bias/MSE obtained when using a non-informative prior for the estimated response rate in the control arm.
Additionally, we investigate the Type I error and power of the methods under different degrees of prior-data conflicts. The decision regarding whether a treatment is superior or inferior to a standard control will be based on the condition: \[\Pr(\theta_t - \theta > \Delta \mid D) > C,\] where \(\Delta\) is the clinical margin, and we let \(\Delta = 0\). \(C\) is the posterior probability cutoff. We calibrated the posterior probability cutoff under the null hypothesis, where there is no treatment effect difference between the treatment and control arms and the historical data and current control arm are assumed to arise from the same data-generating process, to ensure the Type I error is maintained at the nominal level.
In SAMprior, the operating characteristics can be considered in following steps:
Specify priors: This step involves constructing informative prior based on historical data and non-informative prior.
Specify design parameters for the
get_OC function: This step involves
defining the design parameters for evaluating the operating
characteristics. These parameters include the clinically significant
difference (CSD) used in SAM prior calculation, the method used to
determine the mixture weight for the SAM prior, the sample sizes for the
control and treatment arms, the choice of weight for the robust MAP
prior used as a benchmark.
Scenarios: This step specifies the vectors of response rates for
the control and treatment arms. The get_OC
function calibrates the posterior probability cutoff under the
assumption that the null calibration scenario is given by \(\theta =\)
theta[1] and \(\theta_t =\)
theta[1] \(+
\Delta\) with \(\Delta =
0\).
To evaluate Type I error, we consider four scenarios. In the first scenario, we assume \(\theta = \theta_t = \theta_h\), so each method should calibrate the Type I error rate to the nominal level. The second and third scenarios represent minimal prior-data conflict, whereas the last scenario represents substantial prior-data conflict. Overall, the results indicate that both SAM and rMAP effectively control the Type I error under minimal prior-data conflict, while SAM demonstrates better Type I error control in the presence of substantial prior-data conflict.
TypeI <- get_OC(if.prior = map_automix, ## MAP prior from historical data
nf.prior = mixbeta(c(1,1,1)), ## Non-informative prior for mixture prior
prior.t = mixbeta(c(1,1,1)), ## Non-informative prior for treatment arm
delta = 0.2, ## CSD for SAM prior
## Method to determine the mixture weight for the SAM prior
method.w = 'LRT',
n = 35, n.t = 70, ## Sample size for control and treatment arms
if.rMAP = TRUE, ## Output robust MAP prior for comparison
weight = 0.5, ## Weight for robust MAP prior
## Trial settings
alternative = "greater", ## Direction of the posterior decision. Must be one of "greater" or "less"
margin = 0, ## Clinical margin
## Response rates for control and treatment arms
theta = c(summary(map_automix)['mean'], 0.30, 0.40, 0.60),
theta.t = c(summary(map_automix)['mean'], 0.30, 0.38, 0.61))
kable(TypeI)| Scenarios | theta | theta.t | Methods | Cutoffs | Bias.of.theta | RMSE.of.theta | Weight | Probability.of.Rejection |
|---|---|---|---|---|---|---|---|---|
| 1 | 0.358 | 0.358 | NP | 0.9469 | 0.0077 | 0.0770 | 0.0000 | 0.0507 |
| 1 | 0.358 | 0.358 | rMAP | 0.9279 | 0.0015 | 0.0434 | 0.5000 | 0.0496 |
| 1 | 0.358 | 0.358 | SAM | 0.9471 | 0.0017 | 0.0528 | 0.7214 | 0.0502 |
| 2 | 0.300 | 0.300 | NP | 0.9469 | 0.0108 | 0.0741 | 0.0000 | 0.0502 |
| 2 | 0.300 | 0.300 | rMAP | 0.9279 | 0.0290 | 0.0544 | 0.5000 | 0.0216 |
| 2 | 0.300 | 0.300 | SAM | 0.9471 | 0.0240 | 0.0621 | 0.6585 | 0.0363 |
| 3 | 0.400 | 0.380 | NP | 0.9469 | 0.0054 | 0.0785 | 0.0000 | 0.0340 |
| 3 | 0.400 | 0.380 | rMAP | 0.9279 | -0.0177 | 0.0538 | 0.5000 | 0.0544 |
| 3 | 0.400 | 0.380 | SAM | 0.9471 | -0.0135 | 0.0642 | 0.6623 | 0.0539 |
| 4 | 0.600 | 0.610 | NP | 0.9469 | -0.0054 | 0.0785 | 0.0000 | 0.0652 |
| 4 | 0.600 | 0.610 | rMAP | 0.9279 | -0.0330 | 0.1039 | 0.5000 | 0.1554 |
| 4 | 0.600 | 0.610 | SAM | 0.9471 | -0.0134 | 0.0912 | 0.0845 | 0.0997 |
For power evaluation, we also consider four scenarios. In the first scenario, we assume \(\theta = \theta_t = \theta_h\), so each method should calibrate the Type I error rate to the nominal level. The second and third scenarios represent minimal prior-data conflict, whereas the last scenario represents substantial prior-data conflict. Overall, the results show that the SAM prior achieves performance similar to that of rMAP, and both outperform non-informative prior (NP) when prior-data conflict is minimal. However, when prior-data conflict is substantial, the SAM prior yields better performance than rMAP.
Power <- get_OC(if.prior = map_automix, ## MAP prior from historical data
nf.prior = mixbeta(c(1,1,1)), ## Non-informative prior for mixture prior
prior.t = mixbeta(c(1,1,1)), ## Non-informative prior for treatment arm
delta = 0.2, ## CSD for SAM prior
## Method to determine the mixture weight for the SAM prior
method.w = 'LRT',
n = 35, n.t = 70, ## Sample size for control and treatment arms
if.rMAP = TRUE, ## Output robust MAP prior for comparison
weight = 0.5, ## Weight for robust MAP prior
## Trial settings
alternative = "greater", ## Direction of the posterior decision. Must be one of "greater" or "less"
margin = 0, ## Clinical margin,
## Response rates for control and treatment arms
theta = c(summary(map_automix)['mean'], 0.36, 0.42, 0.16),
theta.t = c(summary(map_automix)['mean'], 0.56, 0.62, 0.36))
kable(Power)| Scenarios | theta | theta.t | Methods | Cutoffs | Bias.of.theta | RMSE.of.theta | Weight | Probability.of.Rejection |
|---|---|---|---|---|---|---|---|---|
| 1 | 0.358 | 0.358 | NP | 0.9469 | 0.0077 | 0.0770 | 0.0000 | 0.0507 |
| 1 | 0.358 | 0.358 | rMAP | 0.9279 | 0.0015 | 0.0434 | 0.5000 | 0.0496 |
| 1 | 0.358 | 0.358 | SAM | 0.9471 | 0.0017 | 0.0528 | 0.7214 | 0.0502 |
| 2 | 0.360 | 0.560 | NP | 0.9469 | 0.0076 | 0.0771 | 0.0000 | 0.6417 |
| 2 | 0.360 | 0.560 | rMAP | 0.9279 | 0.0006 | 0.0436 | 0.5000 | 0.8513 |
| 2 | 0.360 | 0.560 | SAM | 0.9471 | 0.0009 | 0.0530 | 0.7204 | 0.8312 |
| 3 | 0.420 | 0.620 | NP | 0.9469 | 0.0043 | 0.0790 | 0.0000 | 0.6394 |
| 3 | 0.420 | 0.620 | rMAP | 0.9279 | -0.0255 | 0.0619 | 0.5000 | 0.8396 |
| 3 | 0.420 | 0.620 | SAM | 0.9471 | -0.0188 | 0.0721 | 0.6100 | 0.7752 |
| 4 | 0.160 | 0.360 | NP | 0.9469 | 0.0184 | 0.0614 | 0.0000 | 0.7184 |
| 4 | 0.160 | 0.360 | rMAP | 0.9279 | 0.0502 | 0.0894 | 0.5000 | 0.5446 |
| 4 | 0.160 | 0.360 | SAM | 0.9471 | 0.0286 | 0.0769 | 0.1268 | 0.6618 |
Finally, we present an example showing how to calibrate the posterior probability cutoff and make a final decision on whether the treatment is superior to a standard control after the trial has been completed and the data have been collected.
The calibration step aims to identify the posterior probability cutoff \(C\) such that the Type I error is controlled at a prespecified level. For superiority, this is based on the posterior decision rule \[ \Pr(\theta_t - \theta > 0 \mid D) > C. \]
This calibration can be carried out using the
calibrate_cutoff_2arm function, as
illustrated below:
## Sample size and number of responses for treatment arm
n_t <- 70; x_t <- 22
## Calibrate the posterior probability cutoff
PPC <- calibrate_cutoff_2arm(if.prior = map_automix, ## MAP prior from historical data
nf.prior = mixbeta(c(1,1,1)), ## Non-informative prior for mixture prior
prior.t = mixbeta(c(1,1,1)), ## Non-informative prior for treatment arm
target = 0.05, ## Targeted Type I error rate
n.t = n_t, n = n, ## Sample size for treatment and control arms, respectively
theta.t = summary(map_automix)['mean'], ## The true response rate for treatment arm
theta = summary(map_automix)['mean'], ## The true response rate for control arm
## Method to determine the mixture weight for the SAM prior
method = 'SAM', ## Method
delta = 0.2, ## CSD for SAM prior
## Trial settings
alternative = "greater", ## Direction of the posterior decision. Must be one of "greater" or "less".
margin = 0 ## Clinical margin
)To make the final decision using the calibrated posterior probability
cutoff \(C\), we next update the
posterior distributions based on the observed trial data. In this
example, the final posterior updating step is carried out using the
postmix function from RBesT, while the
calibrated cutoff \(C\) is obtained
from calibrate_cutoff_2arm in SAMprior.
The treatment is then declared superior if the resulting posterior
probability exceeds the calibrated cutoff. The posterior updating step
is illustrated below:
## first obtain posterior distributions...
post_SAM <- postmix(priormix = SAM.prior, ## SAM Prior
r = r, n = n)
post_trt <- postmix(priormix = mixbeta(c(1,1,1)), ## Non-informative prior
r = x_t, n = n_t)
## Define the decision function
decision = decision2S(PPC$cutoff, 0, lower.tail=FALSE)
## Decision-making
decision(post_trt, post_SAM)## [1] 0
[1] Yang P. et al., Biometrics, 2023; 00, 1–12. https://doi.org/10.1111/biom.13927
[2] Schmidli H. et al., Biometrics 2014; 70(4):1023-1032.
[3] Baeten D. et al., The Lancet, 2013; (382), 9906, p
1705.
[4] Neuenschwander B. et al., Clin Trials. 2010; 7(1):5-18.
## R version 4.5.1 (2025-06-13)
## Platform: aarch64-apple-darwin20
## Running under: macOS Sequoia 15.7.5
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1
##
## locale:
## [1] C/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
##
## time zone: America/Chicago
## tzcode source: internal
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] ggplot2_4.0.0 knitr_1.50 SAMprior_3.0.0 MatchIt_4.7.2 RBesT_1.8-2
##
## loaded via a namespace (and not attached):
## [1] gtable_0.3.6 tensorA_0.36.2.1 xfun_0.54
## [4] bslib_0.9.0 QuickJSR_1.8.1 inline_0.3.21
## [7] vctrs_0.6.5 tools_4.5.1 generics_0.1.4
## [10] stats4_4.5.1 curl_7.0.0 parallel_4.5.1
## [13] tibble_3.3.0 pkgconfig_2.0.3 checkmate_2.3.3
## [16] RColorBrewer_1.1-3 S7_0.2.0 distributional_0.5.0
## [19] RcppParallel_5.1.11-1 assertthat_0.2.1 lifecycle_1.0.4
## [22] compiler_4.5.1 farver_2.1.2 stringr_1.5.2
## [25] codetools_0.2-20 htmltools_0.5.8.1 sass_0.4.10
## [28] bayesplot_1.14.0 yaml_2.3.10 Formula_1.2-5
## [31] pillar_1.11.1 crayon_1.5.3 jquerylib_0.1.4
## [34] cachem_1.1.0 StanHeaders_2.32.10 abind_1.4-8
## [37] posterior_1.6.1 rstan_2.32.7 Metrics_0.1.4
## [40] tidyselect_1.2.1 digest_0.6.37 mvtnorm_1.3-3
## [43] stringi_1.8.7 dplyr_1.1.4 reshape2_1.4.4
## [46] labeling_0.4.3 fastmap_1.2.0 grid_4.5.1
## [49] colorspace_2.1-2 cli_3.6.5 magrittr_2.0.4
## [52] loo_2.8.0 dichromat_2.0-0.1 pkgbuild_1.4.8
## [55] withr_3.0.2 scales_1.4.0 backports_1.5.0
## [58] rmarkdown_2.30 matrixStats_1.5.0 gridExtra_2.3
## [61] evaluate_1.0.5 V8_8.0.1 rstantools_2.5.0
## [64] rlang_1.1.6 Rcpp_1.1.0 glue_1.8.0
## [67] rstudioapi_0.17.1 jsonlite_2.0.0 R6_2.6.1
## [70] plyr_1.8.9
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.