Skip to contents

Wraps rsample::vfold_cv() and re-fits the model on each training fold, returning a tidy tibble of holdout predictions. Scoped to models with fixed effects and IID random intercepts only.

Usage

bru_cv_predict(
  formula,
  family,
  data,
  v = 5L,
  pred_formula,
  n_samples = 500L,
  seed = NULL,
  strata = NULL,
  ...
)

Arguments

formula

Model formula passed to inlabru::bru().

family

INLA family string.

data

Training data frame.

v

Number of folds (default 5).

pred_formula

Formula passed to inlabru::predict() for the response scale (e.g. ~ exp(Intercept + x)).

n_samples

Number of posterior samples per fold (default 500).

seed

Integer seed passed to set.seed() before fold assignment so that two identical calls produce identical fold splits. The session RNG state is restored after fold assignment via on.exit. NULL (default) leaves the session RNG state unchanged.

strata

Optional name of a column in data to use for stratified sampling. Passed through to rsample::vfold_cv(). Useful for sparse counts or imbalanced binomial outcomes where random folds can leave a fold with zero events.

...

Extra named arguments forwarded to every per-fold inlabru::bru() call (e.g. options = inlabru::bru_options(...), alternative control.compute settings). config = TRUE is injected unconditionally so per-fold posterior sampling always works.

Value

A tibble with columns .truth, .pred, .pred_low, .pred_high, .pred_sd.

Details

Structured random effects (SPDE, BYM2, AR1, RW1/RW2) cannot be cross-validated by simply subsetting the data. Each requires per-fold reconstruction of the index structure: SPDE models need a new A-matrix (mesh projector) built from the fold's observation coordinates; BYM2 areal models need the adjacency graph to account for areas with no fold observations; AR1/RW models assume a contiguous integer time index that breaks when folds remove time points. None of this can be done generically. For those models use spatial block cross-validation and evaluate with bru_score().

Folds run sequentially. Callers who want parallel folds should compose with their own parallel backend (e.g. future.apply::future_lapply) around a per-fold inlabru::bru() call — this package stays out of the daemon lifecycle to keep the scope focused on bridging, not execution.