| Title: | Deployment, Versioning and Scoring Tools for 'inlabru' Models |
|---|---|
| Description: | Serves Bayesian spatial and latent Gaussian models fit with 'inlabru' as versioned Representational State Transfer (REST) application programming interfaces (APIs). Includes a 'vetiver' bridge (versioning, REST API serving with posterior uncertainty, 'Docker' packaging) for 'bru' objects, a 'parsnip' model constructor scoped to fixed-effects models, and predictive scoring helpers (continuous ranked probability, log, squared-error and Dawid-Sebastiani scores) computed from inlabru::generate() posterior samples via 'scoringRules'. |
| Authors: | Novica Nakov [aut, cre, cph] (ORCID: <https://orcid.org/0009-0005-7773-7718>) |
| Maintainer: | Novica Nakov <[email protected]> |
| License: | GPL (>= 3) |
| Version: | 0.1.2 |
| Built: | 2026-11-03 18:33:41 UTC |
| Source: | https://github.com/cran/inlaops |
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.
bru_cv_predict( formula, family, data, v = 5L, pred_formula, n_samples = 500L, seed = NULL, strata = NULL, ... )bru_cv_predict( formula, family, data, v = 5L, pred_formula, n_samples = 500L, seed = NULL, strata = NULL, ... )
formula |
Model formula passed to |
family |
INLA family string. |
data |
Training data frame. |
v |
Number of folds (default 5). |
pred_formula |
Formula passed to |
n_samples |
Number of posterior samples per fold (default 500). |
seed |
Integer seed passed to |
strata |
Optional name of a column in |
... |
Extra named arguments forwarded to every per-fold
|
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.
A tibble with columns .truth, .pred, .pred_low,
.pred_high, .pred_sd.
set.seed(1) dat <- data.frame(x = rnorm(60)) dat$y <- 1 + 0.5 * dat$x + rnorm(60, sd = 0.5) bru_cv_predict( formula = y ~ Intercept(1) + x, family = "gaussian", data = dat, v = 3, pred_formula = ~ Intercept + x, n_samples = 100, seed = 42 )set.seed(1) dat <- data.frame(x = rnorm(60)) dat$y <- 1 + 0.5 * dat$x + rnorm(60, sd = 0.5) bru_cv_predict( formula = y ~ Intercept(1) + x, family = "gaussian", data = dat, v = 3, pred_formula = ~ Intercept + x, n_samples = 100, seed = 42 )
Scoped to models with fixed effects and IID random intercepts only. Spatial models with BYM2, SPDE, AR1, or LGCP likelihoods should use inlabru's native interface.
bru_reg(mode = "regression", family = "gaussian")bru_reg(mode = "regression", family = "gaussian")
mode |
Model mode. Currently only |
family |
INLA family string, e.g. |
The formula passed to parsnip::fit() must use inlabru component syntax.
An explicit intercept is required: y ~ Intercept(1) + x1 + x2. Standard
y ~ x1 + x2 formulas are not supported because inlabru does not add an
intercept automatically.
IID random intercepts are supported in the fit, but predict() via the
parsnip interface returns the marginal mean — only the fixed effects
are included in the response-scale linear predictor. The IID random
intercept is integrated over rather than conditioned on any specific
group level, which matches the "new group" use case but silently ignores
the random effect for held-out observations from a seen group. If you
need conditional predictions, call inlabru::predict() directly with a
formula that references the IID component.
A bru_reg model spec.
bru_reg(family = "poisson")bru_reg(family = "poisson")
Thin wrapper over scoringRules that takes posterior samples from
inlabru::generate() and returns four predictive scores per observation.
bru_score(fit, newdata, pred_formula, y_col, n_samples = 1000L, seed = NULL)bru_score(fit, newdata, pred_formula, y_col, n_samples = 1000L, seed = NULL)
fit |
A fitted |
newdata |
Data frame of covariate values for held-out observations. |
pred_formula |
Formula passed to |
y_col |
Name of the response column in |
n_samples |
Number of posterior samples (default 1000). |
seed |
Optional non-zero integer. If non- |
pred_formula must produce samples of Y — including observation-model
stochasticity for discrete families. The caller writes the full
distributional expression. Inside an inlabru generate() formula the
predictor is evaluated once per posterior sample: latent-field symbols
(Intercept, SPDE field values, ...) come in as scalars, and covariates
come in as vectors over observations. So length(<covariate>) gives
the observation count for the per-sample r*() call:
Poisson: ~ rpois(length(x), exp(Intercept + x))
Binomial: ~ rbinom(length(x), size = n_trials, prob = plogis(Intercept + x))
Gaussian: ~ rnorm(length(x), mean = Intercept + x, sd = 1 / sqrt(Precision_for_the_Gaussian_observations))
Hyperparameters are available in the formula under their standardised
names (see inlabru::bru_standardise_names()), so the Gaussian
observation noise is sampled jointly with the latent field.
This is the same contract inlabru::generate() already exposes — the
package does not inject observation noise or dispatch on family. Users
who want response-scale samples for a family not listed above write the
appropriate random draw in the formula.
CRPS and the kernel log-score are strictly proper for continuous Y.
For count / binomial Y the empirical CRPS on integer draws is still a
reasonable proper score; scoringRules::logs_sample uses a kernel-density
estimate which can be unstable on discrete supports — treat logs as
approximate in that case.
Dawid-Sebastiani variance is floored at .Machine$double.eps to avoid
division by zero when the sample variance collapses.
A tibble with one row per observation and columns crps, logs,
se, ds.
Gneiting, T. and Raftery, A. E. (2007). Strictly proper scoring rules, prediction, and estimation. Journal of the American Statistical Association, 102(477), 359–378. doi:10.1198/016214506000001437
set.seed(1) dat <- data.frame(x = rnorm(40)) dat$y <- rpois(40, exp(0.5 + 0.3 * dat$x)) fit <- bru_inlaops_fit( y ~ Intercept(1) + x, data = dat[1:30, ], family = "poisson" ) bru_score( fit, newdata = dat[31:40, ], pred_formula = ~ rpois(length(x), exp(Intercept + x)), y_col = "y", n_samples = 200, seed = 1 )set.seed(1) dat <- data.frame(x = rnorm(40)) dat$y <- rpois(40, exp(0.5 + 0.3 * dat$x)) fit <- bru_inlaops_fit( y ~ Intercept(1) + x, data = dat[1:30, ], family = "poisson" ) bru_score( fit, newdata = dat[31:40, ], pred_formula = ~ rpois(length(x), exp(Intercept + x)), y_col = "y", n_samples = 200, seed = 1 )