loo.mvgam {mvgam} | R Documentation |
LOO information criteria for mvgam
models
Description
Extract the LOOIC (leave-one-out information criterion) using
loo::loo()
Usage
## S3 method for class 'mvgam'
loo(x, incl_dynamics = TRUE, ...)
## S3 method for class 'mvgam'
loo_compare(x, ..., model_names = NULL, incl_dynamics = TRUE)
Arguments
x |
Object of class |
incl_dynamics |
Logical; indicates if any latent dynamic structures that
were included in the model should be considered when calculating in-sample
log-likelihoods. Defaults to |
... |
More |
model_names |
If |
Details
When comparing two (or more) fitted mvgam
models, we can estimate the
difference in their in-sample predictive accuracies using the Expcted Log Predictive
Density (ELPD). This metric can be approximated using Pareto Smoothed Importance Sampling, which
is a method to re-weight posterior draws to approximate what predictions the models might have
made for a given datapoint had that datapoint not been included in the original model fit (i.e.
if we were to run a leave-one-out cross-validation and then made a prediction for the held-out
datapoint). See details from loo::loo()
and loo::loo_compare()
for further information
on how this importance sampling works.
There are two fundamentally different ways to calculate ELPD from mvgam
models that included
dynamic latent processes (i.e. "trend_models"). The first is to use the predictions that were
generated when estimating these latent processes by setting incl_dynamics = TRUE
. This works
in the same way that setting incl_autocor = TRUE
in brms::prepare_predictions()
. But it may
also be desirable to compare predictions by considering that the dynamic processes are nuisance
parameters that we'd wish to account for when making inferences about other processes in the
model (i.e. the linear predictor effects). Setting incl_dynamics = FALSE
will accomplish
this by ignoring the dynamic processes when making predictions. This option matches up with
what mvgam
's prediction functions return (i.e. predict.mvgam
, ppc
,
pp_check.mvgam
, posterior_epred.mvgam
) and will be far less forgiving
of models that may be overfitting the training data due to highly flexible dynamic processes
(such as Random Walks, for example). However setting incl_dynamics = FALSE
will often result
in less stable Pareto k diagnostics for models with dynamic trends, making ELPD comparisons
difficult and unstable. It is therefore recommended to generally stick with
incl_dynamics = TRUE
when comparing models based on in-sample fits, and then to perhaps use
forecast evaluations for further scrutiny of models (see for example forecast.mvgam
,
score.mvgam_forecast
and lfo_cv
)
Value
for loo.mvgam
, an object of class psis_loo
(see loo::loo()
for details). For loo_compare.mvgam
, an object of class compare.loo
(
loo::loo_compare()
for details)
Examples
# Simulate 4 time series with hierarchical seasonality
# and independent AR1 dynamic processes
set.seed(111)
simdat <- sim_mvgam(seasonality = 'hierarchical',
trend_model = AR(),
family = gaussian())
# Fit a model with shared seasonality
mod1 <- mvgam(y ~ s(season, bs = 'cc', k = 6),
data = rbind(simdat$data_train,
simdat$data_test),
family = gaussian(),
chains = 2)
# Inspect the model and calculate LOO
conditional_effects(mod1)
mc.cores.def <- getOption('mc.cores')
options(mc.cores = 1)
loo(mod1)
# Now fit a model with hierarchical seasonality
mod2 <- update(mod1,
formula = y ~ s(season, bs = 'cc', k = 6) +
s(season, series, bs = 'fs',
xt = list(bs = 'cc'), k = 4),
chains = 2)
conditional_effects(mod2)
loo(mod2)
# Now add AR1 dynamic errors to mod2
mod3 <- update(mod2,
trend_model = AR(),
chains = 2)
conditional_effects(mod3)
plot(mod3, type = 'trend')
loo(mod3)
# Compare models using LOO
loo_compare(mod1, mod2, mod3)
options(mc.cores = mc.cores.def)
# Compare forecast abilities using an expanding training window and
# forecasting ahead 1 timepoint from each window; the first window by includes
# the first 92 timepoints (of the 100 that were simulated)
max(mod2$obs_data$time)
lfo_mod2 <- lfo_cv(mod2, min_t = 92)
lfo_mod3 <- lfo_cv(mod3, min_t = 92)
# Take the difference in forecast ELPDs; a model with higher ELPD is preferred,
# so negative values here indicate that mod3 gave better forecasts for a particular
# out of sample timepoint
plot(y = lfo_mod2$elpds - lfo_mod3$elpds,
x = lfo_mod2$eval_timepoints, pch = 16,
ylab = 'ELPD_mod2 - ELPD_mod3',
xlab = 'Evaluation timepoint')
abline(h = 0, lty = 'dashed')