| Title: | Bayesian Prior Elicitation and Diagnostics for Clinical Trials |
| Version: | 0.3.2 |
| Description: | A toolkit for constructing, validating, and justifying Bayesian priors in clinical trial settings. Implements expert elicitation via quantile matching, the roulette method, and moment matching across six distribution families, linear and logarithmic expert pooling, prior-data conflict diagnostics including the Box p-value, surprise index, information divergence, and Mahalanobis distance, sensitivity analyses with tornado and influence heatmap plots, sceptical, robust, and power priors, and automated prior justification reports. Includes a fully modular 'Shiny' application for interactive use. Methods based on O'Hagan et al. (2006, ISBN:9780470029886), Box (1980) <doi:10.2307/2982063>, Oakley and O'Hagan (2010) https://tonyohagan.co.uk/shelf/, Schmidli et al. (2014) <doi:10.1111/biom.12242>, Ibrahim and Chen (2000) <doi:10.1214/ss/1009212673>, Spiegelhalter et al. (1994) <doi:10.2307/2983527>. |
| License: | GPL-3 |
| URL: | https://github.com/ndohpenngit/bayprior |
| BugReports: | https://github.com/ndohpenngit/bayprior/issues |
| Depends: | R (≥ 4.1.0) |
| Imports: | cli (≥ 3.6.0), config (≥ 0.3.1), dplyr (≥ 1.1.0), DT (≥ 0.27), ggplot2 (≥ 3.4.0), glue (≥ 1.6.2), golem (≥ 0.4.1), plotly (≥ 4.10.1), purrr (≥ 1.0.0), rlang (≥ 1.2.0), shiny (≥ 1.7.4), shinycssloaders (≥ 1.0.0), shinydashboard (≥ 0.7.2), shinyjs (≥ 2.1.0), shinyWidgets (≥ 0.7.6), stats |
| Suggests: | htmlwidgets (≥ 1.5.4), knitr (≥ 1.40), patchwork (≥ 1.1.0), quarto (≥ 1.4), rmarkdown (≥ 2.20), shinytest2 (≥ 0.3.1), spelling (≥ 2.2.0), testthat (≥ 3.0.0), vdiffr (≥ 1.0.0), withr (≥ 2.5.0) |
| VignetteBuilder: | knitr |
| Config/Needs/vignettes: | knitr, rmarkdown |
| Config/testthat/edition: | 3 |
| Encoding: | UTF-8 |
| Language: | en-GB |
| RoxygenNote: | 7.3.3 |
| SystemRequirements: | Quarto CLI (>= 1.5, https://quarto.org) |
| NeedsCompilation: | no |
| Packaged: | 2026-08-19 12:37:00 UTC; ndohpenn |
| Author: | Ndoh Penn |
| Maintainer: | Ndoh Penn <ndohpenn9@gmail.com> |
| Repository: | CRAN |
| Date/Publication: | 2026-08-19 14:10:03 UTC |
bayprior: Bayesian Prior Elicitation for Clinical Trials
Description
A toolkit for constructing, validating, and justifying Bayesian priors in clinical trial settings. Implements SHELF-style expert elicitation (quantile matching, roulette method, moment matching) across six distribution families, linear and logarithmic expert pooling with compatibility validation, prior-data conflict diagnostics (Box p-value, surprise index, KL divergence, Bhattacharyya overlap, Mahalanobis check) for binary, continuous, Poisson/count, and survival data types, sensitivity analyses with tornado and influence plots, sceptical/robust/power priors, and automated HTML/PDF/Word regulatory reports informed by FDA and EMA guidance on Bayesian methods. Includes a fully modular Shiny application with automatic output reset on input change.
Main workflow
-
Elicitation –
elicit_beta,elicit_normal,elicit_gamma,elicit_lognormal,elicit_exponential,elicit_weibull,elicit_roulette,elicit_mixture -
Expert pooling –
aggregate_experts -
Conflict diagnostics –
prior_conflict,conflict_mahalanobis -
Sensitivity analysis –
sensitivity_grid,sensitivity_cri -
Robust priors –
sceptical_prior,robust_prior,calibrate_power_prior -
Reporting –
prior_report -
Shiny app –
run_app
Distribution families
betaResponse rates and proportions – support (0, 1)
normalMean differences and log odds ratios – support (-Inf, Inf)
gammaEvent rates and median survival – support (0, Inf)
lognormalHazard ratios and PK parameters – support (0, Inf)
exponentialConstant hazard rates and Poisson rate priors – support (0, Inf). Conjugate with Poisson and survival data via Gamma-Poisson/Exponential updating.
weibullNon-constant hazard survival times (OS, PFS) – support (0, Inf). Posterior approximated via Normal matching.
Data types for conflict diagnostics and sensitivity
"binary"Events / sample size (x, n). Conjugate: Beta-Binomial.
"continuous"Observed mean, SD, sample size (x, sd, n). Conjugate: Normal-Normal.
"poisson"Event count / exposure person-time (x, n). Conjugate: Gamma-Poisson.
"survival"Events / total follow-up time (x, n). Conjugate: Gamma-Exponential.
References
O'Hagan et al. (2006). Uncertain Judgements. Wiley.
Box (1980). JRSS-A, 143, 383–430.
Schmidli et al. (2014). Biometrics, 70, 1023–1032.
Ibrahim & Chen (2000). Statistical Science, 15, 46–60.
Spiegelhalter et al. (1994). JRSS-A, 157, 357–416.
FDA (2026). Use of Bayesian Methodology in Clinical Trials of Drug and Biological Products.
Author(s)
Maintainer: Ndoh Penn ndohpenn9@gmail.com
See Also
Useful links:
Report bugs at https://github.com/ndohpenngit/bayprior/issues
Derive a single-family working prior from a mixture (internal)
Description
Sensitivity grids are defined over a single distribution family's
hyperparameters, so mixture priors (from aggregate_experts
or robust_prior) need a single-family stand-in. This
moment-matches the mixture's actual pooled mean and SD (from
prior$fit_summary) to the dominant component's family, so the
working prior reflects the full pooled information rather than
discarding all but one component. Falls back to the dominant component
alone, with a warning, if the family cannot be moment-matched from
mean/SD (e.g. "exponential", "weibull") or if
fit_summary$sd is unavailable (e.g. logarithmic pooling).
Usage
.mixture_working_prior(prior, quiet = FALSE)
Arguments
prior |
A |
quiet |
Logical. If |
Details
Shared by sensitivity_grid and the Shiny sensitivity
module (mod_sensitivity.R) so that the parameter ranges shown in
the UI are always centred on the same working prior actually analysed.
See aggregate_experts for the pooled mean/variance
formula, and elicit_beta, elicit_normal,
elicit_gamma, elicit_lognormal for each
family's moment-matching identities.
Value
A single-family bayprior object.
Pairwise Bhattacharyya Coefficients
Description
Computes pairwise Bhattacharyya coefficients between a list of prior distributions. Analytical for Beta-Beta pairs; numerical otherwise.
Usage
.pairwise_bhattacharyya(priors)
Arguments
priors |
A named list of |
Value
A symmetric matrix of Bhattacharyya coefficients (values in [0, 1]).
Determine an appropriate (lo, hi) support range for a prior (internal)
Description
Shared per-family range logic, used by both .density_grid() (for
plotting) and .bc_coef() (for numerical Bhattacharyya integration).
Uses exact 0.001/0.999 quantiles where available (lognormal, gamma,
exponential, weibull), [0, 1] for beta, and
fit_summary$q025/q975 %||% mean +/- 4*sd as a general fallback
(normal, and any family without a dedicated branch). Non-negative-support
families have lo clamped to 1e-6.
Usage
.prior_range(prior)
Arguments
prior |
A |
Value
A list with numeric elements lo and hi.
Aggregate multiple expert priors into a consensus prior
Description
Combines elicited priors from multiple experts into a single consensus distribution using either linear pooling (mixture) or logarithmic pooling (normalised product of densities). Includes diagnostics for inter-expert disagreement.
Usage
aggregate_experts(
priors,
weights = NULL,
method = c("linear", "logarithmic"),
disagreement_threshold = 0.5
)
Arguments
priors |
A named list of |
weights |
Numeric vector of expert weights (summing to 1). If |
method |
Character. |
disagreement_threshold |
Numeric in (0, 1). Triggers a warning when
the pairwise Bhattacharyya coefficient drops below this value, flagging
substantial expert disagreement. Default |
Details
Linear pooling satisfies the marginalization property (McConway,
1981): pooling a joint distribution and then marginalising gives the
same result as marginalising each expert's distribution first and then
pooling. The consensus density is a weighted mixture
\pi(\theta) = \sum_k w_k \pi_k(\theta). This is the most commonly
used approach in clinical trial settings (O'Hagan et al., 2006). The
resulting prior always lies within the convex hull of individual expert
priors. The mixture's summary mean and SD (in $fit_summary, used
e.g. by sensitivity_grid to derive a working prior) are
computed exactly from the component means/SDs and weights, without
numerical integration:
\text{mean} = \sum_k w_k \bar{x}_k, \quad
\text{var} = \sum_k w_k \left(s_k^2 + \bar{x}_k^2\right) - \text{mean}^2
Logarithmic pooling satisfies external Bayesianity (Genest, Weerahandi
& Zidek, 1984): pooling experts' priors and then updating on data gives
the same result as updating each expert's prior individually and then
pooling the posteriors – pooling and Bayesian updating commute. This is
in fact the only pooling operator with this property (Genest,
McConway & Schervish, 1986); no pooling method can satisfy both external
Bayesianity and marginalization simultaneously. The consensus density is
proportional to \prod_k \pi_k(\theta)^{w_k}, which produces a
sharper consensus when experts agree, but can be severely influenced by
outlying expert opinions. Unlike linear pooling, no closed-form summary
SD exists for the pooled density in general; $fit_summary$sd is
NULL for logarithmically-pooled priors.
Value
A bayprior object (dist = "mixture" for linear pooling,
dist = "log_pool" for logarithmic), with an additional
$aggregation component containing:
methodPooling method used
weightsApplied weights
disagreementPairwise Bhattacharyya coefficients
n_expertsNumber of experts
References
O'Hagan, A., et al. (2006). Uncertain Judgements: Eliciting Experts' Probabilities. Wiley.
McConway, K. J. (1981). Marginalization and linear opinion pools. Journal of the American Statistical Association, 76(374), 410-414.
Genest, C., Weerahandi, S., & Zidek, J. V. (1984). Aggregating opinions through logarithmic pooling. Theory and Decision, 17(1), 61-70.
Genest, C., McConway, K. J., & Schervish, M. J. (1986). Characterization of externally Bayesian pooling operators. The Annals of Statistics, 14(2), 487-501.
Examples
p1 <- elicit_beta(mean = 0.25, sd = 0.08, method = "moments", expert_id = "E1",
label = "Response rate")
p2 <- elicit_beta(mean = 0.35, sd = 0.10, method = "moments", expert_id = "E2",
label = "Response rate")
p3 <- elicit_beta(mean = 0.30, sd = 0.09, method = "moments", expert_id = "E3",
label = "Response rate")
consensus <- aggregate_experts(
priors = list(E1 = p1, E2 = p2, E3 = p3),
weights = c(0.4, 0.3, 0.3),
method = "linear"
)
print(consensus)
plot(consensus)
Constructor for bayprior from raw parameters
Description
Construct a bayprior object directly from known hyperparameters
(e.g., literature-based priors), bypassing elicitation.
Usage
as_prior(dist, params, label = "Prior", expert_id = "Literature")
Arguments
dist |
Character. One of |
params |
Named list of hyperparameters. |
label |
Character. Description of the quantity. |
expert_id |
Character. Source identifier. |
Value
A bayprior object.
Examples
# Historical Beta(2, 8) prior on response rate
prior <- as_prior("beta", list(alpha = 2, beta = 8),
label = "Historical response rate prior")
Calibrate power prior weight via Bayes Factor
Description
Selects the power prior weight \delta \in (0,1) that down-weights
historical data before incorporating it into the current analysis.
Usage
calibrate_power_prior(
historical_data,
current_data,
base_prior,
target_bf = 3,
delta_grid = seq(0.05, 1, by = 0.05),
method = c("bayes_factor", "compatibility")
)
Arguments
historical_data |
Named list: |
current_data |
Named list (same structure as |
base_prior |
A |
target_bf |
Numeric. Target Bayes Factor. Default |
delta_grid |
Numeric vector of |
method |
Character. |
Value
A list of class bayprior_power_prior with components:
- delta_opt
Optimal power prior weight selected by the chosen method.
- delta_grid
The grid of delta values evaluated.
- bf_grid
Bayes Factor at each delta value.
- compatibility_grid
Box p-value at each delta value.
- results
Data frame with all diagnostic metrics across the grid.
- power_prior
A
baypriorobject updated with the optimal delta.- target_bf
The target Bayes Factor supplied by the user.
- method
The calibration method used.
References
Ibrahim, J. G. & Chen, M.-H. (2000). Power prior distributions for regression models. Statistical Science, 15, 46-60.
Gravestock, I. & Held, L. (2017). Adaptive power priors with empirical Bayes for clinical trials. Pharmaceutical Statistics, 16, 349-360.
Examples
base <- elicit_beta(mean = 0.5, sd = 0.2, method = "moments",
label = "Response rate")
calib <- calibrate_power_prior(
historical_data = list(type = "binary", x = 12, n = 40),
current_data = list(type = "binary", x = 18, n = 50),
base_prior = base,
target_bf = 3
)
print(calib)
plot(calib)
Multivariate prior-data conflict via Mahalanobis distance
Description
Tests joint prior-data conflict across two correlated endpoints using the Mahalanobis distance. Under the null (no conflict) the squared distance follows a chi-squared distribution with degrees of freedom equal to the number of endpoints.
Usage
conflict_mahalanobis(
prior_means,
prior_cov,
obs_means,
obs_cov,
alpha = 0.05,
labels = NULL
)
Arguments
prior_means |
Numeric vector of length k. Prior means for each endpoint. |
prior_cov |
k x k numeric matrix. Prior covariance matrix. |
obs_means |
Numeric vector of length k. Observed data means. |
obs_cov |
k x k numeric matrix. Observed data covariance (Var/n for each diagonal; Cov/n for off-diagonal). |
alpha |
Numeric. Significance level for the chi-squared test.
Default |
labels |
Character vector of length k. Endpoint labels for output. |
Details
Assumptions: This test assumes that the prior and observed summary statistics are approximately multivariate Normal. For proportion endpoints (e.g. response rates), transform to the log-odds scale before entering means and variances. For hazard ratios, use the log scale. Results may be unreliable if the Normal approximation is poor (e.g. for small samples with extreme proportions).
Current limitation: The function is designed for bivariate (k = 2) endpoints. While it will accept k > 2, the Shiny interface currently only exposes two endpoints. Support for k >= 3 is a planned extension.
Distribution family: The Mahalanobis approach is distribution-agnostic at the summary statistic level – it does not require a specific prior family (Beta, Normal, etc.). Any continuous prior whose mean and covariance can be extracted is supported.
Value
A named list of class bayprior_conflict_mv with components:
- mahal_distance
Mahalanobis distance D.
- mahal_D2
Squared distance D^2.
- pvalue
Chi-squared p-value (df = p).
- df
Degrees of freedom (number of endpoints, p).
- conflict_flag
Logical. TRUE if pvalue < alpha.
- marginal_z
Named numeric vector of per-parameter marginal z-scores (difference standardised by the marginal predictive SD).
- interpretation
Character. Plain-language summary.
- labels
Endpoint labels.
- alpha
The significance level used.
References
Mahalanobis, P. C. (1936). On the generalised distance in statistics. Proceedings of the National Institute of Sciences of India, 2, 49–55.
Examples
pm <- c(0.35, 0.60)
pcov <- matrix(c(0.010, 0.003, 0.003, 0.015), 2, 2)
om <- c(0.55, 0.58)
ocov <- matrix(c(2e-4, 4e-5, 4e-5, 2e-4), 2, 2)
conflict_mahalanobis(pm, pcov, om, ocov, labels = c("Response rate", "OS rate"))
Elicit a Beta prior via quantile matching or moment matching
Description
Fits a Beta(alpha, beta) distribution to expert-specified quantiles or moments. Implements the structured elicitation framework of the SHELF methodology, supporting the documented, reproducible prior derivation called for in the FDA's 2026 draft guidance on Bayesian methods.
Usage
elicit_beta(
quantiles = NULL,
mean = NULL,
sd = NULL,
method = c("quantile", "moments"),
expert_id = "Expert_1",
label = "Unknown quantity",
tol = 1e-06
)
Arguments
quantiles |
Named numeric vector of quantile specifications, e.g.
|
mean |
Optional numeric. Expert-specified mean for moment matching. |
sd |
Optional numeric. Expert-specified SD for moment matching. |
method |
Character. One of |
expert_id |
Character. Identifier for this expert's elicitation. |
label |
Character. Description of the quantity being elicited. |
tol |
Numeric. Optimisation tolerance. Default |
Details
For method = "moments", the mean and SD are matched analytically
to the Beta family using the standard method-of-moments identities:
\alpha = \bar{x}\left(\frac{\bar{x}(1-\bar{x})}{s^2} - 1\right),
\quad
\beta = (1-\bar{x})\left(\frac{\bar{x}(1-\bar{x})}{s^2} - 1\right)
where \bar{x} is mean and s is sd. This requires
s^2 < \bar{x}(1-\bar{x}); an SD too large for the given mean implies
a negative \alpha or \beta and raises an error. For
method = "quantile", \alpha and \beta are instead found
numerically by minimising squared error between the fitted quantiles and
the expert-specified quantiles.
Value
An object of class bayprior with components:
dist"beta"paramsNamed list with
alphaandbetamethodElicitation method used
expert_idExpert identifier
labelQuantity label
fit_summarySummary statistics of fitted prior
Examples
# Expert believes response rate is ~30%, with 90% CI of [10%, 60%]
prior <- elicit_beta(
quantiles = c("0.05" = 0.10, "0.50" = 0.30, "0.95" = 0.60),
expert_id = "Expert_1",
label = "Response rate (treatment arm)"
)
print(prior)
plot(prior)
# Moment-based elicitation
prior_mom <- elicit_beta(
mean = 0.30, sd = 0.12,
method = "moments",
label = "Response rate"
)
Elicit an Exponential prior via moments, rate, or quantile matching
Description
Fits an Exponential(rate) prior from expert-specified moments or quantiles. Suitable for constant-hazard survival models and Poisson rate priors. The Exponential distribution is the conjugate prior likelihood for a Gamma prior on the rate parameter.
Usage
elicit_exponential(
rate = NULL,
mean = NULL,
quantiles = NULL,
method = c("moments", "rate", "quantile"),
expert_id = "Expert",
label = "Quantity"
)
Arguments
rate |
Numeric > 0. Rate parameter (= 1 / mean). Used when
|
mean |
Numeric > 0. Prior mean (= 1 / rate). Used when
|
quantiles |
Named numeric vector with at least one interior quantile.
Used when |
method |
Character. One of |
expert_id |
Character. Identifier for the eliciting expert. |
label |
Character. Human-readable label for the quantity. |
Details
The Exponential distribution has a single parameter \lambda > 0
(the rate). Its mean is 1/\lambda and its SD equals its mean.
Typical use cases:
- Hazard rates
OS/PFS hazard in oncology trials
- Event rates
Adverse event rates (events per person-time)
- Poisson rate priors
Conjugate prior for Poisson count data
Value
A bayprior object with dist = "exponential".
Examples
# Mean survival 20 months => hazard rate 1/20 = 0.05
p <- elicit_exponential(mean = 0.05, method = "moments",
label = "Hazard rate",
expert_id = "Expert_1")
print(p)
plot(p)
# Direct rate specification
p2 <- elicit_exponential(rate = 0.10, method = "rate",
label = "AE rate per person-year")
# Quantile matching
p3 <- elicit_exponential(
quantiles = c("0.25" = 0.02, "0.50" = 0.05, "0.75" = 0.10),
method = "quantile",
label = "Hazard rate"
)
Elicit a Gamma prior via quantile matching or moment matching
Description
Elicit a Gamma prior via quantile matching or moment matching
Usage
elicit_gamma(
quantiles = NULL,
mean = NULL,
sd = NULL,
method = c("quantile", "moments"),
expert_id = "Expert_1",
label = "Unknown quantity",
tol = 1e-06
)
Arguments
quantiles |
Named numeric vector of quantiles. Values must be positive. |
mean |
Optional numeric. Expert mean. |
sd |
Optional numeric. Expert SD. |
method |
Character. |
expert_id |
Character. Expert identifier. |
label |
Character. Quantity description. |
tol |
Numeric. Optimisation tolerance. |
Details
For method = "moments", mean and SD are matched to the Gamma's
shape-rate parameterisation via
\text{shape} = \left(\frac{\bar{x}}{s}\right)^2, \quad
\text{rate} = \frac{\bar{x}}{s^2}
Value
An object of class bayprior.
Examples
prior <- elicit_gamma(
mean = 5, sd = 2,
method = "moments",
label = "Median OS (months)"
)
Elicit a Log-Normal prior via quantile matching or moment matching
Description
Fits a Log-Normal distribution to expert-specified quantiles or moments. Appropriate for positive-valued quantities such as hazard ratios, fold changes, median survival times, or PK parameters.
Usage
elicit_lognormal(
quantiles = NULL,
mean = NULL,
sd = NULL,
method = c("quantile", "moments"),
expert_id = "Expert_1",
label = "Unknown quantity",
tol = 1e-06
)
Arguments
quantiles |
Named numeric vector. Values must be strictly positive.
E.g. |
mean |
Optional numeric. Expert mean on the original scale. |
sd |
Optional numeric. Expert SD on the original scale. |
method |
Character. |
expert_id |
Character. Expert identifier. |
label |
Character. Quantity description. |
tol |
Numeric. Optimisation tolerance. |
Details
For method = "moments", the mean and SD (on the original,
untransformed scale) are matched to the Log-Normal's own
meanlog/sdlog parameterisation via
\text{sdlog} = \sqrt{\log\left(1 + \frac{s^2}{\bar{x}^2}\right)},
\quad
\text{meanlog} = \log(\bar{x}) - \frac{\text{sdlog}^2}{2}
Value
An object of class bayprior with dist = "lognormal".
Examples
prior <- elicit_lognormal(
quantiles = c("0.05" = 0.40, "0.50" = 0.70, "0.95" = 1.20),
label = "Hazard ratio (treatment vs control)"
)
print(prior)
Elicit a mixture prior
Description
Constructs a finite mixture prior from a list of component bayprior
objects (e.g., from elicit_beta, elicit_normal). Mixing
weights can be specified or estimated via linear pooling.
Usage
elicit_mixture(components, weights = NULL, label = "Mixture prior")
Arguments
components |
List of |
weights |
Numeric vector of mixing weights (must sum to 1). If
|
label |
Character. Label for the mixture prior. |
Details
Same-family mixtures (e.g. Beta + Beta, Normal + Normal) have mixture means and SDs computed in closed form. Cross-family mixtures (e.g. Beta + Normal) also have closed-form mixture means and SDs, but the mixture density must be computed numerically by evaluating and summing the component densities on a grid. A warning is issued in this case:
"Components have different distribution families. Mixture densities computed numerically."
This warning is informative, not an error. The numerical approximation is
accurate in the body of the distribution but may be less reliable at the
tails, particularly for components with very different supports (e.g. a
Beta defined on (0, 1) mixed with a Normal defined on (-Inf, Inf)). Use
suppressWarnings() only when you have verified the mixture is
appropriate for your use case.
Value
A bayprior object with dist = "mixture".
Examples
p1 <- elicit_beta(mean = 0.2, sd = 0.08, method = "moments", expert_id = "E1")
p2 <- elicit_beta(mean = 0.4, sd = 0.10, method = "moments", expert_id = "E2")
mix <- elicit_mixture(list(p1, p2), weights = c(0.5, 0.5),
label = "Pooled prior")
Elicit a Normal prior via quantile matching or moment matching
Description
Elicit a Normal prior via quantile matching or moment matching
Usage
elicit_normal(
quantiles = NULL,
mean = NULL,
sd = NULL,
method = c("quantile", "moments"),
expert_id = "Expert_1",
label = "Unknown quantity",
tol = 1e-06
)
Arguments
quantiles |
Named numeric vector. E.g.
|
mean |
Optional numeric. Expert mean for moment matching. |
sd |
Optional numeric. Expert SD for moment matching. |
method |
Character. |
expert_id |
Character. Expert identifier. |
label |
Character. Quantity description. |
tol |
Numeric. Optimisation tolerance. |
Details
For method = "moments", the Normal is parameterised directly by
its mean and SD, so matching is exact with no transformation required:
\mu = \bar{x}, \sigma = s.
Value
An object of class bayprior.
Examples
prior <- elicit_normal(
quantiles = c("0.025" = -0.5, "0.50" = 0.2, "0.975" = 0.9),
label = "Log odds ratio"
)
Roulette-method elicitation (chip-allocation)
Description
Implements the SHELF roulette method: the expert allocates a fixed number of "chips" across a set of pre-defined bins representing the range of the quantity. The resulting histogram is fitted to a parametric distribution.
Usage
elicit_roulette(
chips,
breaks,
family = c("beta", "normal", "gamma", "lognormal"),
expert_id = "Expert_1",
label = "Unknown quantity"
)
Arguments
chips |
Integer vector. Number of chips in each bin (left-to-right). |
breaks |
Numeric vector of length |
family |
Character. Distribution to fit. One of |
expert_id |
Character. Expert identifier. |
label |
Character. Quantity description. |
Details
In the Shiny app (Prior elicitation tab) the roulette grid is rendered
interactively. This function provides the fitting back-end that can
also be called programmatically when chips are known.
Chips are converted to relative frequencies, and bin midpoints are used as
representative values. The chosen family is then fitted by minimising the
weighted sum of squared CDF differences (a histogram-matching approach).
Value
A bayprior object fitted to the chip histogram.
References
Oakley, J. E. & O'Hagan, A. (2010). SHELF: the Sheffield Elicitation Framework. University of Sheffield.
Examples
# Expert places 0, 2, 5, 8, 5, 2, 1 chips across bins [0,.1,.2,...,.7]
prior <- elicit_roulette(
chips = c(0L, 2L, 5L, 8L, 5L, 2L, 1L),
breaks = seq(0, 0.7, by = 0.1),
family = "beta",
label = "Response rate"
)
print(prior)
Elicit a Weibull prior via moments, direct parameters, or quantile matching
Description
Fits a Weibull(shape, scale) prior from expert-specified moments or quantiles. The Weibull distribution generalises the Exponential and is widely used for survival analysis with non-constant hazard.
Usage
elicit_weibull(
shape = NULL,
scale = NULL,
mean = NULL,
sd = NULL,
quantiles = NULL,
method = c("moments", "params", "quantile"),
expert_id = "Expert",
label = "Quantity"
)
Arguments
shape |
Numeric > 0. Shape parameter |
scale |
Numeric > 0. Scale parameter |
mean |
Numeric > 0. Prior mean. Used with |
sd |
Numeric > 0. Prior SD. Used with |
quantiles |
Named numeric vector with at least two interior quantiles.
Used when |
method |
Character. One of |
expert_id |
Character. Identifier for the eliciting expert. |
label |
Character. Human-readable label for the quantity. |
Details
Parameterised as in R's stats::dweibull: shape k and
scale \lambda, with mean \lambda \Gamma(1 + 1/k) and
variance \lambda^2 [\Gamma(1 + 2/k) - \Gamma(1 + 1/k)^2].
Shape parameter interpretation:
-
k < 1: decreasing hazard (e.g. early mortality selecting out) -
k = 1: constant hazard (reduces to Exponential) -
k > 1: increasing hazard (e.g. ageing, post-surgical)
Value
A bayprior object with dist = "weibull".
Examples
# Moment matching: mean 20 months, SD 10 months
p <- elicit_weibull(mean = 20, sd = 10, method = "moments",
label = "Survival time (months)",
expert_id = "Expert_1")
print(p)
plot(p)
# Direct parameters (shape = 2 = increasing hazard)
p2 <- elicit_weibull(shape = 2, scale = 20, method = "params",
label = "PFS (months)")
# Quantile matching (at least 2 required)
p3 <- elicit_weibull(
quantiles = c("0.10" = 5, "0.50" = 18, "0.90" = 40),
method = "quantile",
label = "OS (months)"
)
Plot calibration curve for power prior weight selection
Description
Plot calibration curve for power prior weight selection
Usage
## S3 method for class 'bayprior_power_prior'
plot(x, ...)
Arguments
x |
A |
... |
Ignored. |
Value
A ggplot object, or a list of two ggplots if 'patchwork' is
not installed.
Plot prior, likelihood, and posterior density overlays
Description
Plot prior, likelihood, and posterior density overlays
Usage
plot_prior_likelihood(
prior,
data_summary,
show_posterior = TRUE,
show_conflict = TRUE,
n_grid = 500,
title = NULL
)
Arguments
prior |
A |
data_summary |
Named list with |
show_posterior |
Logical. Default |
show_conflict |
Logical. Default |
n_grid |
Integer. Default |
title |
Character. Plot title. |
Value
A ggplot object.
Examples
prior <- elicit_beta(mean = 0.30, sd = 0.10, method = "moments",
label = "Response rate")
plot_prior_likelihood(prior, list(n = 40, x = 20, type = "binary"))
Plot sensitivity analysis results
Description
Plot sensitivity analysis results
Usage
plot_sensitivity(sensitivity, target = NULL, highlight_reference = TRUE)
Arguments
sensitivity |
A |
target |
Character. Which target quantity to plot. |
highlight_reference |
Logical. Default |
Value
A ggplot object.
Tornado plot of prior influence on posterior quantities
Description
Tornado plot of prior influence on posterior quantities
Usage
plot_tornado(sensitivity, title = "Prior influence on posterior estimates")
Arguments
sensitivity |
A |
title |
Character. Plot title. |
Value
A ggplot object.
Print method for bayprior objects
Description
Print method for bayprior objects
Usage
## S3 method for class 'bayprior'
print(x, ...)
Arguments
x |
A |
... |
Ignored. |
Value
Invisibly returns the input bayprior object. Called
for its side effect of printing a formatted summary of the prior
distribution including family, parameters, mean, SD, and 95\
credible interval.
Print method for bayprior_conflict objects
Description
Print method for bayprior_conflict objects
Usage
## S3 method for class 'bayprior_conflict'
print(x, ...)
Arguments
x |
A |
... |
Ignored. |
Value
Invisibly returns the input bayprior_conflict object.
Called for its side effect of printing conflict diagnostic statistics
including Box p-value, surprise index, information divergence,
Bhattacharyya overlap, and colour-coded conflict severity.
Print method for multivariate conflict objects
Description
Print method for multivariate conflict objects
Usage
## S3 method for class 'bayprior_conflict_mv'
print(x, ...)
Arguments
x |
A |
... |
Ignored. |
Value
Invisibly returns the input bayprior_conflict_mv object.
Called for its side effect of printing a formatted summary of the
multivariate Mahalanobis conflict check, including the Mahalanobis
distance, chi-squared p-value, conflict flag, per-parameter marginal
z-scores, and an interpretation string.
Print method for bayprior_power_prior objects
Description
Print method for bayprior_power_prior objects
Usage
## S3 method for class 'bayprior_power_prior'
print(x, ...)
Arguments
x |
A |
... |
Ignored. |
Value
Invisibly returns the input bayprior_power_prior object.
Called for its side effect of printing a formatted summary of the power
prior calibration, including the calibration method, target Bayes Factor,
optimal delta weight, and the mean and SD of the resulting power prior.
Compute prior-data conflict diagnostics
Description
Evaluates conflict between a specified prior and observed data using multiple complementary diagnostics: Box's (1980) predictive p-value, the surprise index (standardised distance), Kullback-Leibler divergence, and the Bhattacharyya overlap coefficient between the prior and the (normalised) likelihood.
Usage
prior_conflict(prior, data_summary, alpha = 0.05)
Arguments
prior |
A |
data_summary |
Named list describing the observed data:
|
alpha |
Numeric. Significance level for the Box p-value flag.
Default |
Value
An object of class bayprior_conflict containing:
box_pvalueBox's prior predictive p-value.
surprise_indexStandardised distance between prior mean and observed data.
kl_prior_likelihoodKL divergence from prior to likelihood.
overlapBhattacharyya overlap coefficient in [0, 1].
conflict_severityOne of
"none","mild","severe".conflict_flagLogical;
TRUEifbox_pvalue < alpha.recommendationPlain-language guidance string.
data_summaryThe data summary passed in.
priorThe input prior.
References
Box, G. E. P. (1980). Sampling and Bayes' inference in scientific modelling and robustness. Journal of the Royal Statistical Society A, 143, 383-430.
Examples
prior <- elicit_beta(mean = 0.30, sd = 0.10, method = "moments",
label = "Response rate")
cd <- prior_conflict(prior, list(type = "binary", x = 18, n = 40))
print(cd)
Generate a Prior Justification Report
Description
Renders an HTML, PDF, or Word (.docx) report using quarto::quarto_render().
Usage
prior_report(
prior,
conflict = NULL,
sensitivity = NULL,
robust_prior = NULL,
sceptical_prior = NULL,
power_prior = NULL,
output_format = c("html", "pdf", "docx"),
output_file = NULL,
trial_name = "Clinical Trial",
sponsor = "Sponsor",
date = as.character(Sys.Date()),
author = "Biostatistics",
notes = "",
prior_plot = NULL,
overlay_plot = NULL,
tornado_plot = NULL,
heatmap_plot = NULL,
robust_plot = NULL,
sceptical_plot = NULL,
power_plot = NULL,
open_after = interactive()
)
Arguments
prior |
A bayprior object. |
conflict |
Optional bayprior_conflict from prior_conflict(). |
sensitivity |
Optional bayprior_sensitivity from sensitivity_grid(). |
robust_prior |
Optional output of robust_prior(). |
sceptical_prior |
Optional output of sceptical_prior(). |
power_prior |
Optional output of calibrate_power_prior(). |
output_format |
"html" (default), "pdf", or "docx". |
output_file |
Output path without extension. |
trial_name |
Trial / protocol identifier. |
sponsor |
Sponsor name. |
date |
Report date string. Default Sys.Date(). |
author |
Responsible statistician. |
notes |
Optional narrative text. |
prior_plot |
Optional pre-captured ggplot from |
overlay_plot |
Optional pre-captured ggplot from |
tornado_plot |
Optional pre-captured ggplot from |
heatmap_plot |
Optional pre-captured ggplot from |
robust_plot |
Optional pre-captured ggplot of the robust prior. |
sceptical_plot |
Optional pre-captured ggplot of the sceptical prior. |
power_plot |
Optional pre-captured ggplot of the power prior. |
open_after |
Open after rendering. Default TRUE interactively. |
Value
Path to the rendered report, invisibly.
Construct a robust (heavy-tailed mixture) prior
Description
Builds a robust prior by mixing an informative component with a vague (diffuse) component, following the RBesT/MAP robust mixture approach (Schmidli et al., 2014). This protects against prior misspecification by ensuring the posterior is not dominated by a conflicting informative prior.
Usage
robust_prior(
informative,
vague_weight = 0.2,
vague_sd = NULL,
label = "Robust mixture prior"
)
Arguments
informative |
A |
vague_weight |
Numeric in (0, 1). Weight assigned to the vague
(diffuse) component. Default |
vague_sd |
Numeric. SD of the vague Normal component (on the
natural scale). If |
label |
Character. Label for the robust prior. |
Details
The vague component is always a Normal distribution centred at
the informative prior's mean with SD = vague_sd (default: 10x the
informative SD). When the informative prior is itself Normal, both
components share the same family and the mixture density is computed
analytically. For any other informative prior family (Beta, Gamma,
Log-Normal, Exponential, Weibull), the components have different
distribution families, and the mixture density is computed
numerically. A warning is issued in this case.
Value
A bayprior object with dist = "mixture" and
prior_type = "robust".
References
Schmidli, H. et al. (2014). Robust meta-analytic-predictive priors in clinical trials with historical control information. Biometrics, 70, 1023-1032.
Examples
informative <- elicit_normal(mean = 0.30, sd = 0.10,
method = "moments", label = "Response rate")
robust <- robust_prior(informative, vague_weight = 0.20)
plot(robust)
Run the bayprior Shiny Application
Description
Launches the golem-structured shinydashboard application.
Usage
run_app(
onStart = NULL,
options = list(),
enableBookmarking = NULL,
uiPattern = "/",
...
)
Arguments
onStart |
A function called before the app runs. |
options |
List of options passed to |
enableBookmarking |
Passed to |
uiPattern |
Passed to |
... |
Additional arguments passed to |
Value
A shiny.appobj, invisibly.
Construct a sceptical (penalised-enthusiasm) prior
Description
Generates a sceptical prior that places most mass at or near the null value of the treatment effect, representing a conservative stance for regulatory submissions. Implements the Spiegelhalter-Freedman sceptical prior approach, commonly paired with an enthusiastic prior as a sensitivity-analysis pair in regulatory submissions.
Usage
sceptical_prior(
null_value = 0,
family = c("normal", "beta", "lognormal"),
strength = c("moderate", "weak", "strong"),
label = "Treatment effect",
expert_id = "Sceptic"
)
Arguments
null_value |
Numeric. The null treatment effect. For
|
family |
Character. Distribution family. One of |
strength |
Character. How concentrated the prior is around the null:
|
label |
Character. Description of the quantity. |
expert_id |
Character. Identifier for provenance. |
Details
For a Normal family, the sceptical prior is centred at null_value
with SD calibrated to the strength argument:
-
weak: SD = 1.0 (vague half-normal) -
moderate: SD = 0.5 (2-SD departure from null has ~5% prior probability) -
strong: SD = 0.25 (very concentrated at null)
For family = "beta", null_value must be in (0, 1).
Value
A bayprior object tagged with prior_type = "sceptical".
References
Spiegelhalter, D. J., Freedman, L. S. & Parmar, M. K. B. (1994). Bayesian approaches to randomized trials. JRSS-A, 157, 357-416.
Examples
sc <- sceptical_prior(null_value = 0, family = "normal",
strength = "moderate", label = "Mean difference")
print(sc)
plot(sc)
# Beta sceptical prior centred at a null response rate
sc_b <- sceptical_prior(null_value = 0.20, family = "beta",
strength = "moderate", label = "Response rate")
plot(sc_b)
# Lognormal sceptical prior for a hazard ratio: null_value is on the LOG
# scale, so 0 (not 1) represents a null hazard ratio of exp(0) = 1.
sc_hr <- sceptical_prior(null_value = 0, family = "lognormal",
strength = "moderate", label = "Hazard ratio")
print(sc_hr) # mean should be at or near 1, the null hazard ratio
Credible interval sensitivity over prior hyperparameters
Description
Evaluates how the posterior credible interval width and bounds change as prior hyperparameters vary over a specified grid. This is the preferred function for demonstrating that key regulatory conclusions (e.g., whether the CrI excludes a null value) are robust to prior choice.
Usage
sensitivity_cri(
prior,
data_summary,
param_grid,
cri_level = 0.95,
threshold = NULL
)
Arguments
prior |
A |
data_summary |
Named list as for |
param_grid |
Named list of numeric vectors, one per hyperparameter. |
cri_level |
Numeric in (0, 1). Credible interval level. Default
|
threshold |
Optional numeric. Computes |
Details
As with sensitivity_grid, when prior is a mixture,
a single-family working prior is derived via .mixture_working_prior()
– moment-matching the mixture's pooled mean/SD to the dominant
component's family – rather than analysing the dominant component alone.
Value
An object of class bayprior_sensitivity whose grid contains
columns cri_lower, cri_upper, and cri_width, plus
optionally posterior_mean, posterior_sd, and
prob_efficacy.
Examples
prior <- elicit_beta(mean = 0.30, sd = 0.10, method = "moments",
label = "Response rate")
cri_sa <- sensitivity_cri(
prior,
data_summary = list(type = "binary", x = 14, n = 40),
param_grid = list(alpha = seq(1, 8, 0.5), beta = seq(2, 20, 1)),
cri_level = 0.95
)
plot_sensitivity(cri_sa, target = "cri_width")
Sensitivity grid over prior hyperparameters
Description
Evaluates how posterior inferences change as prior hyperparameters vary over a specified grid. This is the core function for demonstrating robustness of trial conclusions to prior choice.
Usage
sensitivity_grid(
prior,
data_summary,
param_grid,
target = c("posterior_mean", "posterior_sd", "prob_efficacy"),
threshold = 0.3
)
Arguments
prior |
A |
data_summary |
Named list as for |
param_grid |
Named list of numeric vectors, one per hyperparameter
to vary. Names must match hyperparameter names in |
target |
Character vector. Which posterior quantities to compute.
Any of |
threshold |
Numeric. Efficacy threshold used in
|
Details
The hyperparameter grid is defined over a single distribution family, so
when prior is a mixture (e.g. from aggregate_experts
or robust_prior), a single-family working prior is
derived first, via the internal .mixture_working_prior() helper.
As of this version, that working prior is obtained in two steps: first,
the mixture's pooled mean and SD are computed exactly (see the mean/var
formula in aggregate_experts); second, those pooled moments
are matched to the dominant component's distribution family using that
family's own moment-matching identities (see elicit_beta,
elicit_normal, elicit_gamma, or
elicit_lognormal for the specific formula used). The grid
therefore reflects the full pooled information, not just one component.
A message reports the working prior used. If the dominant component's
family cannot be moment-matched from mean/SD alone ("exponential"
or "weibull"), the function falls back to the dominant component
by weight and issues an explicit warning identifying which component
was used and why.
Value
An object of class bayprior_sensitivity.
Examples
prior <- elicit_beta(mean = 0.30, sd = 0.10, method = "moments",
label = "Response rate")
sa <- sensitivity_grid(
prior,
data_summary = list(type = "binary", x = 14, n = 40),
param_grid = list(alpha = seq(1, 8, 0.5), beta = seq(2, 20, 1))
)
plot_tornado(sa)
plot_sensitivity(sa, target = "posterior_mean")
Summary method for bayprior objects
Description
Summary method for bayprior objects
Usage
## S3 method for class 'bayprior'
summary(object, ...)
Arguments
object |
A |
... |
Ignored. |
Value
A list with summary statistics (invisibly).