Skip to contents

The multiple-chain release gives sampling arguments the same meaning across posterior_samples(), fitted_samples(), smooth_samples(), derivative_samples(), their add_*() helpers, and coefficient draw functions. Obsolete arguments now produce errors with migration guidance. Controls must be named; only the model, or the data and model in add_*() helpers, can be passed by position. This prevents old positional calls from changing meaning.

Draw counts and evaluation points

n_draws always means the total retained draws across all chains. It must be divisible by chains. Generating draws requires an explicit count: the previous defaults ranged from one draw to 10,000 draws. chains = NULL uses one chain, or infers the chains from supplied coefficient draws.

Previous argument Replacement
n in fitted, posterior, predicted, smooth and coefficient sampling n_draws
n_sim in derivative sampling n_draws
n in derivative sampling n_grid
n_vals in smooth sampling n_grid
object in derivative sampling model
object in add_*() sampling helpers data
freq frequentist
newdata data
ncores n_cores for MH chains; n_threads for Gaussian draws
n_cores for Gaussian sampling n_threads
term in smooth sampling select

For example, the previous derivative call

# Previous interface; now produces an informative error.
derivative_samples(model, focal = "x", n = 100, n_sim = 1000)

becomes

# 1,000 retained coefficient draws, evaluated at 100 points.
derivative_samples(model, focal = "x", n_draws = 1000, n_grid = 100)

n_grid = 200 is the common default for smooth and derivative sampling. For smooths, it supplies the resolution to smooth_data(); multidimensional smooths can contain more rows than n_grid. Derivative sampling constructs a slice along focal, holding other variables at representative values. Explicit data determine the evaluation locations instead of n_grid. Use explicit data when the exact grid matters. Fitted and response sampling use fitting observations when data = NULL and do not construct a grid.

Multiple chains and parallel work

samples <- fitted_samples(
  model, n_draws = 1000, chains = 4, n_cores = 4,
  method = "mh", burnin = 1000, thin = 1,
  diagnostics = TRUE, seed = 281
)
diagnostics <- sampling_diagnostics(samples)
diagnostics
# These plots describe the coefficient chains used for the fitted samples.
draw(diagnostics, select = 1:2)
draw(diagnostics, type = "rank", select = 1:2)

This retains 250 draws per chain. Every chain discards its own 1,000 burn-in iterations; parallel chains repeat this warmup work. thin = 2 retains every second iteration after burn-in and still returns n_draws draws in total. n_cores limits concurrent MH chains using mirai, capped at chains. An existing worker pool is reused; otherwise temporary workers are cleaned up automatically. Given the same seed and sampler backend, retained draws agree between serial and parallel runs.

Gaussian sampling uses n_threads to control threads inside mvnfast. It does not run concurrent MH chains. A control explicitly supplied to a method that cannot use it produces an error, including MH controls for Gaussian draws or Gaussian covariance controls for MH. block_size and dense_limit apply only to method = "mh", mh_backend = "gratia".

The default MH backend remains "mgcv". The three options are:

mh_backend Evaluation Model support
"mgcv" mgcv::gam.mh() Its existing gam support
"gratia" Compiled likelihoods and MH loop Gaussian identity, Poisson log, binomial logit, Gamma log, and negative binomial log gam and independent-observation bam fits
"family" Compiled MH loop with callbacks to the fitted family Compatible standard, extended, and general mgcv families, including independent-observation bam fits

For example, a multinomial fit can use the family evaluator without a separate compiled multinomial likelihood:

samples <- posterior_samples(
  model, n_draws = 1000, chains = 4, n_cores = 4,
  method = "mh", mh_backend = "family",
  burnin = 1000, diagnostics = TRUE, seed = 281
)

The family backend prepares its full design matrix, fitted smoothing penalty, and proposal factorisation once and reuses them across chains. It calls the fitted family’s dev.resids() and linkinv(), or ll() for multiple predictors, preserving response attributes and coefficient mappings. It retains the full design matrix even for bam: use the gratia backend’s block evaluation when that matrix is too large and its family is supported. Both evaluate bases at the original covariates for discrete bam fits.

The gratia and family evaluators reject GAMM components and AR1 dependence; they do not evaluate fitted observation correlations. They also reject paraPen, H, pre-fit G objects, and singular coefficient covariances. The family backend additionally rejects quasi families, which do not provide a likelihood, and Cox proportional hazards models. All three MH backends condition on fitted smoothing, dispersion, and any family parameters outside the coefficient vector. Parameters represented by coefficients are sampled, including scale or covariance coefficients in general families. unconditional = TRUE applies to Gaussian sampling only.

Reusing coefficient draws

betas <- post_draws(model, n_draws = 1000, chains = 4, seed = 281)
fitted <- fitted_samples(model, method = "user", draws = betas)
smooth <- smooth_samples(model, method = "user", draws = betas)
derivative <- derivative_samples(
  model, focal = "x", method = "user", draws = betas
)

The coefficient matrix determines the count and chain layout. Explicit n_draws or chains must agree with it. A plain matrix without chain metadata represents one chain; chain boundaries are never guessed from the row count. Smooths always transform the same joint coefficient draws. The old rng_per_smooth option is removed because independently redrawing each smooth loses their posterior dependence. The previously ignored mu, sigma, and derivative level arguments are also rejected.

Multiple-chain tables retain .chain, .iteration, and globally unique .draw columns. Single-chain tables keep their previous columns. Attached diagnostics refer to coefficients before transformation or response simulation. as_mcmc_draws() converts coefficient matrices or sampled quantities for posterior or coda diagnostics. Optional packages are required only when their formats or diagnostics are requested.

