glmbayes_bayestestR_prior_methods: bayestestR Prior-Checking Methods for glmb/lmb Model Objects

glmbayes_bayestestR_prior_methodsR Documentation

bayestestR Prior-Checking Methods for glmb/lmb Model Objects

Description

Methods implementing three of bayestestR's prior-related generics for objects of class "glmb" (which includes lmb, rglmb, rlmb, and rGamma_reg fits, since these all inherit "glmb" in their class vector).

simulate_prior.glmb() delegates to the pfun stored in x$pfamily (see pfamily and prior_simfuncs), drawing n independent samples directly from the actual prior specification in prior_list, rather than reconstructing an approximation glmbayes_insight_methods's get_priors.glmb() flattened Parameter/Distribution/Location/Scale table. This matters when the coefficient prior is a genuine multivariate normal (dNormal, dNormal_Gamma, dIndependent_Normal_Gamma) with a non-diagonal covariance matrix Sigma: the flattened table can only report each parameter's marginal mean/SD, but simulate_prior.glmb() draws from the true joint N(\mu, \Sigma) (via a Cholesky factor of the complete Sigma), preserving any correlation between coefficients. dBeta/dGamma priors are drawn from their exact Beta/Gamma form rather than their Normal-moment surrogate. dGamma with Inv_Dispersion = TRUE is a special case: that prior is on the inverse dispersion (precision) only – beta is a fixed, known input, not a modeled quantity – so simulate_prior.glmb() returns only simulated dispersion draws for it, with no coefficient columns at all (mirroring glmbayes_insight_methods's get_parameters.glmb() treatment of the posterior side).

dNormal_Gamma and dIndependent_Normal_Gamma both place priors on both the coefficients (joint normal) and the dispersion (inverse-gamma), and simulate_prior.glmb() simulates both parts for either. For dIndependent_Normal_Gamma, however, the dispersion prior is two-sided truncated to x$pfamily$prior_list$disp_lower/disp_upper – bounds that rindepNormalGamma_reg (and rglmb/ rlmb/glmb/lmb, which call it) always compute and write back into the fitted object's pfamily even when the user leaves disp_lower/disp_upper at their default NULL at prior-specification time, because the accept-reject envelope requires a bounded dispersion domain to construct (lack of conjugacy between the independent coefficient and precision priors rules out the closed-form, unbounded posterior available to dNormal_Gamma). simulate_prior.glmb() draws from this same truncated Inverse-Gamma via the exact inverse-CDF method ‘src/invgamma_ct.cpp’ uses internally, so it matches what the fit actually assumed rather than the untruncated Inverse-Gamma(shape, rate). dNormal_Gamma's dispersion prior has no truncation concept at all (its prior_list has no disp_lower/disp_upper fields; it is fully conjugate), and dGamma's truncation is opt-in only (via explicit disp_lower/disp_upper arguments at construction; the default NULL is never overwritten after fitting) – both are handled by the same helper, which falls back to the plain untruncated Inverse-Gamma whenever disp_lower/disp_upper are NULL.

check_prior.glmb() compares those prior draws against the fit's posterior draws (get_parameters), one parameter at a time, using the same "gelman" (posterior SD vs. prior SD ratio) and "lakeland" (fraction of posterior mass inside the prior's 95\ rules bayestestR uses for other model classes – reimplemented locally so glmbayes does not depend on bayestestR's unexported internal helpers. Because both rules only ever compare one parameter's prior draws to that same parameter's posterior draws, the joint/marginal distinction above never changes check_prior()'s verdicts; it only matters if you use simulate_prior()'s draws directly (e.g. for prior-predictive visualization).

describe_prior.glmb() does not route through get_priors()'s flattened, marginal-only table (unlike bayestestR's own describe_prior.stanreg(), which is a thin wrapper around get_priors). Instead it returns pfamily(model) directly, so it prints the exact same Call / Prior Family / Prior List report as pfamily(model) (via the package's existing print.pfamily() method) – including the complete covariance matrix for a multivariate normal coefficient prior, not just its diagonal.

Usage

## S3 method for class 'glmb'
simulate_prior(model, n = 1000, ...)

## S3 method for class 'glmb'
check_prior(model, method = "gelman", simulate_priors = TRUE, ...)

## S3 method for class 'glmb'
describe_prior(model, parameters = NULL, ...)

Arguments

model

An object of class "glmb".

n

Number of prior draws to simulate.

...

Not used; included for S3 signature compatibility with the bayestestR generics.

method

Either "gelman" or "lakeland"; see check_prior for the general rule definitions.

simulate_priors

Ignored (prior draws are always simulated via simulate_prior.glmb()); included for signature compatibility with check_prior. glmbayes fits have no unupdate()-style refit mechanism (unlike stanreg/brmsfit), so simulate_priors = FALSE is not supported.

parameters

Not used; included for signature compatibility with describe_prior.

Value

simulate_prior.glmb() returns a data.frame with n rows and one column per parameter (matching get_parameters's shape).

check_prior.glmb() returns a data.frame with columns Parameter and Prior_Quality.

describe_prior.glmb() returns the fit's "pfamily" object (see pfamily).

See Also

glmbayes_insight_methods, pfamily, prior_simfuncs; simulate_prior, check_prior, describe_prior.

Examples

## bayestestR prior-checking methods for glmb/lmb fits (simulate_prior,
## check_prior, describe_prior). 'bayestestR' is a hard dependency (Imports)
## and these generics are re-exported by glmbayes, so no separate
## library(bayestestR) call is needed.

## ----setup: mtcars, a multivariate normal coefficient prior with real data----
## wt and cyl are strongly correlated in mtcars (heavier cars tend to have
## more cylinders), so Prior_Setup()'s data-driven Sigma -- based on
## (X'WX)^-1 -- has a substantial off-diagonal entry between c_wt and c_cyl:
## simulate_prior() draws from this exact joint N(mu, Sigma), not just the
## per-parameter marginals insight's usual get_priors() shape would report
## for other model classes.
##
## sd = c(10, 10, 0.5) gives the intercept and c_wt a deliberately vague
## prior (SD = 10) but c_cyl a tight, informative one (SD = 0.5) centered at
## 0 -- in tension with c_cyl's actual (negative) effect on mpg -- so
## check_prior() below reports a genuine mix of "informative"/"uninformative"
## (gelman) and "informative"/"misinformative" (lakeland) verdicts, rather
## than the same verdict for every coefficient. (A per-coefficient `pwt`
## vector, unlike `sd`, does not survive Prior_Setup()'s Gaussian
## dispersion-calibration step, which recomputes Sigma from (X'WX)^-1 times
## a single scalar dispersion; `sd` is passed straight through instead.)
data(mtcars)
mt <- mtcars
mt$c_wt  <- as.numeric(scale(mtcars$wt, center = TRUE, scale = FALSE))
mt$c_cyl <- as.numeric(scale(mtcars$cyl, center = TRUE, scale = FALSE))
form <- mpg ~ c_wt + c_cyl

ps <- Prior_Setup(form, gaussian(), data = mt, sd = c(10, 10, 0.5), n_prior = 3)

fit <- lmb(
  form,
  dNormal(mu = ps$mu, Sigma = ps$Sigma, dispersion = ps$dispersion),
  data = mt, n = 2000L, verbose = FALSE, use_parallel = FALSE
)

## ----simulate_prior-----------------------------------------------------------
prior_draws <- simulate_prior(fit, n = 5000)
dim(prior_draws)                          ## 5000 draws x 3 coefficients
cor(prior_draws$c_wt, prior_draws$c_cyl)  ## recovers Sigma's off-diagonal correlation

## ----check_prior---------------------------------------------------------------
check_prior(fit)                       ## "gelman" rule (posterior SD vs. prior SD)
check_prior(fit, method = "lakeland")  ## posterior mass inside the prior's 95% HDI

## ----describe_prior-------------------------------------------------------------
## describe_prior() and get_priors() both return pfamily(fit) directly -- the
## same full report (including the complete Sigma, not just its diagonal)
## shown by pfamily(fit) itself.
describe_prior(fit)
identical(describe_prior(fit), pfamily(fit))  ## TRUE
identical(get_priors(fit), pfamily(fit))      ## TRUE

## ----dIndependent_Normal_Gamma: priors on *both* coefficients and dispersion---
## dNormal_Gamma() and dIndependent_Normal_Gamma() both place a prior on the
## coefficients (joint normal) *and* a separate inverse-gamma prior on the
## dispersion, so simulate_prior() below returns both a coefficient block and
## a dispersion column. Unlike dNormal_Gamma() (fully conjugate, no
## truncation), dIndependent_Normal_Gamma()'s independent coefficient/
## precision priors are not jointly conjugate, so its accept-reject sampler
## needs a *bounded* dispersion domain -- the dispersion prior is therefore
## two-sided truncated to [disp_lower, disp_upper] (derived from
## max_disp_perc; here left at its default). simulate_prior() draws from this
## exact *truncated* Inverse-Gamma, not the wider untruncated one.
ps_ing <- Prior_Setup(form, gaussian(), data = mt, n_prior = 5)

fit_ing <- lmb(
  form,
  dIndependent_Normal_Gamma(mu = ps_ing$mu, Sigma = ps_ing$Sigma,
                             shape = ps_ing$shape_ING, rate = ps_ing$rate),
  data = mt, n = 2000L, verbose = FALSE, use_parallel = FALSE
)

## The fit writes the envelope's actual bounds back into pfamily(fit_ing),
## even though disp_lower/disp_upper were left at their default NULL above.
fit_ing$pfamily$prior_list[c("disp_lower", "disp_upper")]

prior_draws_ing <- simulate_prior(fit_ing, n = 5000)
colnames(prior_draws_ing)                 ## coefficients *and* dispersion
range(prior_draws_ing$dispersion)         ## stays within [disp_lower, disp_upper]

check_prior(fit_ing)  ## "dispersion" is checked alongside the coefficients

glmbayes documentation built on Aug. 5, 2026, 1:07 a.m.