| Title: | Bayesian Prior Elicitation and Diagnostics for Clinical Trials |
|---|---|
| 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>. |
| Authors: | Ndoh Penn [aut, cre] (ORCID: <https://orcid.org/0009-0003-9054-465X>) |
| Maintainer: | Ndoh Penn <[email protected]> |
| License: | GPL-3 |
| Version: | 0.2.12 |
| Built: | 2026-06-04 14:06:20 UTC |
| Source: | https://github.com/ndohpenngit/bayprior |
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.
aggregate_experts( priors, weights = NULL, method = c("linear", "logarithmic"), disagreement_threshold = 0.5 )aggregate_experts( priors, weights = NULL, method = c("linear", "logarithmic"), disagreement_threshold = 0.5 )
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 |
Linear pooling (externally Bayesian): The consensus density is a
weighted mixture . 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.
Logarithmic pooling (internally Bayesian): The consensus density is
proportional to , which produces a
sharper consensus when experts agree, but can be severely influenced by
outlying expert opinions.
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
O'Hagan, A., et al. (2006). Uncertain Judgements: Eliciting Experts' Probabilities. Wiley.
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)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)
Construct a bayprior object directly from known hyperparameters
(e.g., literature-based priors), bypassing elicitation.
as_prior(dist, params, label = "Prior", expert_id = "Literature")as_prior(dist, params, label = "Prior", expert_id = "Literature")
dist |
Character. One of |
params |
Named list of hyperparameters. |
label |
Character. Description of the quantity. |
expert_id |
Character. Source identifier. |
A bayprior object.
# Historical Beta(2, 8) prior on response rate prior <- as_prior("beta", list(alpha = 2, beta = 8), label = "Historical response rate prior")# Historical Beta(2, 8) prior on response rate prior <- as_prior("beta", list(alpha = 2, beta = 8), label = "Historical response rate prior")
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 aligned with FDA/EMA expectations. Includes a fully modular Shiny application with automatic output reset on input change.
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
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.
"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.
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 Draft Guidance: Bayesian Methods in Clinical Trials (2026).
Maintainer: Ndoh Penn [email protected]
Useful links:
Report bugs at https://github.com/ndohpenngit/bayprior/issues
Selects the power prior weight that down-weights
historical data before incorporating it into the current analysis.
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") )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") )
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. |
A list of class bayprior_power_prior with components:
Optimal power prior weight selected by the chosen method.
The grid of delta values evaluated.
Bayes Factor at each delta value.
Box p-value at each delta value.
Data frame with all diagnostic metrics across the grid.
A bayprior object updated with the optimal delta.
The target Bayes Factor supplied by the user.
The calibration method used.
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.
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)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)
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.
conflict_mahalanobis( prior_means, prior_cov, obs_means, obs_cov, alpha = 0.05, labels = NULL )conflict_mahalanobis( prior_means, prior_cov, obs_means, obs_cov, alpha = 0.05, labels = NULL )
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. |
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.
A named list with components:
Mahalanobis distance D.
Squared distance D^2.
Chi-squared p-value (df = k).
Logical. TRUE if p_value < alpha.
Endpoint labels.
Mahalanobis, P. C. (1936). On the generalised distance in statistics. Proceedings of the National Institute of Sciences of India, 2, 49–55.
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"))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"))
Fits a Beta(alpha, beta) distribution to expert-specified quantiles or moments. Implements the structured elicitation framework recommended in the SHELF methodology and FDA guidance on Bayesian clinical trials.
elicit_beta( quantiles = NULL, mean = NULL, sd = NULL, method = c("quantile", "moments"), expert_id = "Expert_1", label = "Unknown quantity", tol = 1e-06 )elicit_beta( quantiles = NULL, mean = NULL, sd = NULL, method = c("quantile", "moments"), expert_id = "Expert_1", label = "Unknown quantity", tol = 1e-06 )
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 |
An object of class bayprior with components:
dist"beta"
paramsNamed list with alpha and beta
methodElicitation method used
expert_idExpert identifier
labelQuantity label
fit_summarySummary statistics of fitted prior
# 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" )# 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" )
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.
elicit_exponential( rate = NULL, mean = NULL, quantiles = NULL, method = c("moments", "rate", "quantile"), expert_id = "Expert", label = "Quantity" )elicit_exponential( rate = NULL, mean = NULL, quantiles = NULL, method = c("moments", "rate", "quantile"), expert_id = "Expert", label = "Quantity" )
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. |
The Exponential distribution has a single parameter
(the rate). Its mean is and its SD equals its mean.
Typical use cases:
OS/PFS hazard in oncology trials
Adverse event rates (events per person-time)
Conjugate prior for Poisson count data
A bayprior object with dist = "exponential".
# 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" )# 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
elicit_gamma( quantiles = NULL, mean = NULL, sd = NULL, method = c("quantile", "moments"), expert_id = "Expert_1", label = "Unknown quantity", tol = 1e-06 )elicit_gamma( quantiles = NULL, mean = NULL, sd = NULL, method = c("quantile", "moments"), expert_id = "Expert_1", label = "Unknown quantity", tol = 1e-06 )
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. |
An object of class bayprior.
prior <- elicit_gamma( mean = 5, sd = 2, method = "moments", label = "Median OS (months)" )prior <- elicit_gamma( mean = 5, sd = 2, method = "moments", label = "Median OS (months)" )
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.
elicit_lognormal( quantiles = NULL, mean = NULL, sd = NULL, method = c("quantile", "moments"), expert_id = "Expert_1", label = "Unknown quantity", tol = 1e-06 )elicit_lognormal( quantiles = NULL, mean = NULL, sd = NULL, method = c("quantile", "moments"), expert_id = "Expert_1", label = "Unknown quantity", tol = 1e-06 )
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. |
An object of class bayprior with dist = "lognormal".
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)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)
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.
elicit_mixture(components, weights = NULL, label = "Mixture prior")elicit_mixture(components, weights = NULL, label = "Mixture prior")
components |
List of |
weights |
Numeric vector of mixing weights (must sum to 1). If
|
label |
Character. Label for the mixture prior. |
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.
A bayprior object with dist = "mixture".
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")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
elicit_normal( quantiles = NULL, mean = NULL, sd = NULL, method = c("quantile", "moments"), expert_id = "Expert_1", label = "Unknown quantity", tol = 1e-06 )elicit_normal( quantiles = NULL, mean = NULL, sd = NULL, method = c("quantile", "moments"), expert_id = "Expert_1", label = "Unknown quantity", tol = 1e-06 )
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. |
An object of class bayprior.
prior <- elicit_normal( quantiles = c("0.025" = -0.5, "0.50" = 0.2, "0.975" = 0.9), label = "Log odds ratio" )prior <- elicit_normal( quantiles = c("0.025" = -0.5, "0.50" = 0.2, "0.975" = 0.9), label = "Log odds ratio" )
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.
elicit_roulette( chips, breaks, family = c("beta", "normal", "gamma", "lognormal"), expert_id = "Expert_1", label = "Unknown quantity" )elicit_roulette( chips, breaks, family = c("beta", "normal", "gamma", "lognormal"), expert_id = "Expert_1", label = "Unknown quantity" )
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. |
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).
A bayprior object fitted to the chip histogram.
Oakley, J. E. & O'Hagan, A. (2010). SHELF: the Sheffield Elicitation Framework. University of Sheffield.
# 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)# 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)
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.
elicit_weibull( shape = NULL, scale = NULL, mean = NULL, sd = NULL, quantiles = NULL, method = c("moments", "params", "quantile"), expert_id = "Expert", label = "Quantity" )elicit_weibull( shape = NULL, scale = NULL, mean = NULL, sd = NULL, quantiles = NULL, method = c("moments", "params", "quantile"), expert_id = "Expert", label = "Quantity" )
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. |
Parameterised as in R's stats::dweibull: shape and
scale , with mean and
variance .
Shape parameter interpretation:
: decreasing hazard (e.g. early mortality selecting out)
: constant hazard (reduces to Exponential)
: increasing hazard (e.g. ageing, post-surgical)
A bayprior object with dist = "weibull".
# 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)" )# 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 prior, likelihood, and posterior density overlays
plot_prior_likelihood( prior, data_summary, show_posterior = TRUE, show_conflict = TRUE, n_grid = 500, title = NULL )plot_prior_likelihood( prior, data_summary, show_posterior = TRUE, show_conflict = TRUE, n_grid = 500, title = NULL )
prior |
A |
data_summary |
Named list with |
show_posterior |
Logical. Default |
show_conflict |
Logical. Default |
n_grid |
Integer. Default |
title |
Character. Plot title. |
A ggplot object.
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"))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
plot_sensitivity(sensitivity, target = NULL, highlight_reference = TRUE)plot_sensitivity(sensitivity, target = NULL, highlight_reference = TRUE)
sensitivity |
A |
target |
Character. Which target quantity to plot. |
highlight_reference |
Logical. Default |
A ggplot object.
Tornado plot of prior influence on posterior quantities
plot_tornado(sensitivity, title = "Prior influence on posterior estimates")plot_tornado(sensitivity, title = "Prior influence on posterior estimates")
sensitivity |
A |
title |
Character. Plot title. |
A ggplot object.
Plot calibration curve for power prior weight selection
## S3 method for class 'bayprior_power_prior' plot(x, ...)## S3 method for class 'bayprior_power_prior' plot(x, ...)
x |
A |
... |
Ignored. |
A ggplot object, or a list of two ggplots if 'patchwork' is
not installed.
Print method for bayprior objects
## S3 method for class 'bayprior' print(x, ...)## S3 method for class 'bayprior' print(x, ...)
x |
A |
... |
Ignored. |
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
## S3 method for class 'bayprior_conflict' print(x, ...)## S3 method for class 'bayprior_conflict' print(x, ...)
x |
A |
... |
Ignored. |
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
## S3 method for class 'bayprior_conflict_mv' print(x, ...)## S3 method for class 'bayprior_conflict_mv' print(x, ...)
x |
A |
... |
Ignored. |
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
## S3 method for class 'bayprior_power_prior' print(x, ...)## S3 method for class 'bayprior_power_prior' print(x, ...)
x |
A |
... |
Ignored. |
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.
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.
prior_conflict(prior, data_summary, alpha = 0.05)prior_conflict(prior, data_summary, alpha = 0.05)
prior |
A |
data_summary |
Named list describing the observed data:
|
alpha |
Numeric. Significance level for the Box p-value flag.
Default |
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; TRUE if
box_pvalue < alpha.
recommendationPlain-language guidance string.
data_summaryThe data summary passed in.
priorThe input prior.
Box, G. E. P. (1980). Sampling and Bayes' inference in scientific modelling and robustness. Journal of the Royal Statistical Society A, 143, 383-430.
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)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)
Renders an HTML, PDF, or Word (.docx) report using quarto::quarto_render().
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() )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() )
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. |
Path to the rendered report, invisibly.
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.
robust_prior( informative, vague_weight = 0.2, vague_sd = NULL, label = "Robust mixture prior" )robust_prior( informative, vague_weight = 0.2, vague_sd = NULL, label = "Robust mixture prior" )
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. |
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.
A bayprior object with dist = "mixture" and
prior_type = "robust".
Schmidli, H. et al. (2014). Robust meta-analytic-predictive priors in clinical trials with historical control information. Biometrics, 70, 1023-1032.
informative <- elicit_normal(mean = 0.30, sd = 0.10, method = "moments", label = "Response rate") robust <- robust_prior(informative, vague_weight = 0.20) plot(robust)informative <- elicit_normal(mean = 0.30, sd = 0.10, method = "moments", label = "Response rate") robust <- robust_prior(informative, vague_weight = 0.20) plot(robust)
Launches the golem-structured shinydashboard application.
run_app( onStart = NULL, options = list(), enableBookmarking = NULL, uiPattern = "/", ... )run_app( onStart = NULL, options = list(), enableBookmarking = NULL, uiPattern = "/", ... )
onStart |
A function called before the app runs. |
options |
List of options passed to |
enableBookmarking |
Passed to |
uiPattern |
Passed to |
... |
Additional arguments passed to |
A shiny.appobj, invisibly.
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 and the FDA-recommended "enthusiastic vs sceptical" prior sensitivity pair.
sceptical_prior( null_value = 0, family = c("normal", "beta", "lognormal"), strength = c("moderate", "weak", "strong"), label = "Treatment effect", expert_id = "Sceptic" )sceptical_prior( null_value = 0, family = c("normal", "beta", "lognormal"), strength = c("moderate", "weak", "strong"), label = "Treatment effect", expert_id = "Sceptic" )
null_value |
Numeric. The null treatment effect (e.g. 0 for a mean
difference, 1 for a hazard ratio, 0.5 for a response-rate difference).
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. |
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).
A bayprior object tagged with prior_type = "sceptical".
Spiegelhalter, D. J., Freedman, L. S. & Parmar, M. K. B. (1994). Bayesian approaches to randomized trials. JRSS-A, 157, 357-416.
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)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)
A focused sensitivity analysis that tracks the width and location of the posterior credible interval (CrI) across a one- or two-dimensional hyperparameter grid. This directly answers the regulatory question: "Does the CrI change materially under plausible alternative priors?"
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.
sensitivity_cri( prior, data_summary, param_grid, cri_level = 0.95, threshold = NULL ) sensitivity_cri( prior, data_summary, param_grid, cri_level = 0.95, threshold = NULL )sensitivity_cri( prior, data_summary, param_grid, cri_level = 0.95, threshold = NULL ) sensitivity_cri( prior, data_summary, param_grid, cri_level = 0.95, threshold = NULL )
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 |
A bayprior_sensitivity object (same class as
sensitivity_grid) with additional columns cri_lower,
cri_upper, and cri_width in the result grid.
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.
prior <- elicit_beta(mean = 0.30, sd = 0.10, method = "moments") 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, threshold = 0.30 ) plot_sensitivity(cri_sa, target = "cri_width") 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")prior <- elicit_beta(mean = 0.30, sd = 0.10, method = "moments") 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, threshold = 0.30 ) plot_sensitivity(cri_sa, target = "cri_width") 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")
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.
sensitivity_grid( prior, data_summary, param_grid, target = c("posterior_mean", "posterior_sd", "prob_efficacy"), threshold = 0.3 )sensitivity_grid( prior, data_summary, param_grid, target = c("posterior_mean", "posterior_sd", "prob_efficacy"), threshold = 0.3 )
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
|
An object of class bayprior_sensitivity.
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")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
## S3 method for class 'bayprior' summary(object, ...)## S3 method for class 'bayprior' summary(object, ...)
object |
A |
... |
Ignored. |
A list with summary statistics (invisibly).