--- title: "Bayesian model evaluation" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Bayesian model evaluation} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} bibliography: ../inst/REFERENCES.bib link-citations: true --- ```{r, include=FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 4, fig.align = "center" ) ``` This vignette describes how to compare competing model specifications. **RprobitB** provides three criteria for this purpose: the widely applicable information criterion (WAIC), Pareto-smoothed importance sampling leave-one-out cross-validation (PSIS-LOO), and Bayes factors. WAIC and PSIS-LOO estimate the expected predictive accuracy of a model for new data from the pointwise log-likelihood of the posterior draws [@Watanabe2010; @Vehtari2017]. A Bayes factor is the ratio of the marginal likelihoods of two models, that is, of the likelihood averaged over the prior of each model [@Kass1995]. In panel data, the pointwise log-likelihood is evaluated per decider, so WAIC and PSIS-LOO estimate the accuracy of predicting the choices of new deciders. The examples use data sets of the **AER** package [@Kleiber2008], the **mlogit** package [@Croissant2020], and the **MASS** package [@VenablesRipley2002]. The vignette [Get started with RprobitB][v01] explains how to fit and read a model, and the vignettes [Model specification and variants][v02] and [Modeling preference heterogeneity][v03] cover the specifications compared here. ```{r setup} library(RprobitB) set.seed(1) ``` ## A nested model comparison for travel mode choices The `TravelMode` data of the **AER** package record which of four modes 210 travelers between Sydney and Melbourne had taken: air, train, bus, or car. The vignette [Model specification and variants][v02] fits a model in which terminal waiting time, in-vehicle cost, and travel time vary across modes, while household income and the size of the traveling party shift the utilities of the modes relative to air, the base alternative. Does income change the mode choice beyond cost and time? The reduced model below omits the two traveler characteristics and the alternative-specific constants. `update()` rebuilds the call of the full model with the formula changed part by part: `. ~ wait + vcost + travel | 0` keeps the first part and empties the second. ```{r fit} data("TravelMode", package = "AER") TravelMode$choice <- TravelMode$choice == "yes" TravelMode$vcost <- TravelMode$vcost / 1.6196 TravelMode$income <- TravelMode$income / 1.6196 full_model <- fit( choice ~ wait + vcost + travel | income + size, data = TravelMode, format = "long", column_decider = "individual", column_alternative = "mode", iterations = 6000, warmup = 3000, thin = 30, chains = 2, progress = FALSE ) reduced_model <- update(full_model, . ~ wait + vcost + travel | 0) ``` `logLik()` evaluates the log-likelihood at the posterior means of the parameters. Its `df` attribute counts the free parameters, without the error variance that is fixed to identify the utility scale, and its `nobs` attribute counts the independent likelihood units, here the `r nobs(full_model)` travelers with one choice each. ```{r loglik} logLik(full_model) logLik(reduced_model) ``` The log-likelihood values can be used to compute AIC and BIC, but it ignores the posterior uncertainty about the parameters. WAIC and PSIS-LOO instead use all posterior draws and are the primary criteria. ## WAIC and PSIS-LOO `WAIC()` and `loo()` return objects of the **loo** package [@Vehtari2026]. Both report the expected log predictive density `elpd`, an effective number of parameters, and the criterion on the deviance scale. Lower `waic` and `looic`, or equivalently higher `elpd`, mean better predictive accuracy. @Watanabe2010 introduced WAIC and showed that it asymptotically approximates Bayesian cross-validation; @Vehtari2017 and @Vehtari2024 developed the PSIS-LOO approximation and its diagnostics. ```{r waic} WAIC(full_model) WAIC(reduced_model) ``` The **loo** package warns when the contribution of a decider to `p_waic` exceeds 0.4, the level above which @Vehtari2017 consider the WAIC approximation unreliable; here this concerns a few travelers. PSIS-LOO is preferable in this situation, because it comes with a diagnostic per traveler: a Pareto-k value below the printed threshold means that the importance sampling for that traveler is reliable, and larger values usually belong to travelers whose choices have low probability under the model [@Vehtari2024]. ```{r loo} loo_full <- loo(full_model) loo_reduced <- loo(reduced_model) loo_full ``` The **loo** package plots the Pareto-k values per traveler. Points above the dashed line mark the travelers whose choices are hardest to predict from the choices of the other travelers. ```{r loo-plot} plot(loo_full) ``` `loo::loo_compare()` ranks the models by `elpd` and reports the difference to the best model with its standard error. ```{r compare} loo::loo_compare(loo_full, loo_reduced) ``` The models are named in the order of the arguments, so `model1` is the full model. It ranks first, and the reduced model falls short by several standard errors of the difference: income and party size improve the prediction of the mode choice. ## Bayes factors `bayes_factor()` estimates the marginal likelihood of each model with the **bridgesampling** package [@Gronau2020; @Meng1996] and returns their ratio; values above one favor the first model. ```{r bf} set.seed(1) bayes_factor(full_model, reduced_model, log = TRUE) ``` The large positive log Bayes factor also favors the full model. ## Models with random coefficients Does a random price coefficient improve the train model of the vignette [Get started with RprobitB][v01]? The fixed model is fitted first, on the first 100 travelers, and `update()` gives the price coefficient a normal random effect, as in the vignette [Posterior prediction][v04]. ```{r train} data("Train", package = "mlogit") Train$price_A <- Train$price_A / 100 / 2.20371 Train$price_B <- Train$price_B / 100 / 2.20371 Train$time_A <- Train$time_A / 60 Train$time_B <- Train$time_B / 60 train_small <- Train[Train$id %in% unique(Train$id)[1:100], ] train_fixed <- fit( choice ~ price + time + change + factor(comfort) | 0, data = train_small, column_decider = "id", column_occasion = "choiceid", iterations = 2000, warmup = 1000, thin = 20, chains = 2, progress = FALSE ) train_random <- update(train_fixed, random_effects = c(price = "n")) loo_fixed <- loo(train_fixed, progress = FALSE) loo_random <- loo(train_random, progress = FALSE) loo::loo_compare(loo_fixed, loo_random) ``` The model with the random price coefficient, `model2`, ranks first, and the fixed model falls short by several standard errors of the difference. Letting the price sensitivity vary between travelers thus improves the prediction of a traveler's choices. ## Ordered and ranked responses The criteria are not specific to unordered choices. The ordered model of the vignette [Model specification and variants][v02] asked whether older students smoke less; the comparison below asks whether the exercise dummies improve the prediction. ```{r ordered-comparison} data("survey", package = "MASS") smoking_full <- fit( Smoke ~ Age + Exer | 0, data = survey, alternatives = c("Never", "Occas", "Regul", "Heavy"), choice_type = "ordered", column_decider = NULL, chains = 1 ) smoking_age <- update(smoking_full, . ~ Age | 0) loo::loo_compare( loo(smoking_full, progress = FALSE), loo(smoking_age, progress = FALSE) ) ``` The difference is smaller than its standard error, so the exercise dummies appear to not improve the prediction of how much a student smokes. ## Further reading The vignette [Posterior prediction][v04] computes choice probabilities and marginal effects from a fitted model, and the vignette [Modeling preference heterogeneity][v03] describes the random coefficient and latent class specifications that the criteria above can compare. [v01]: https://loelschlaeger.de/RprobitB/articles/v01_get_started.html [v02]: https://loelschlaeger.de/RprobitB/articles/v02_model_variants.html [v03]: https://loelschlaeger.de/RprobitB/articles/v03_heterogeneity.html [v04]: https://loelschlaeger.de/RprobitB/articles/v04_prediction.html ## References