draw(sampling_diagnostics(x)) uses native gratia plotting code. Trace plots show retained iteration within each chain; type = "rank" compares histogram outlines of ranks pooled across chains, with a reference line for equal counts per bin. Ranks use average ranks for ties and no random jitter. Use select to choose coefficient names or positions. Rank plots require at least two chains. Discarded burn-in is unavailable, and thinning is represented by the retained iteration count. Coefficient matrices provide their own draws; fitted, response, smooth and derivative outputs require diagnostics = TRUE when sampling to retain coefficient draws for these plots. Plotting itself needs neither posterior nor bayesplot. Numerical summaries still use posterior.

Which response sampling function to use

fitted_samples() draws the expected response, smooth_samples() draws individual smooth contributions, and derivative_samples() draws derivatives. posterior_samples() also simulates response variation for each coefficient draw. predicted_samples() simulates responses with fitted parameters held fixed. It uses n_draws for the number of response replicates and rejects coefficient-chain controls; use posterior_samples() to include coefficient uncertainty.

Model-specific capabilities still apply. For example, the native diagnostic samplers for lm and mixed models support Gaussian approximations and fitting observations only, and reject unsupported chain controls. See help("diagnostic_support") for model-specific support. Functions that summarise draws, such as response_derivatives() and conditional_differences(), keep their existing grid and simulation-count arguments; their internal sampling calls use this interface.

Likelihoods and external diagnostic wrappers

log_lik(), loo::loo(), loo::waic() and bayesplot::pp_check() use the same n_draws convention. Likelihood and LOO/WAIC wrappers default to 4,000 draws; bayesplot uses 50 for ordinary checks and 4,000 for leave-one-out plots. Supplied coefficient matrices determine their own counts. Pass chains, diagnostics, method and backend controls directly to log_lik(), or through sampling_args for LOO, WAIC and bayesplot. Likelihood matrices and these diagnostic results retain the coefficient sampling metadata. LOO reads stored chain iterations when estimating relative efficiency, while keeping likelihood and response draws in the same original order. Unlabelled supplied matrices still require explicit chain_id or r_eff for LOO. The old n argument and explicit controls for a different sampler produce errors.

Location-scale-shape models

posterior_samples() now accepts evaluation data for gaulss(), gammals(), gumbls(), gevlss(), shash(), twlss() and ziplss() fits. Supply covariates and formula-offset variables; observed responses are unnecessary. Every predictor uses the same joint coefficient draw. For example:

# Evaluate the first 200 observations, retaining their joint parameter draws.
b <- post_draws(model, n_draws = 1000, chains = 4, seed = 281)
y <- posterior_samples(model, data = evaluation_data[1:200, ],
  method = "user", draws = b, seed = 282)

The functions return different quantities:

Function Quantity for an LSS model
fitted_samples(scale = "response") Expected response, including every distribution parameter that affects it
fitted_samples(scale = "linear_predictor") First linear predictor, for location
posterior_samples() Responses conditional on each joint coefficient draw
predicted_samples() Responses conditional on the fixed fitted coefficients
derivative_samples(scale = "response") Derivative of the expected response, retaining joint coefficient uncertainty
derivative_samples(scale = "linear_predictor") Derivative of the first predictor
smooth_samples() Selected smooth contribution to its own predictor

The historical .parameter = "location" label in fitted samples remains on both scales. On the response scale, .fitted is E[Y]. In particular, Gumbel, GEV and sinh-arcsinh means generally differ from location; the Gamma LSS mean requires exponentiation and the hurdle Poisson mean uses both predictors. These calculations no longer emit the earlier warning about location needing to equal the mean. A GEV mean does not exist at shape >= 1; requesting that mean or its derivative gives an error, while response draws remain available.

gaulss() represents its second response parameter as inverse SD. Sampling uses its reciprocal and divides SD by the square root of an explicit sampling weight. The native gaulss() likelihood ignores fitting weights; default response weights are ones, preserving the fitted likelihood and existing diagnostic rules. The other LSS response generators currently ignore sampling weights, as their mgcv implementations do. Formula offsets are evaluated at supplied covariates; stored fitting offsets are retained with data = NULL. The installed mgcv version rejects offsets when fitting shash() and drops call-level offsets for general-family fits; gratia cannot reconstruct offsets never applied by the fitter. Prefer supported formula offsets.

Grouped response families

posterior_samples() also accepts fitting-data subsets and new covariates for mgcv::gfam() models. Every row must identify its component family, either through the response-index expression in the supplied data or through family_index. Observed response values are not needed. For example:

posterior_samples(grouped_model, data = evaluation_data,
  family_index = component_index, n_draws = 1000, chains = 4, seed = 281)

The same joint coefficient draw is used for every component. Component-specific links, fitted nuisance parameters and formula offsets are retained. New-data sampling weights default to one; explicit weights override them. Output retains .parameter = "component1", "component2", and so on, together with .row, .draw and any chain columns. Missing predictors, membership or sampling weights produce missing responses. Fitting rows excluded by na.exclude are restored. Smooth samples retain their predictor contributions, and response derivatives use each row’s component mean. For derivatives, membership must be recoverable from data; derivative_samples() does not accept family_index. Ordinal response-scale fitted values and their derivatives remain unsupported; response draws and predictor-scale calculations remain available. Censored grouped components require an observation process for posterior response sampling; use simulate() for latent uncensored draws.

MH coefficient sampling rejects BAM fits with nonzero prescribed smooth contributions, such as a nonzero soap-film boundary. Native fitting and prediction can use different offsets for those fits. Supplied coefficient draws can still be evaluated with the native prediction conventions.

Censoring and survival responses

Censored-family generators return latent uncensored responses; posterior predictive checks need a censoring observation process. Cox survival models lack a response generator for this interface, and expected survival times cannot be obtained from a location parameter alone.