| Title: | Modular Bayesian Hierarchical Shrinkage Models |
|---|---|
| Description: | Implements a two-stage Bayesian hierarchical modeling framework for applying shrinkage to subgroup-specific effects. The package separates model fitting (Stage 1) from hierarchical shrinkage (Stage 2), enabling modular sensitivity analyses without refitting expensive Markov chain Monte Carlo (MCMC) chains. Supports flexible prior specifications through the 'distributional' package, mixture approximations via 'mclust', and efficient 'Stan'-based inference. |
| Authors: | Jacob M. Maronge [aut, cre] (ORCID: <https://orcid.org/0000-0003-3606-0841>), GlaxoSmithKline Research & Development Limited [cph, fnd], Trustees of Columbia University [cph] (R/stanmodels.R, configure, configure.win) |
| Maintainer: | Jacob M. Maronge <[email protected]> |
| License: | GPL (>= 3) |
| Version: | 0.4.5 |
| Built: | 2026-07-07 08:30:05 UTC |
| Source: | https://github.com/gsk-biostatistics/shrinkr |
The shrinkr package provides a flexible framework for two-stage Bayesian
hierarchical modeling. It enables post-hoc shrinkage of subgroup-specific
posterior estimates from any Bayesian model, with support for diverse prior
specifications and diagnostic tools.
Two-Stage Workflow:
Stage 1: Fit any Bayesian model without shrinkage
Stage 2: Apply hierarchical shrinkage with flexible priors
Flexible Priors:
Standard families (Normal, Student-t, Cauchy, Lognormal)
Heavy-tailed (Inverse-Gamma, Half-Cauchy, Half-t)
Bounded (Uniform)
Mixture priors (spike-and-slab)
Truncated distributions
Input Methods:
Full posterior samples (via mixture approximation)
Point estimates + variance/covariance
Core Workflow:
fit_mixture(): Approximate Stage 1 posteriors with Gaussian mixture
shrink(): Main user interface for hierarchical shrinkage
Prior Specification:
prior_spike_slab(): Create spike-and-slab mixture prior
prior_mixture(): Create custom mixture prior
sample_prior_predictive(): Generate prior predictive samples for checking
Extraction & Visualization:
extract_mu_tau(): Extract hyperparameter draws
extract_theta(): Extract group-level draws
summarise_mu_tau(): Summarize hyperparameters
summarise_theta(): Summarize group-level estimates
theta_contrasts(): Compute linear combinations of theta
plot(): Visualize shrinkage effect and mixture approximation quality
See vignette("getting_started", package = "shrinkr") for a basic workflow,
or vignette("brms_integration", package = "shrinkr") for a survival analysis example.
Meta-analysis: Shrink study-specific effects
Clinical trials: Borrow information across subgroups or historical controls
Genomics: Regularize gene-specific effects
Simulation studies: Compare shrinkage methods systematically
shrinkr.refresh: Controls Stan sampling progress output (default: 100)
Maintainer: Jacob M. Maronge [email protected] (ORCID)
Authors:
Jacob M. Maronge [email protected] (ORCID)
Other contributors:
GlaxoSmithKline Research & Development Limited [copyright holder, funder]
Trustees of Columbia University (R/stanmodels.R, configure, configure.win) [copyright holder]
Maronge, J. M. (2026). shrinkr: Modular Bayesian Hierarchical Shrinkage Models. R package version 0.4.3.
Stan: https://mc-stan.org/
distributional package: https://pkg.mitchelloharawild.com/distributional/
## Not run: # This example fits a Stan model, so it is not run during package checks. library(shrinkr) priors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_student_t(3, 0, 1), lower = 0) ) fit <- shrink( mle = c(0.0, 0.5, 1.0), var_matrix = c(0.25, 0.25, 0.25), hierarchical_priors = priors, iter = 1000, chains = 2, seed = 1 ) summary(fit) ## End(Not run)## Not run: # This example fits a Stan model, so it is not run during package checks. library(shrinkr) priors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_student_t(3, 0, 1), lower = 0) ) fit <- shrink( mle = c(0.0, 0.5, 1.0), var_matrix = c(0.25, 0.25, 0.25), hierarchical_priors = priors, iter = 1000, chains = 2, seed = 1 ) summary(fit) ## End(Not run)
Extracts posterior draws in tidy format using the posterior package.
By default returns user-facing parameters (mu, tau, theta, etc.) and
excludes internal parameterization details. Set include_internals = TRUE
to access all parameters including theta_c and z.
## S3 method for class 'shrinkr_fit' as_draws_df(x, variables = NULL, include_internals = FALSE, ...)## S3 method for class 'shrinkr_fit' as_draws_df(x, variables = NULL, include_internals = FALSE, ...)
x |
A |
variables |
Character vector of parameter names to extract. Options include:
If |
include_internals |
Logical; if |
... |
Additional arguments passed to |
A posterior::draws_df with columns for chain, iteration, draw,
and requested parameters.
shrink() for fitting models,
extract_mu_tau() for hyperparameters only
set.seed(1) draws <- data.frame( mu = rnorm(20, 0.2, 0.05), tau = abs(rnorm(20, 0.3, 0.03)), `theta[1]` = rnorm(20, 0.0, 0.1), `theta[2]` = rnorm(20, 0.3, 0.1), `theta[3]` = rnorm(20, 0.5, 0.1), check.names = FALSE ) draws$tau_squared <- draws$tau^2 fit <- list( fit = posterior::as_draws_df(draws), data = list( G = 3, K = 1, centered = FALSE, vars = c("group1", "group2", "group3"), quantiles = data.frame( q2.5 = c(-0.20, 0.10, 0.30), q50 = c(0.00, 0.30, 0.50), q97.5 = c(0.20, 0.50, 0.70) ) ), summary = posterior::summarise_draws( posterior::as_draws_df(draws), "mean", "sd", ~posterior::quantile2(., probs = c(0.025, 0.5, 0.975)) ), diagnostics = list(n_divergent = 0, max_treedepth = 0, n_leapfrog = 0) ) class(fit) <- "shrinkr_fit" all_draws <- posterior::as_draws_df(fit) posterior::variables(all_draws) theta_draws <- posterior::as_draws_df(fit, variables = c("theta[1]", "theta[2]"))set.seed(1) draws <- data.frame( mu = rnorm(20, 0.2, 0.05), tau = abs(rnorm(20, 0.3, 0.03)), `theta[1]` = rnorm(20, 0.0, 0.1), `theta[2]` = rnorm(20, 0.3, 0.1), `theta[3]` = rnorm(20, 0.5, 0.1), check.names = FALSE ) draws$tau_squared <- draws$tau^2 fit <- list( fit = posterior::as_draws_df(draws), data = list( G = 3, K = 1, centered = FALSE, vars = c("group1", "group2", "group3"), quantiles = data.frame( q2.5 = c(-0.20, 0.10, 0.30), q50 = c(0.00, 0.30, 0.50), q97.5 = c(0.20, 0.50, 0.70) ) ), summary = posterior::summarise_draws( posterior::as_draws_df(draws), "mean", "sd", ~posterior::quantile2(., probs = c(0.025, 0.5, 0.975)) ), diagnostics = list(n_divergent = 0, max_treedepth = 0, n_leapfrog = 0) ) class(fit) <- "shrinkr_fit" all_draws <- posterior::as_draws_df(fit) posterior::variables(all_draws) theta_draws <- posterior::as_draws_df(fit, variables = c("theta[1]", "theta[2]"))
Extracts posterior draws as a regular data frame. This is a convenience
wrapper around as_draws_df() that returns a plain data.frame.
## S3 method for class 'shrinkr_fit' as.data.frame( x, row.names = NULL, optional = FALSE, variables = NULL, include_internals = FALSE, ... )## S3 method for class 'shrinkr_fit' as.data.frame( x, row.names = NULL, optional = FALSE, variables = NULL, include_internals = FALSE, ... )
x |
A |
row.names |
NULL or character vector giving row names. |
optional |
Logical; if |
variables |
Character vector of parameter names to extract.
If |
include_internals |
Logical; if |
... |
Additional arguments passed to |
A data.frame with columns for chain, iteration, draw, and requested parameters.
as_draws_df.shrinkr_fit() for posterior package format,
extract_mu_tau() for hyperparameters only
set.seed(1) draws <- data.frame( mu = rnorm(20, 0.2, 0.05), tau = abs(rnorm(20, 0.3, 0.03)), `theta[1]` = rnorm(20, 0.0, 0.1), `theta[2]` = rnorm(20, 0.3, 0.1), `theta[3]` = rnorm(20, 0.5, 0.1), check.names = FALSE ) draws$tau_squared <- draws$tau^2 fit <- list( fit = posterior::as_draws_df(draws), data = list( G = 3, K = 1, centered = FALSE, vars = c("group1", "group2", "group3"), quantiles = data.frame( q2.5 = c(-0.20, 0.10, 0.30), q50 = c(0.00, 0.30, 0.50), q97.5 = c(0.20, 0.50, 0.70) ) ), summary = posterior::summarise_draws( posterior::as_draws_df(draws), "mean", "sd", ~posterior::quantile2(., probs = c(0.025, 0.5, 0.975)) ), diagnostics = list(n_divergent = 0, max_treedepth = 0, n_leapfrog = 0) ) class(fit) <- "shrinkr_fit" draws_df <- as.data.frame(fit) head(draws_df) mu_tau_df <- as.data.frame(fit, variables = c("mu", "tau"))set.seed(1) draws <- data.frame( mu = rnorm(20, 0.2, 0.05), tau = abs(rnorm(20, 0.3, 0.03)), `theta[1]` = rnorm(20, 0.0, 0.1), `theta[2]` = rnorm(20, 0.3, 0.1), `theta[3]` = rnorm(20, 0.5, 0.1), check.names = FALSE ) draws$tau_squared <- draws$tau^2 fit <- list( fit = posterior::as_draws_df(draws), data = list( G = 3, K = 1, centered = FALSE, vars = c("group1", "group2", "group3"), quantiles = data.frame( q2.5 = c(-0.20, 0.10, 0.30), q50 = c(0.00, 0.30, 0.50), q97.5 = c(0.20, 0.50, 0.70) ) ), summary = posterior::summarise_draws( posterior::as_draws_df(draws), "mean", "sd", ~posterior::quantile2(., probs = c(0.025, 0.5, 0.975)) ), diagnostics = list(n_divergent = 0, max_treedepth = 0, n_leapfrog = 0) ) class(fit) <- "shrinkr_fit" draws_df <- as.data.frame(fit) head(draws_df) mu_tau_df <- as.data.frame(fit, variables = c("mu", "tau"))
Converts a fitted mixture model to a tidy long-format data frame.
This is essentially an accessor for the components element.
## S3 method for class 'shrinkr_mixture' as.data.frame(x, row.names = NULL, optional = FALSE, ...)## S3 method for class 'shrinkr_mixture' as.data.frame(x, row.names = NULL, optional = FALSE, ...)
x |
A |
row.names |
Ignored (for S3 consistency). |
optional |
Ignored (for S3 consistency). |
... |
Additional arguments (currently unused). |
A data frame (or tibble if available) containing the component specifications with columns:
component |
Component number (1 to K) |
variable |
Variable name |
weight |
Component weight (mixing proportion) |
mean |
Component mean for this variable |
sd |
Component marginal standard deviation for this variable |
fit_mixture for fitting mixture models
set.seed(1) samples <- list( group1 = matrix(rnorm(100, 0.0, 0.5), ncol = 1), group2 = matrix(rnorm(100, 0.5, 0.5), ncol = 1) ) mix <- fit_mixture(samples, K_max = 2, verbose = FALSE) df <- as.data.frame(mix) head(df)set.seed(1) samples <- list( group1 = matrix(rnorm(100, 0.0, 0.5), ncol = 1), group2 = matrix(rnorm(100, 0.5, 0.5), ncol = 1) ) mix <- fit_mixture(samples, K_max = 2, verbose = FALSE) df <- as.data.frame(mix) head(df)
Converts prior predictive samples to a tidy long-format data frame suitable for analysis and visualization with tidyverse tools.
## S3 method for class 'shrinkr_prior_pred' as.data.frame(x, row.names = NULL, optional = FALSE, ...)## S3 method for class 'shrinkr_prior_pred' as.data.frame(x, row.names = NULL, optional = FALSE, ...)
x |
A |
row.names |
Ignored (for S3 consistency). |
optional |
Ignored (for S3 consistency). |
... |
Additional arguments (currently unused). |
A data frame (or tibble if tibble package is available) with columns:
.draw |
Draw number (1 to n_draws) |
group |
Group name |
theta |
Sampled group-level effect |
mu |
Sampled global mean for this draw |
tau |
Sampled heterogeneity parameter for this draw |
sample_prior_predictive for generating prior predictive samples
priors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_normal(0, 1), lower = 0) ) prior_pred <- sample_prior_predictive(priors, n_groups = 3, n_draws = 50) df <- as.data.frame(prior_pred) head(df)priors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_normal(0, 1), lower = 0) ) prior_pred <- sample_prior_predictive(priors, n_groups = 3, n_draws = 50) df <- as.data.frame(prior_pred) head(df)
Extracts posterior draws for the hyperparameters mu (global mean) and tau (heterogeneity standard deviation) from a fitted shrinkage model.
extract_mu_tau(x, ...)extract_mu_tau(x, ...)
x |
A |
... |
Additional arguments (currently unused). |
A posterior::draws_df with columns:
.chainChain index
.iterationIteration within chain
.drawOverall draw index
muGlobal mean parameter
tauHeterogeneity parameter
tau_squaredVariance (tau^2)
shrink() for fitting models,
summarise_mu_tau() for summary statistics,
as_draws_df.shrinkr_fit() for all parameters
set.seed(1) draws <- data.frame( mu = rnorm(20, 0.2, 0.05), tau = abs(rnorm(20, 0.3, 0.03)), `theta[1]` = rnorm(20, 0.0, 0.1), `theta[2]` = rnorm(20, 0.3, 0.1), `theta[3]` = rnorm(20, 0.5, 0.1), check.names = FALSE ) draws$tau_squared <- draws$tau^2 fit <- list( fit = posterior::as_draws_df(draws), data = list( G = 3, K = 1, centered = FALSE, vars = c("group1", "group2", "group3"), quantiles = data.frame( q2.5 = c(-0.20, 0.10, 0.30), q50 = c(0.00, 0.30, 0.50), q97.5 = c(0.20, 0.50, 0.70) ) ), summary = posterior::summarise_draws( posterior::as_draws_df(draws), "mean", "sd", ~posterior::quantile2(., probs = c(0.025, 0.5, 0.975)) ), diagnostics = list(n_divergent = 0, max_treedepth = 0, n_leapfrog = 0) ) class(fit) <- "shrinkr_fit" mu_tau <- extract_mu_tau(fit) summarise_mu_tau(fit) posterior::summarise_draws(mu_tau)set.seed(1) draws <- data.frame( mu = rnorm(20, 0.2, 0.05), tau = abs(rnorm(20, 0.3, 0.03)), `theta[1]` = rnorm(20, 0.0, 0.1), `theta[2]` = rnorm(20, 0.3, 0.1), `theta[3]` = rnorm(20, 0.5, 0.1), check.names = FALSE ) draws$tau_squared <- draws$tau^2 fit <- list( fit = posterior::as_draws_df(draws), data = list( G = 3, K = 1, centered = FALSE, vars = c("group1", "group2", "group3"), quantiles = data.frame( q2.5 = c(-0.20, 0.10, 0.30), q50 = c(0.00, 0.30, 0.50), q97.5 = c(0.20, 0.50, 0.70) ) ), summary = posterior::summarise_draws( posterior::as_draws_df(draws), "mean", "sd", ~posterior::quantile2(., probs = c(0.025, 0.5, 0.975)) ), diagnostics = list(n_divergent = 0, max_treedepth = 0, n_leapfrog = 0) ) class(fit) <- "shrinkr_fit" mu_tau <- extract_mu_tau(fit) summarise_mu_tau(fit) posterior::summarise_draws(mu_tau)
Extracts posterior draws for the group-level effects (theta parameters) from a fitted shrinkage model. This is the hierarchically shrunk version of the subgroup effects.
extract_theta(x, ...)extract_theta(x, ...)
x |
A |
... |
Additional arguments passed to |
A posterior::draws_df with columns:
.chainChain index
.iterationIteration within chain
.drawOverall draw index
theta[1], theta[2], ...Group-level effects
shrink() for fitting models,
extract_mu_tau() for hyperparameters,
summarise_theta() for summary statistics,
theta_contrasts() for pairwise comparisons
set.seed(1) draws <- data.frame( mu = rnorm(20, 0.2, 0.05), tau = abs(rnorm(20, 0.3, 0.03)), `theta[1]` = rnorm(20, 0.0, 0.1), `theta[2]` = rnorm(20, 0.3, 0.1), `theta[3]` = rnorm(20, 0.5, 0.1), check.names = FALSE ) draws$tau_squared <- draws$tau^2 fit <- list( fit = posterior::as_draws_df(draws), data = list( G = 3, K = 1, centered = FALSE, vars = c("group1", "group2", "group3"), quantiles = data.frame( q2.5 = c(-0.20, 0.10, 0.30), q50 = c(0.00, 0.30, 0.50), q97.5 = c(0.20, 0.50, 0.70) ) ), summary = posterior::summarise_draws( posterior::as_draws_df(draws), "mean", "sd", ~posterior::quantile2(., probs = c(0.025, 0.5, 0.975)) ), diagnostics = list(n_divergent = 0, max_treedepth = 0, n_leapfrog = 0) ) class(fit) <- "shrinkr_fit" theta_draws <- extract_theta(fit) posterior::summarise_draws(theta_draws) summarise_theta(fit)set.seed(1) draws <- data.frame( mu = rnorm(20, 0.2, 0.05), tau = abs(rnorm(20, 0.3, 0.03)), `theta[1]` = rnorm(20, 0.0, 0.1), `theta[2]` = rnorm(20, 0.3, 0.1), `theta[3]` = rnorm(20, 0.5, 0.1), check.names = FALSE ) draws$tau_squared <- draws$tau^2 fit <- list( fit = posterior::as_draws_df(draws), data = list( G = 3, K = 1, centered = FALSE, vars = c("group1", "group2", "group3"), quantiles = data.frame( q2.5 = c(-0.20, 0.10, 0.30), q50 = c(0.00, 0.30, 0.50), q97.5 = c(0.20, 0.50, 0.70) ) ), summary = posterior::summarise_draws( posterior::as_draws_df(draws), "mean", "sd", ~posterior::quantile2(., probs = c(0.025, 0.5, 0.975)) ), diagnostics = list(n_divergent = 0, max_treedepth = 0, n_leapfrog = 0) ) class(fit) <- "shrinkr_fit" theta_draws <- extract_theta(fit) posterior::summarise_draws(theta_draws) summarise_theta(fit)
Fits a multivariate Gaussian mixture model (GMM) jointly across all supplied variables using mclust. The function is intended for approximating posterior draws from Bayesian models and produces a tidy component table suitable for visualization and shrinkage modeling.
fit_mixture(samples, K_max = 5L, verbose = FALSE, model_names = NULL, ...)fit_mixture(samples, K_max = 5L, verbose = FALSE, model_names = NULL, ...)
samples |
Posterior samples in one of the following formats:
At least two groups/variables are required for hierarchical shrinkage. Non-numeric columns in data frames are automatically dropped. Rows with missing values are removed before fitting. |
K_max |
Integer |
verbose |
Logical. If |
model_names |
Optional character vector of mclust covariance model
codes to consider (e.g., |
... |
Additional arguments forwarded to |
Requires at least two variables; shrinkage across a single variable is not meaningful.
Rows with any missing values are removed before fitting.
Component weights are normalized to sum to one.
The sd column reports marginal standard deviations (square roots of
diagonal entries) from each component covariance matrix.
A list with class "shrinkr_mixture" containing:
components — data frame with columns: group, component, variable,
weight, mean, and sd (marginal standard deviations).
K — number of mixture components selected.
vars — character vector of variable names.
weights — vector of component weights (mixing proportions).
covs — list of component covariance matrices (p × p each).
model_name — selected mclust covariance structure (e.g., "VVV").
bic — Bayesian Information Criterion for the fitted model.
n_samples — number of samples used in fitting.
n_vars — number of variables.
mclust_fit — the complete mclust model object (for advanced use).
diagnostics — list with sample size details, removed rows, and
quality warnings.
mclust parameterizes component covariances via eigen-decomposition and offers a set of model families controlling volume (V), shape (S), and orientation (O). Common codes include (non-exhaustive):
"EII": equal volume, spherical "VII": variable volume, spherical
"EEI": equal volume & shape (axis-aligned) "VEI": variable volume, equal shape "EVI": equal volume, variable shape "VVI": variable volume & shape
"EEE": equal volume, shape, orientation "EEV": equal volume & shape, variable orientation "VEV": variable volume, equal shape, variable orientation "VVV": variable volume, shape, and orientation (most flexible)
If model_names = NULL (default), mclust::Mclust() selects among
the models appropriate for the data dimension via BIC. In practice, this lets
the data decide between parsimonious structures (e.g., "EII", "VVI")
and fully flexible ones (e.g., "VVV"). You can restrict or expand the
search space by supplying model_names.
plot.shrinkr_mixture for visualizing marginal fits,
as.data.frame.shrinkr_mixture for extracting component data
set.seed(1) samples <- list( group1 = matrix(rnorm(100, 0.0, 0.5), ncol = 1), group2 = matrix(rnorm(100, 0.5, 0.5), ncol = 1), group3 = matrix(rnorm(100, 1.0, 0.5), ncol = 1) ) mix <- fit_mixture(samples, K_max = 2, verbose = FALSE) summary(mix)set.seed(1) samples <- list( group1 = matrix(rnorm(100, 0.0, 0.5), ncol = 1), group2 = matrix(rnorm(100, 0.5, 0.5), ncol = 1), group3 = matrix(rnorm(100, 1.0, 0.5), ncol = 1) ) mix <- fit_mixture(samples, K_max = 2, verbose = FALSE) summary(mix)
Visualizes the hierarchical shrinkage model fit. Creates either:
"shrinkage" — Shows pre/post-shrunk estimates with arrows
"diagnostics" — Multi-panel view with hyperparameters and shrinkage factor
The shrinkage plot displays:
Pre-shrunk estimates (hollow circles) — from stage 1 mixture or MLEs
Post-shrunk estimates (filled circles) — posterior means of theta
Global mean (dashed line) — posterior mean of mu
Credible intervals (optional) — for shrunken estimates
Arrows (optional) — showing direction and magnitude of shrinkage
## S3 method for class 'shrinkr_fit' plot( x, type = c("shrinkage", "diagnostics"), group_names = NULL, show_arrows = FALSE, show_intervals = TRUE, interval_prob = 0.95, point_size = 3, arrow_alpha = 0.6, dodge_width = 0.3, title = NULL, subtitle = NULL, ... )## S3 method for class 'shrinkr_fit' plot( x, type = c("shrinkage", "diagnostics"), group_names = NULL, show_arrows = FALSE, show_intervals = TRUE, interval_prob = 0.95, point_size = 3, arrow_alpha = 0.6, dodge_width = 0.3, title = NULL, subtitle = NULL, ... )
x |
A |
type |
Character; type of plot. Options:
|
group_names |
Optional character vector of length G to label groups.
If |
show_arrows |
Logical; draw arrows from pre-shrunk to post-shrunk estimates?
Default |
show_intervals |
Logical; show credible intervals for both pre-shrunk and
post-shrunk estimates? Default |
interval_prob |
Numeric; probability mass for credible intervals.
Default 0.95 for 95% intervals. Only applies when |
point_size |
Numeric; size of points. Default 3. |
arrow_alpha |
Numeric; transparency of arrows (0-1). Default 0.6.
Only applies when |
dodge_width |
Numeric; horizontal spacing between pre-shrunk and post-shrunk estimates in the side-by-side display. Default 0.3. Larger values increase separation between estimate types. |
title |
Character; plot title. If |
subtitle |
Character; plot subtitle. If |
... |
Additional arguments (currently unused). |
A ggplot2 object (for type = "shrinkage"), or a patchwork object/list
(for type = "diagnostics").
shrink() for fitting models,
extract_mu_tau() for hyperparameter draws
# Plotting requires a fitted shrinkr_fit object from shrink(). # The full example is not run because it fits a Stan model. ## Not run: fit <- shrink(mixture = mix, hierarchical_priors = priors) plot(fit) plot(fit, show_arrows = TRUE, interval_prob = 0.95) ## End(Not run)# Plotting requires a fitted shrinkr_fit object from shrink(). # The full example is not run because it fits a Stan model. ## Not run: fit <- shrink(mixture = mix, hierarchical_priors = priors) plot(fit) plot(fit, show_arrows = TRUE, interval_prob = 0.95) ## End(Not run)
Overlays fitted marginal mixture densities from a shrinkr_mixture
(returned by fit_mixture()) on top of the observed samples for
selected variables, OR creates QQ plots comparing empirical vs fitted quantiles.
The function uses the same coercion logic as fit_mixture() (via an internal
.coerce_draws_df() helper), ensuring that variable names line up even when
users pass a list of matrices.
Important: For multivariate joint fits, this produces marginal overlays (one panel per variable when faceting). Each marginal density is computed by summing the weighted component densities for that variable.
## S3 method for class 'shrinkr_mixture' plot( x, draws = NULL, variables = NULL, type = c("density", "qq"), overlay = c("hist", "kde", "both", "none"), bins = 50, kde_bw = NULL, show_components = TRUE, facet = TRUE, n_points = 501, verbose = FALSE, ... )## S3 method for class 'shrinkr_mixture' plot( x, draws = NULL, variables = NULL, type = c("density", "qq"), overlay = c("hist", "kde", "both", "none"), bins = 50, kde_bw = NULL, show_components = TRUE, facet = TRUE, n_points = 501, verbose = FALSE, ... )
x |
A |
draws |
Optional samples to show as histogram/KDE or for QQ plot. Accepts any
input shape supported by |
variables |
Character vector of variables to plot. Defaults to all
variables in |
type |
One of |
overlay |
One of |
bins |
Integer number of bins for the histogram (default |
kde_bw |
Bandwidth for |
show_components |
Logical; if |
facet |
Logical; if |
n_points |
Integer; number of x grid points for evaluating densities
(default |
verbose |
Logical; print brief matching diagnostics. |
... |
Additional arguments (currently unused). |
The total marginal density for each variable is computed as
using per-component marginal SDs (sd) already stored in x$components.
The plotting range per variable is taken from the sample range if available
(with 5% padding), otherwise from mean +/- 4*sd across that variable's
components–avoiding non-finite seq() errors when samples are absent.
When type = "qq", the function creates quantile-quantile plots by:
Computing empirical quantiles from the observed data
Computing theoretical quantiles from the fitted mixture CDF via numerical inversion
Plotting empirical vs theoretical quantiles with a 45-degree reference line
Points falling on the reference line indicate good agreement between the fitted mixture and the data. Systematic deviations suggest model misfit.
A ggplot2 object.
fit_mixture() for fitting mixture models
set.seed(1) samples <- list( group1 = matrix(rnorm(100, 0.0, 0.5), ncol = 1), group2 = matrix(rnorm(100, 0.5, 0.5), ncol = 1) ) mix <- fit_mixture(samples, K_max = 2, verbose = FALSE) plot(mix, draws = samples, type = "density", variables = c("group1", "group2"))set.seed(1) samples <- list( group1 = matrix(rnorm(100, 0.0, 0.5), ncol = 1), group2 = matrix(rnorm(100, 0.5, 0.5), ncol = 1) ) mix <- fit_mixture(samples, K_max = 2, verbose = FALSE) plot(mix, draws = samples, type = "density", variables = c("group1", "group2"))
Creates a density plot of
from prior predictive samples. Useful for calibrating hierarchical priors.
Styling matches plot.shrinkr_prior_pred() for visual consistency.
## S3 method for class 'shrinkr_prior_contrasts' plot(x, by_pair = FALSE, ...)## S3 method for class 'shrinkr_prior_contrasts' plot(x, by_pair = FALSE, ...)
x |
A |
by_pair |
Logical; if |
... |
Additional arguments (currently unused). |
A ggplot2 object.
priors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_normal(0, 1), lower = 0) ) prior_pred <- sample_prior_predictive(priors, n_groups = 3, n_draws = 50) pw <- prior_pairwise_differences(prior_pred) plot(pw)priors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_normal(0, 1), lower = 0) ) prior_pred <- sample_prior_predictive(priors, n_groups = 3, n_draws = 50) pw <- prior_pairwise_differences(prior_pred) plot(pw)
Visualizes the prior predictive distribution for hyperparameters (mu and tau) and subgroup effects (theta). Requires the ggplot2 package.
## S3 method for class 'shrinkr_prior_pred' plot(x, type = c("both", "hyperparameters", "theta"), ...)## S3 method for class 'shrinkr_prior_pred' plot(x, type = c("both", "hyperparameters", "theta"), ...)
x |
A |
type |
Character; type of plot. Options:
|
... |
Additional arguments (currently unused). |
A ggplot2 object, or a list of two ggplot2 objects if type = "both"
and patchwork package is not available. If patchwork is available and
type = "both", returns a combined plot.
sample_prior_predictive for generating samples,
as.data.frame.shrinkr_prior_pred for extracting data
priors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_student_t(3, 0, 1), lower = 0) ) prior_pred <- sample_prior_predictive(priors, n_groups = 3, n_draws = 50) plot(prior_pred, type = "hyperparameters")priors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_student_t(3, 0, 1), lower = 0) ) prior_pred <- sample_prior_predictive(priors, n_groups = 3, n_draws = 50) plot(prior_pred, type = "hyperparameters")
Displays a compact summary of the fitted model including dimensions, hyperparameter estimates, and diagnostics.
## S3 method for class 'shrinkr_fit' print(x, digits = 3, ...)## S3 method for class 'shrinkr_fit' print(x, digits = 3, ...)
x |
A |
digits |
Number of digits to display. Default is 3. |
... |
Additional arguments (currently unused). |
Invisibly returns the input object x.
shrink() for fitting models,
summarise_theta() for detailed theta estimates
Displays summary information about a fitted mixture model in a readable format.
## S3 method for class 'shrinkr_mixture' print(x, ...)## S3 method for class 'shrinkr_mixture' print(x, ...)
x |
A |
... |
Additional arguments (currently unused). |
Invisibly returns the input object x.
fit_mixture for fitting mixture models,
summary.shrinkr_mixture for detailed summaries
set.seed(1) samples <- list( group1 = matrix(rnorm(100, 0.0, 0.5), ncol = 1), group2 = matrix(rnorm(100, 0.5, 0.5), ncol = 1) ) mix <- fit_mixture(samples, K_max = 2, verbose = FALSE) print(mix)set.seed(1) samples <- list( group1 = matrix(rnorm(100, 0.0, 0.5), ncol = 1), group2 = matrix(rnorm(100, 0.5, 0.5), ncol = 1) ) mix <- fit_mixture(samples, K_max = 2, verbose = FALSE) print(mix)
Print method for prior pairwise contrasts
## S3 method for class 'shrinkr_prior_contrasts' print(x, digits = 3, ...)## S3 method for class 'shrinkr_prior_contrasts' print(x, digits = 3, ...)
x |
A |
digits |
Number of digits to display. Default 3. |
... |
Additional arguments (currently unused). |
Invisibly returns x.
Displays summary information about prior predictive samples in a readable format.
## S3 method for class 'shrinkr_prior_pred' print(x, ...)## S3 method for class 'shrinkr_prior_pred' print(x, ...)
x |
A |
... |
Additional arguments (currently unused). |
Invisibly returns the input object x.
sample_prior_predictive for generating samples,
summary.shrinkr_prior_pred for detailed summaries
priors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_normal(0, 1), lower = 0) ) prior_pred <- sample_prior_predictive(priors, n_groups = 3, n_draws = 50) print(prior_pred)priors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_normal(0, 1), lower = 0) ) prior_pred <- sample_prior_predictive(priors, n_groups = 3, n_draws = 50) print(prior_pred)
Displays formatted summary statistics for a fitted mixture model.
## S3 method for class 'summary.shrinkr_mixture' print(x, digits = 3, ...)## S3 method for class 'summary.shrinkr_mixture' print(x, digits = 3, ...)
x |
A summary object from |
digits |
Number of decimal digits to display. Default is 3. |
... |
Additional arguments (currently unused). |
Invisibly returns the input object x.
summary.shrinkr_mixture for creating summaries
set.seed(1) samples <- list( group1 = matrix(rnorm(100, 0.0, 0.5), ncol = 1), group2 = matrix(rnorm(100, 0.5, 0.5), ncol = 1) ) mix <- fit_mixture(samples, K_max = 2, verbose = FALSE) summ <- summary(mix) print(summ)set.seed(1) samples <- list( group1 = matrix(rnorm(100, 0.0, 0.5), ncol = 1), group2 = matrix(rnorm(100, 0.5, 0.5), ncol = 1) ) mix <- fit_mixture(samples, K_max = 2, verbose = FALSE) summ <- summary(mix) print(summ)
Displays formatted summary statistics for prior predictive samples.
## S3 method for class 'summary.shrinkr_prior_pred' print(x, digits = 3, ...)## S3 method for class 'summary.shrinkr_prior_pred' print(x, digits = 3, ...)
x |
A summary object from |
digits |
Number of decimal digits to display. Default is 3. |
... |
Additional arguments (currently unused). |
Invisibly returns the input object x.
summary.shrinkr_prior_pred for creating summaries
priors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_normal(0, 1), lower = 0) ) prior_pred <- sample_prior_predictive(priors, n_groups = 3, n_draws = 50) print(summary(prior_pred))priors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_normal(0, 1), lower = 0) ) prior_pred <- sample_prior_predictive(priors, n_groups = 3, n_draws = 50) print(summary(prior_pred))
Creates a mixture distribution using distributional::dist_mixture().
All standard distributional operations (sampling, density, quantiles,
formatting) work automatically.
prior_mixture(..., weights = NULL)prior_mixture(..., weights = NULL)
... |
Component distributions (from distributional package) |
weights |
Mixture weights (normalized automatically if not summing to 1) |
A distributional mixture distribution object
mix <- prior_mixture( distributional::dist_normal(0, 0.1), distributional::dist_normal(0, 1), weights = c(0.7, 0.3) )mix <- prior_mixture( distributional::dist_normal(0, 0.1), distributional::dist_normal(0, 1), weights = c(0.7, 0.3) )
Computes the prior-implied distribution of absolute pairwise differences between subgroup effects. This is useful for calibrating priors: if your prior implies that subgroup differences of 5 units are common but clinical relevance starts at 0.5, your prior may be too diffuse.
This implements the recommendation from the SDSIH Vignettes Library:
inspect the prior distribution of when
choosing priors for Bayesian hierarchical models.
prior_pairwise_differences(prior_pred)prior_pairwise_differences(prior_pred)
prior_pred |
A |
A list with class "shrinkr_prior_contrasts" containing:
differences |
Data frame with columns |
summary |
Data frame with per-pair summary statistics |
overall_summary |
Named numeric vector of quantiles across all pairs |
n_pairs |
Number of unique pairs |
n_draws |
Number of prior predictive draws |
group_names |
Group labels used |
sample_prior_predictive for generating prior predictive samples,
plot.shrinkr_prior_contrasts for visualizing the result
priors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_normal(0, 1), lower = 0) ) prior_pred <- sample_prior_predictive(priors, n_groups = 3, n_draws = 50) pw <- prior_pairwise_differences(prior_pred) print(pw) pw$overall_summarypriors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_normal(0, 1), lower = 0) ) prior_pred <- sample_prior_predictive(priors, n_groups = 3, n_draws = 50) pw <- prior_pairwise_differences(prior_pred) print(pw) pw$overall_summary
Creates a mixture of two Normal distributions. Since tau is a scale parameter,
this must be wrapped in distributional::dist_truncated() with lower = 0
before passing to shrink():
prior_spike_slab( spike_location = 0, spike_scale = 0.01, slab_scale = 1, spike_prob = 0.5 )prior_spike_slab( spike_location = 0, spike_scale = 0.01, slab_scale = 1, spike_prob = 0.5 )
spike_location |
Location of the spike (default 0) |
spike_scale |
Scale of the spike component (default 0.01) |
slab_scale |
Scale of the slab component (default 1) |
spike_prob |
Probability of the spike component (default 0.5) |
tau_prior <- dist_truncated(prior_spike_slab(), lower = 0)
A spike-and-slab mixture distribution
tau_prior <- distributional::dist_truncated( prior_spike_slab(spike_prob = 0.5, spike_scale = 0.01, slab_scale = 1), lower = 0 )tau_prior <- distributional::dist_truncated( prior_spike_slab(spike_prob = 0.5, spike_scale = 0.01, slab_scale = 1), lower = 0 )
Generates samples from the prior predictive distribution for the hierarchical shrinkage model. Useful for prior elicitation and sensitivity analysis.
The generative process is:
Sample mu from p(mu)
Sample tau from p(tau)
Sample theta_i ~ N(mu, tau) for each group i
sample_prior_predictive( hierarchical_priors, n_groups, n_draws = 1000, group_names = NULL )sample_prior_predictive( hierarchical_priors, n_groups, n_draws = 1000, group_names = NULL )
hierarchical_priors |
Named list with |
n_groups |
Integer; number of subgroups (G). |
n_draws |
Integer; number of prior predictive samples to draw. Default 1000. |
group_names |
Optional character vector of length |
A list with class "shrinkr_prior_pred" containing:
mu |
Vector of mu draws |
tau |
Vector of tau draws |
theta |
Matrix of theta draws (n_draws x n_groups) |
implied_range |
Vector of ranges (max - min) of theta across groups for each draw |
implied_sd |
Vector of standard deviations of theta across groups for each draw |
group_names |
Group labels |
n_draws |
Number of draws |
n_groups |
Number of groups |
priors |
The hierarchical_priors specification used |
shrink for fitting the hierarchical model,
plot.shrinkr_prior_pred for visualizing prior predictive samples
priors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_normal(0, 1), lower = 0) ) prior_pred <- sample_prior_predictive(priors, n_groups = 3, n_draws = 50) median(prior_pred$implied_range) head(as.data.frame(prior_pred))priors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_normal(0, 1), lower = 0) ) prior_pred <- sample_prior_predictive(priors, n_groups = 3, n_draws = 50) median(prior_pred$implied_range) head(as.data.frame(prior_pred))
Applies hierarchical shrinkage to group-specific estimates using a two-stage Bayesian approach. Takes either a Gaussian mixture approximation of Stage 1 posteriors or point estimates with variance, and applies a Normal hierarchical model with flexible hyperpriors.
shrink( mixture = NULL, mle = NULL, var_matrix = NULL, hierarchical_priors = list(mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_normal(0, 2.5), lower = 0)), centered = FALSE, verbose = TRUE, ... )shrink( mixture = NULL, mle = NULL, var_matrix = NULL, hierarchical_priors = list(mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_normal(0, 2.5), lower = 0)), centered = FALSE, verbose = TRUE, ... )
mixture |
A |
mle |
Numeric vector of group point estimates. Used when |
var_matrix |
Numeric vector of variances (length |
hierarchical_priors |
Named list with
Supported distributions for Supported distributions for |
centered |
Logical; use centered ( |
verbose |
Logical; print progress messages (default |
... |
Additional arguments passed to
|
Hierarchical model (Stage 2):
Stage 1 likelihood (Gaussian mixture approximation):
Full posterior:
where approximates the Stage 1 posterior for group .
Fixed:
Hierarchical distribution:
Flexible:
Hyperpriors and : Normal, Student-t, Cauchy,
Lognormal, Gamma, Inverse-Gamma, Exponential, Uniform, mixtures (including
spike-and-slab), and truncated versions
Stage 1 posteriors: Can be non-Normal (handled by mixture approximation)
Stage 1 must use flat/uninformative priors on
Ensures two-stage = one-stage hierarchical model
Stan: Don't specify prior (defaults to flat)
JAGS/NIMBLE: Use very wide priors
Verify mixture quality: plot(mixture, draws = samples)
Check density overlays and QQ plots
Poor approximation → biased shrinkage
Check prior implications: sample_prior_predictive(hierarchical_priors)
Understand what priors imply before fitting
Avoid prior-data conflicts
Minimum 2 groups required for heterogeneity estimation
Half-Normal: dist_truncated(dist_normal(0, s), lower = 0) - Weakly informative
Half-t: dist_truncated(dist_student_t(df, 0, s), lower = 0) - Heavier tails
Half-Cauchy: dist_truncated(dist_cauchy(0, s), lower = 0) - Very diffuse
Uniform: dist_uniform(0, U) - Bounded heterogeneity
Inverse-Gamma: dist_inverse_gamma(a, b) - Traditional choice
See vignette("getting_started") for complete workflow,
vignette("brms_integration") for real examples, and package README for
mathematical justification.
A shrinkr_fit object (list) containing:
fit |
Stan model object |
data |
Data list used for fitting |
summary |
Parameter summaries (mean, sd, quantiles, Rhat, ESS) |
diagnostics |
Sampler diagnostics (divergences, treedepth) |
priors |
Prior specifications used |
Workflow functions:
fit_mixture(), sample_prior_predictive()
Extract results:
extract_mu_tau(), extract_theta(), summarize_mu_tau(), summarize_theta(), theta_contrasts()
Visualization:
plot.shrinkr_fit(), plot.shrinkr_mixture()
Vignettes:
vignette("getting_started") - Complete workflow with Stan example
vignette("brms_integration") - Survival analysis example
## Not run: # This example fits a Stan model, so it is not run during package checks. priors <- list( mu = distributional::dist_normal(0, 10), tau = distributional::dist_truncated(distributional::dist_student_t(3, 0, 2.5), lower = 0) ) fit <- shrink( mle = c(0.5, 1.2, -0.3), var_matrix = c(0.1, 0.15, 0.12), hierarchical_priors = priors, iter = 1000, chains = 2, seed = 1 ) summarise_theta(fit) ## End(Not run)## Not run: # This example fits a Stan model, so it is not run during package checks. priors <- list( mu = distributional::dist_normal(0, 10), tau = distributional::dist_truncated(distributional::dist_student_t(3, 0, 2.5), lower = 0) ) fit <- shrink( mle = c(0.5, 1.2, -0.3), var_matrix = c(0.1, 0.15, 0.12), hierarchical_priors = priors, iter = 1000, chains = 2, seed = 1 ) summarise_theta(fit) ## End(Not run)
Computes posterior summaries for the hierarchical hyperparameters
(mu, tau, and tau_squared). Returns a data frame with one row per
parameter containing posterior means, standard deviations, quantiles, and
convergence diagnostics.
This is a focused alternative to summary(fit), which returns summaries
for all parameters including theta.
summarise_mu_tau(fit, probs = c(0.025, 0.5, 0.975), measures = NULL) summarize_mu_tau(fit, probs = c(0.025, 0.5, 0.975), measures = NULL)summarise_mu_tau(fit, probs = c(0.025, 0.5, 0.975), measures = NULL) summarize_mu_tau(fit, probs = c(0.025, 0.5, 0.975), measures = NULL)
fit |
A |
probs |
Numeric vector of quantiles to compute. Default is
|
measures |
Optional character vector or list of summary measures to compute.
If |
A data frame (tibble if available) with one row per parameter and columns:
parameterParameter name (mu, tau, or tau_squared)
meanPosterior mean
sdPosterior standard deviation
q2.5, q50, q97.5
Quantiles (or custom quantiles from probs)
rhatR-hat convergence diagnostic
ess_bulkEffective sample size (bulk)
ess_tailEffective sample size (tail)
shrink() for fitting models,
extract_mu_tau() for raw hyperparameter draws,
summarise_theta() for group-level summaries
set.seed(1) draws <- data.frame( mu = rnorm(20, 0.2, 0.05), tau = abs(rnorm(20, 0.3, 0.03)), `theta[1]` = rnorm(20, 0.0, 0.1), `theta[2]` = rnorm(20, 0.3, 0.1), `theta[3]` = rnorm(20, 0.5, 0.1), check.names = FALSE ) draws$tau_squared <- draws$tau^2 fit <- list( fit = posterior::as_draws_df(draws), data = list( G = 3, K = 1, centered = FALSE, vars = c("group1", "group2", "group3"), quantiles = data.frame( q2.5 = c(-0.20, 0.10, 0.30), q50 = c(0.00, 0.30, 0.50), q97.5 = c(0.20, 0.50, 0.70) ) ), summary = posterior::summarise_draws( posterior::as_draws_df(draws), "mean", "sd", ~posterior::quantile2(., probs = c(0.025, 0.5, 0.975)) ), diagnostics = list(n_divergent = 0, max_treedepth = 0, n_leapfrog = 0) ) class(fit) <- "shrinkr_fit" summarise_mu_tau(fit) summarise_mu_tau(fit, probs = c(0.05, 0.5, 0.95))set.seed(1) draws <- data.frame( mu = rnorm(20, 0.2, 0.05), tau = abs(rnorm(20, 0.3, 0.03)), `theta[1]` = rnorm(20, 0.0, 0.1), `theta[2]` = rnorm(20, 0.3, 0.1), `theta[3]` = rnorm(20, 0.5, 0.1), check.names = FALSE ) draws$tau_squared <- draws$tau^2 fit <- list( fit = posterior::as_draws_df(draws), data = list( G = 3, K = 1, centered = FALSE, vars = c("group1", "group2", "group3"), quantiles = data.frame( q2.5 = c(-0.20, 0.10, 0.30), q50 = c(0.00, 0.30, 0.50), q97.5 = c(0.20, 0.50, 0.70) ) ), summary = posterior::summarise_draws( posterior::as_draws_df(draws), "mean", "sd", ~posterior::quantile2(., probs = c(0.025, 0.5, 0.975)) ), diagnostics = list(n_divergent = 0, max_treedepth = 0, n_leapfrog = 0) ) class(fit) <- "shrinkr_fit" summarise_mu_tau(fit) summarise_mu_tau(fit, probs = c(0.05, 0.5, 0.95))
Computes posterior summaries for subgroup effects (theta parameters). Returns a data frame with one row per group containing posterior means, standard deviations, quantiles, and convergence diagnostics.
This is a focused alternative to summary(fit), which returns summaries
for all parameters including mu and tau.
summarise_theta( fit, probs = c(0.025, 0.5, 0.975), group_names = NULL, measures = NULL ) summarize_theta( fit, probs = c(0.025, 0.5, 0.975), group_names = NULL, measures = NULL )summarise_theta( fit, probs = c(0.025, 0.5, 0.975), group_names = NULL, measures = NULL ) summarize_theta( fit, probs = c(0.025, 0.5, 0.975), group_names = NULL, measures = NULL )
fit |
A |
probs |
Numeric vector of quantiles to compute. Default is
|
group_names |
Optional character vector of length G to label groups.
If |
measures |
Optional character vector or list of summary measures to compute.
If |
A data frame (tibble if available) with one row per group and columns:
groupGroup identifier
meanPosterior mean
sdPosterior standard deviation
q2.5, q50, q97.5
Quantiles (or custom quantiles from probs)
rhatR-hat convergence diagnostic
ess_bulkEffective sample size (bulk)
ess_tailEffective sample size (tail)
shrink() for fitting models,
summarise_mu_tau() for hyperparameter summaries,
theta_contrasts() for computing contrasts
set.seed(1) draws <- data.frame( mu = rnorm(20, 0.2, 0.05), tau = abs(rnorm(20, 0.3, 0.03)), `theta[1]` = rnorm(20, 0.0, 0.1), `theta[2]` = rnorm(20, 0.3, 0.1), `theta[3]` = rnorm(20, 0.5, 0.1), check.names = FALSE ) draws$tau_squared <- draws$tau^2 fit <- list( fit = posterior::as_draws_df(draws), data = list( G = 3, K = 1, centered = FALSE, vars = c("group1", "group2", "group3"), quantiles = data.frame( q2.5 = c(-0.20, 0.10, 0.30), q50 = c(0.00, 0.30, 0.50), q97.5 = c(0.20, 0.50, 0.70) ) ), summary = posterior::summarise_draws( posterior::as_draws_df(draws), "mean", "sd", ~posterior::quantile2(., probs = c(0.025, 0.5, 0.975)) ), diagnostics = list(n_divergent = 0, max_treedepth = 0, n_leapfrog = 0) ) class(fit) <- "shrinkr_fit" summarise_theta(fit) summarise_theta(fit, probs = c(0.05, 0.5, 0.95)) summarise_theta(fit, group_names = c("Control", "A", "B"))set.seed(1) draws <- data.frame( mu = rnorm(20, 0.2, 0.05), tau = abs(rnorm(20, 0.3, 0.03)), `theta[1]` = rnorm(20, 0.0, 0.1), `theta[2]` = rnorm(20, 0.3, 0.1), `theta[3]` = rnorm(20, 0.5, 0.1), check.names = FALSE ) draws$tau_squared <- draws$tau^2 fit <- list( fit = posterior::as_draws_df(draws), data = list( G = 3, K = 1, centered = FALSE, vars = c("group1", "group2", "group3"), quantiles = data.frame( q2.5 = c(-0.20, 0.10, 0.30), q50 = c(0.00, 0.30, 0.50), q97.5 = c(0.20, 0.50, 0.70) ) ), summary = posterior::summarise_draws( posterior::as_draws_df(draws), "mean", "sd", ~posterior::quantile2(., probs = c(0.025, 0.5, 0.975)) ), diagnostics = list(n_divergent = 0, max_treedepth = 0, n_leapfrog = 0) ) class(fit) <- "shrinkr_fit" summarise_theta(fit) summarise_theta(fit, probs = c(0.05, 0.5, 0.95)) summarise_theta(fit, group_names = c("Control", "A", "B"))
Comprehensive posterior summary including hyperparameters and all subgroup effects with convergence diagnostics.
## S3 method for class 'shrinkr_fit' summary( object, probs = c(0.025, 0.5, 0.975), group_names = NULL, digits = 3, ... )## S3 method for class 'shrinkr_fit' summary( object, probs = c(0.025, 0.5, 0.975), group_names = NULL, digits = 3, ... )
object |
A |
probs |
Numeric vector of quantiles to compute. Default is
|
group_names |
Optional character vector to label groups. |
digits |
Number of digits to display. Default is 3. |
... |
Additional arguments (currently unused). |
Invisibly returns a list with mu_tau and theta summary tables.
Prints formatted output.
shrink() for fitting models,
summarise_theta() for theta-only summaries
Computes comprehensive summary statistics for fitted mixture components, including component-wise and variable-wise summaries.
## S3 method for class 'shrinkr_mixture' summary(object, ...)## S3 method for class 'shrinkr_mixture' summary(object, ...)
object |
A |
... |
Additional arguments (currently unused). |
A list with class "summary.shrinkr_mixture" containing:
components |
Data frame with component weights and sizes |
by_variable |
Data frame with per-variable mixture summaries |
model_info |
List with model selection details |
diagnostics |
Fit diagnostics |
fit_mixture for fitting mixture models,
print.shrinkr_mixture for quick overview
set.seed(1) samples <- list( group1 = matrix(rnorm(100, 0.0, 0.5), ncol = 1), group2 = matrix(rnorm(100, 0.5, 0.5), ncol = 1) ) mix <- fit_mixture(samples, K_max = 2, verbose = FALSE) summ <- summary(mix) summ$componentsset.seed(1) samples <- list( group1 = matrix(rnorm(100, 0.0, 0.5), ncol = 1), group2 = matrix(rnorm(100, 0.5, 0.5), ncol = 1) ) mix <- fit_mixture(samples, K_max = 2, verbose = FALSE) summ <- summary(mix) summ$components
Computes comprehensive summary statistics for hyperparameters (mu and tau) and theta parameters from prior predictive samples.
## S3 method for class 'shrinkr_prior_pred' summary(object, probs = c(0.025, 0.5, 0.975), ...)## S3 method for class 'shrinkr_prior_pred' summary(object, probs = c(0.025, 0.5, 0.975), ...)
object |
A |
probs |
Numeric vector of quantiles to compute. Default is c(0.025, 0.5, 0.975) for 95% credible intervals. |
... |
Additional arguments (currently unused). |
A list with class "summary.shrinkr_prior_pred" containing:
hyperparameters |
Data frame with summary statistics for mu and tau |
theta |
Data frame with summary statistics for each group's theta |
Each data frame includes columns for mean, sd, and the requested quantiles.
sample_prior_predictive for generating samples,
print.shrinkr_prior_pred for quick overview
priors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_normal(0, 1), lower = 0) ) prior_pred <- sample_prior_predictive(priors, n_groups = 3, n_draws = 50) summ <- summary(prior_pred) summ$thetapriors <- list( mu = distributional::dist_normal(0, 5), tau = distributional::dist_truncated(distributional::dist_normal(0, 1), lower = 0) ) prior_pred <- sample_prior_predictive(priors, n_groups = 3, n_draws = 50) summ <- summary(prior_pred) summ$theta
Computes posterior draws for linear combinations of subgroup effects. Useful for pairwise contrasts (e.g., treatment vs control), weighted averages, or any custom linear estimand involving theta parameters.
theta_contrasts(fit, contrast_matrix, labels = NULL)theta_contrasts(fit, contrast_matrix, labels = NULL)
fit |
A |
contrast_matrix |
A numeric matrix L with
|
labels |
Optional character vector of length M to name the contrasts.
If |
A posterior::draws_df with columns .chain, .iteration, .draw,
and one column per contrast.
shrink() for fitting models,
summarise_theta() for basic theta summaries
set.seed(1) draws <- data.frame( mu = rnorm(20, 0.2, 0.05), tau = abs(rnorm(20, 0.3, 0.03)), `theta[1]` = rnorm(20, 0.0, 0.1), `theta[2]` = rnorm(20, 0.3, 0.1), `theta[3]` = rnorm(20, 0.5, 0.1), check.names = FALSE ) draws$tau_squared <- draws$tau^2 fit <- list( fit = posterior::as_draws_df(draws), data = list( G = 3, K = 1, centered = FALSE, vars = c("group1", "group2", "group3"), quantiles = data.frame( q2.5 = c(-0.20, 0.10, 0.30), q50 = c(0.00, 0.30, 0.50), q97.5 = c(0.20, 0.50, 0.70) ) ), summary = posterior::summarise_draws( posterior::as_draws_df(draws), "mean", "sd", ~posterior::quantile2(., probs = c(0.025, 0.5, 0.975)) ), diagnostics = list(n_divergent = 0, max_treedepth = 0, n_leapfrog = 0) ) class(fit) <- "shrinkr_fit" L <- matrix(c(-1, 1, 0), nrow = 1) contrast <- theta_contrasts(fit, L, labels = "group2_vs_group1") posterior::summarise_draws(contrast)set.seed(1) draws <- data.frame( mu = rnorm(20, 0.2, 0.05), tau = abs(rnorm(20, 0.3, 0.03)), `theta[1]` = rnorm(20, 0.0, 0.1), `theta[2]` = rnorm(20, 0.3, 0.1), `theta[3]` = rnorm(20, 0.5, 0.1), check.names = FALSE ) draws$tau_squared <- draws$tau^2 fit <- list( fit = posterior::as_draws_df(draws), data = list( G = 3, K = 1, centered = FALSE, vars = c("group1", "group2", "group3"), quantiles = data.frame( q2.5 = c(-0.20, 0.10, 0.30), q50 = c(0.00, 0.30, 0.50), q97.5 = c(0.20, 0.50, 0.70) ) ), summary = posterior::summarise_draws( posterior::as_draws_df(draws), "mean", "sd", ~posterior::quantile2(., probs = c(0.025, 0.5, 0.975)) ), diagnostics = list(n_divergent = 0, max_treedepth = 0, n_leapfrog = 0) ) class(fit) <- "shrinkr_fit" L <- matrix(c(-1, 1, 0), nrow = 1) contrast <- theta_contrasts(fit, L, labels = "group2_vs_group1") posterior::summarise_draws(contrast)