bayprior Bayesian Prior Elicitation for Clinical Trials
Prior Elicitation -- Fit parametric distributions from expert beliefs
elicit_beta(mean, sd, method, ...)
Fit a Beta prior for proportions / response rates.
meansdmethod = "moments" | "quantile"labelexpert_id
p <- elicit_beta(mean=0.30, sd=0.10, method="moments", label="ORR")
Expert belief
mean=0.30
sd=0.10
Beta(alpha,beta)
bayprior object
elicit_normal(mean, sd, method, ...)
Normal prior for unbounded quantities (log OR, mean differences).
p <- elicit_normal(mean=0, sd=0.5, method="moments", label="Log OR")
elicit_gamma(mean, sd, method, ...)
Gamma prior for positive quantities (rates, variances).
p <- elicit_gamma(mean=5, sd=2, method="moments", label="Event rate")
elicit_lognormal(mean, sd, method, ...)
Log-Normal prior for hazard ratios and PK parameters.
p <- elicit_lognormal( quantiles = c("0.05"=0.4,"0.50"=0.7,"0.95"=1.2))
elicit_roulette(chips, breaks, family, ...)
SHELF roulette method: expert places chips across histogram bins.
chipsbreaksfamily
chips <- c(0L,1L,3L,7L,9L,7L,4L,2L,1L,1L) breaks <- seq(0, 1, by=0.1) p <- elicit_roulette(chips, breaks, "beta")
elicit_mixture(priors, weights, ...)
Build an explicit mixture prior from component bayprior objects.
m <- elicit_mixture(list(p1, p2), weights = c(0.6, 0.4))
plot(prior)
Density plot with 95% CrI shading and mean dashed line.
print(prior)
Summary: distribution, parameters, mean, SD, 95% CrI.
Expert Pooling -- Aggregate beliefs from multiple experts
aggregate_experts(priors, weights, method)
Linear or logarithmic opinion pooling with Bhattacharyya agreement diagnostics.
priors named listweights must sum to 1method = "linear" | "logarithmic"
e1 <- elicit_beta(0.25, 0.08, "moments", expert_id="E1") e2 <- elicit_beta(0.35, 0.10, "moments", expert_id="E2") con <- aggregate_experts( priors = list(E1=e1, E2=e2), weights = c(0.6, 0.4), method = "linear")
E1: Beta(a1,b1)
w=0.60
E2: Beta(a2,b2)
w=0.40
Mixture
consensus
Bhattacharyya coefficient in con$aggregation$disagreement: 1 = identical experts, 0 = no overlap. Values <0.5 warrant review.
Conflict Diagnostics -- Detect prior-data conflict
prior_conflict(prior, data_summary, alpha)
Box p-value, surprise index, KL divergence, Bhattacharyya overlap.
Binary: type="binary"xn
Continuous: type="continuous"xsdn
cd <- prior_conflict( prior = p, data_summary = list(type="binary", x=18, n=40), alpha = 0.05)
Severity classification:
NONE   Box p > 0.10 MILD   p < 0.10 SEVERE   p < alpha
FieldDescription
box_pvaluePrior predictive p-value (Box 1980)
surprise_indexStandardised distance from prior mean
kl_prior_likelihoodKL divergence prior || likelihood
overlapBhattacharyya overlap coefficient
conflict_severity"none" / "mild" / "severe"
recommendationAutomatic actionable guidance
plot_prior_likelihood(prior, data_summary, show_posterior)
Prior / likelihood / posterior density overlay plot.
gp <- plot_prior_likelihood(p, data_obs, show_posterior = TRUE)
conflict_mahalanobis(prior_means, prior_cov, obs_means, obs_cov, labels)
Multivariate omnibus test for co-primary endpoints. Returns chi-squared p-value and per-parameter z-scores.
mv <- conflict_mahalanobis( prior_means = c(0.35, 0.60), prior_cov = matrix(c(0.01, 0.003, 0.003, 0.015), 2, 2), obs_means = c(0.55, 0.58), obs_cov = matrix(c(0.008,0.002,0.002,0.010),2,2)/50, labels = c("ORR", "OS"))
Sensitivity Analysis -- Posterior robustness to hyperparameter choice
sensitivity_grid(prior, data_summary, param_grid, target, threshold)
Evaluate posterior quantities over a hyperparameter grid.
target: "posterior_mean" "posterior_sd" "prob_efficacy"
sa <- sensitivity_grid( prior = p, data_summary = list(type="binary", x=14, n=40), param_grid = list(alpha=seq(1,8,0.5), beta=seq(2,20,1)), target = c("posterior_mean","prob_efficacy"), threshold = 0.30)
sensitivity_cri(prior, data_summary, param_grid, cri_level)
Track credible interval width and bounds across the grid. Key for regulatory submissions.
cri <- sensitivity_cri(p, data_obs, param_grid = list(alpha=seq(1,8,0.5), beta=seq(2,20,1)), cri_level = 0.95)
Grid
alpha x beta
cri_lower
cri_upper
cri_width
plot_tornado(sa)
Bar chart: influence range ordered from largest to smallest.
plot_sensitivity(sa, target)
Two-dimensional heatmap of posterior quantity over the parameter grid.
plot_sensitivity(sa, target="posterior_mean") plot_sensitivity(cri, target="cri_width")
Robust Priors -- Sceptical, mixture, and power priors
robust_prior(prior, vague_weight, ...)
Schmidli et al. (2014) robust mixture: informative + vague Normal component.
priorvague_weight 0-1, e.g. 0.20 = 20% vague
rob <- robust_prior(p, vague_weight=0.20) plot(rob) # density overlay
Informative
Beta(a,b) 80%
+
Vague
Normal 20%
Robust
mixture
sceptical_prior(null_value, family, strength)
Spiegelhalter & Freedman (1994) prior centred at the null. Calibrated to weak / moderate / strong scepticism.
family: "normal" | "beta" | "lognormal"
strength: "weak" | "moderate" | "strong"
sc <- sceptical_prior( null_value = 0.20, family = "beta", strength = "moderate")
For Beta priors, null_value must be in (0, 1).
calibrate_power_prior(historical_data, current_data, base_prior, target_bf, delta_grid, method)
Ibrahim & Chen (2000) power prior: down-weights historical data by delta, calibrated to a target Bayes Factor.
method: "bayes_factor" | "compatibility"
calib <- calibrate_power_prior( historical_data = list(type="binary", x=12, n=40), current_data = list(type="binary", x=18, n=50), base_prior = elicit_beta(0.5,0.2,"moments"), target_bf = 3, method = "bayes_factor") plot(calib) # calibration curves + optimal delta
Regulatory Reporting -- Quarto HTML / PDF / Word reports
prior_report(prior, conflict, sensitivity, ...)
Render a self-contained regulatory justification report via Quarto.
prior_report( prior = p, conflict = cd, sensitivity = sa, robust_prior = rob, # optional sceptical_prior = sc, # optional output_format = "pdf", # "html" | "pdf" | "docx" output_file = "prior_justification", trial_name = "TRIAL-001", sponsor = "BioPharma Ltd", author = "J. Smith, Biostatistician", notes = "Prior pre-specified in SAP v2.1.")
Requires devtools::install() -- not load_all(). Quarto spawns a fresh R session.
Report sections: Executive summary • Trial information • Prior specification (density + parameters) • Conflict diagnostics (Box p-value, overlay) • Sensitivity (tornado, heatmap) • Robust/sceptical/power priors • FDA/EMA compliance checklist • Session info
Typical Workflow
  1. Elicit prior: elicit_beta() / elicit_roulette()
  2. Pool experts: aggregate_experts()
  3. Check conflict: prior_conflict()
  4. Assess sensitivity: sensitivity_grid() or sensitivity_cri()
  5. Build robust prior: robust_prior() / sceptical_prior()
  6. Generate report: prior_report(..., output_format="pdf")
run_app()
Launch the full Shiny app with dark/light mode toggle. All panels feed directly into the downloaded report.
Install & Docs
pak::pak("ndohpenngit/bayprior") # or devtools::install_github("ndohpenngit/bayprior", build_vignettes = TRUE)
Docs: ndohpenngit.github.io/bayprior
Vignettes: browseVignettes("bayprior")
Citation: citation("bayprior")
Issues: github.com/ndohpenngit/bayprior/issues