Lecture 2

inlabru workflow

Sara Martino

Dept. of Mathematical Science, NTNU

Janine Illian

University of Glasgow

Jafet Belmont

University of Glasgow

Fitting a LGM with inlabru

The general workflow:

# Define model components
comps <- component_1(...) +
  component_2(...) + 
  ...

# Define the model predictor
pred <- linear_function(component_1,
                            component_2, ...)

# Build the observation model
lik <- bru_obs(formula = pred,
               family = ... ,
               data = ... ,
                ...)

# Fit the model
fit <- bru(comps, lik, ...)

Fitting a LGM with inlabru

The general workflow:

# Define model components
comps <- component_1(...) +
  component_2(...) + 
  ...

# Define the model predictor
pred <- linear_function(component_1,
                            component_2, ...)

# Build the observation model
lik <- bru_obs(formula = pred,
               family = ... ,
               data = ... ,
                ...)

# Fit the model
fit <- bru(comps, lik, ...)

Basic component features

Basic component features

The basic syntax for components is:

~ my_component_name(
  main = ...,
  model = ...
)
  • my_component_name: this is a user-chosen label for the model component. This is then used as input in predict() and generate().
  • main: here we define the input data for the component.
  • model: The type of model component see ?component, and ?INLA::inla.list.models()$latent.

Examples

  • beta_0(1) or Intercept(1) define one intercept.
  • cov_effect(altitude, model= "linear") defines the linear effect of altitude on the predictor.
  • time_effect(time, model= "rw2") defines the smooth effect of time on the predictor.

Shortcuts

Some inlabru shortcuts

In the slides we have fitted the model as:

cmp = ~ -1 + beta0(1) beta1(covariate, model = "linear")
formula = y ~ beta0 + beta1
lik = bru_obs(formula = formula,
              famuly  = "gaussian",
              data = df)
fit = bry(cmp, lik)

but in the practical you have

cmp = ~ -1 + beta0(1) beta1(covariate, model = "linear")

lik = bru_obs(formula = y~.,
              famuly  = "gaussian",
              data = df)
fit = bry(cmp, lik)

Some inlabru shortcuts

In the slides we have fitted the model as:

cmp = ~ -1 + beta0(1) beta1(covariate, model = "linear")
formula = y ~ beta0 + beta1
lik = bru_obs(formula = formula,
              famuly  = "gaussian",
              data = df)
fit = bru(cmp, lik)

but in the practical you have

cmp = ~ -1 + beta0(1) beta1(covariate, model = "linear")

lik = bru_obs(formula = y~.,
              famuly  = "gaussian",
              data = df)
fit = bru(cmp, lik)
  1. You don’t have to define a formula outside of the bru_obs() function …it can also be defined inside the function!
lik = bru_obs(formula = y~  beta0 + beta1,
              famuly  = "gaussian",
              data = df)
  1. The expression y ~ . just means “take all the components and sum them together”. It also tells the bru() function that your predictor is linear.

Why do we need the -1 in the formula?

  • inlabru provides a dedicated term, Intercept(), for specifying an intercept that is shared across all data.

  • When this term is omitted, a common intercept is added by default, unless the formula or component explicitly includes -1. This will be come relevant later, when we look at models with multiple likelihoods.

One wrong way and two correct ways of coding

# This is WRONG as we get an intercept too much :-)
cmp = ~ beta0(1) + beta1(covariate, model = "linear") 

lik = bru_obs(formula = y ~ . , data = df)

m1 = bru(cmp, lik)

round(m1$summary.fixed[,c(1,2)],3)
           mean     sd
beta0     0.281 22.361
beta1     1.038  0.333
Intercept 0.281 22.361
# This is correct ...

cmp = ~ Intercept(1) + beta1(covariate, model = "linear")

lik = bru_obs(y~ ., data = df)

m1 = bru(cmp, lik)

round(m1$summary.fixed[,c(1,2)],3)
           mean    sd
Intercept 0.563 0.193
beta1     1.038 0.333
# This is also correct
cmp = ~  -1 + beta0(1) + beta1(covariate, model = "linear")

lik = bru_obs(y~. ,data = df)

m1 = bru(cmp, lik)
round(m1$summary.fixed[,c(1,2)],3)
       mean    sd
beta0 0.563 0.193
beta1 1.038 0.333

Categorical variables and interactions

Effects of categorical variables and Interactions

inlabru has a specific component type for this that is called fixed.

Let’s look at the iris dataset available in R

  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa

Effects of categorical variables in inlabru

We want to fit a model where Species is the only covariate.

  • Species has three categories: setosa, versicolor and virginica.
  • We want to model it as a factor effect.
iris$Species = factor(iris$Species)
m1 = lm(Sepal.Length ~ Species, data = iris)
m1$coef
      (Intercept) Speciesversicolor  Speciesvirginica 
            5.006             0.930             1.582 

Here I. setosa is our reference category!

How do we do this in inlabru?

Effects of categorical variables in inlabru

Option 1: Use the fixed model

# create the model matrix

cmp1 = ~ -1 + spp(~ Species, model = "fixed")

lik1 = bru_obs(formula = Sepal.Length ~.,
               data = iris)

fit1 = bru(cmp1, lik1)

fit1$summary.random$spp[,c(1:3)]
                 ID      mean         sd
1       (Intercept) 5.0059868 0.07268916
2 Speciesversicolor 0.9300083 0.10279799
3  Speciesvirginica 1.5820048 0.10279799

Note

  • spp(~ Species, model = "fixed") is an lm-style model definition! So an intercept is automatically included.
  • The results are stored in the summary.random part of the model, not the summary.fixed.

Effects of categorical variables in inlabru

  • Option 2: Fixed effect are just random effects with fixed precision 😄
cmp2 = ~ -1 +  spp(Species, model = "iid", fixed = T,initial = -6)
# or: cmp2 = ~ Intercept(1) +  spp(Species, model = "iid", fixed = T,initial = -6, constr = T)
lik2 = bru_obs(formula = Sepal.Length ~.,
               data = iris)
fit2 = bru(cmp2, lik2)
fit2$summary.random$spp$mean
[1] 5.005934 5.935922 6.587914

What is happening here??

This is just a re-parametrization problem

c(m1$coef[1],
  
  m1$coef[1] + m1$coef[2],
  
  m1$coef[1] + m1$coef[3])
  • \(\beta_0\): mean sepal length for I. setosa

  • \(\beta_0 + \beta_{0,\text{versicolor}}\) : mean sepal length for for I. versicolor

  • \(\beta_0 + \beta_{0,\text{virginica}}\): mean sepal length for for I. virginica

Effects of categorical variables in inlabru

Alternative (and equivalent) coding options

cmp1 = ~ -1 + spp(~ Species, model = "fixed")     # One reference category
cmp2 = ~ -1 + spp( ~ Species -1, model = "fixed") # No common intercept 
cmp3 = ~ -1 + spp(  Species , model = "iid", fixed = T,initial = -6) # No common intercept 

Note

When using the fixed model, inlabru internally creates a model matrix using the function MatrixModels::model.Matrix(). The syntax

cmp1 = ~ -1 + spp(main = ~ Species, 
                   model = "fixed")     #One reference category

is equivalent to

cmp1 = ~ -1 + spp(main = ~ MatrixModels::model.Matrix(Species, .data.),
                   model = "fixed")     #One reference category

Interactions of linear covariates in inlabru

Here the easiest option is to again use the fixed model type.

Say, we want to fit a model with interactions between (categorical) Species and (continuous) Petal.Length.

m2 = lm(Sepal.Length ~ Species * Petal.Length, data = iris)
m2$coefficients
                   (Intercept)              Speciesversicolor 
                     4.2131682                     -1.8056451 
              Speciesvirginica                   Petal.Length 
                    -3.1535091                      0.5422926 
Speciesversicolor:Petal.Length  Speciesvirginica:Petal.Length 
                     0.2859884                      0.4534460 
cmp = ~ -1 + fixed_effects( ~ ( Species * Petal.Length), model = "fixed")
lik = bru_obs(formula = Sepal.Length ~ .,
              data = iris)
fit = bru(cmp, lik)
fit$summary.random$fixed_effects$mean
[1]  4.2116296 -1.8037483 -3.1512099  0.5433309  0.2848670  0.4522720
fit$summary.random$fixed_effects$sd
[1] 0.4066572 0.5973291 0.6329061 0.2762484 0.2944994 0.2895902

Interactions of linear covariates in inlabru

We can also use the idea that “fixed effects are just random effects with fixed precision” 😄

NOTE: This idea can be very useful in more complex contexts, where the fixed model does not work (for example if one wants to have spatially varying effect of a covariate!)

Let’s look at the interaction between (categorical) Species and (continuous) Petal.Length.

\[ \begin{aligned} \eta_i & = \beta_0 + \beta_{0,\text{Species}_i} + \beta_1x_i + \beta_{1,\text{Species}_i} x_i\\ &\class{fragment}{= \beta^*_{0,\text{Species}_i} + (\beta_1 + \beta_{1,\text{Species}_i}) x_i} \\ & \class{fragment}{= \beta^*_{0,\text{Species}_i} +\beta^*_{1,\text{Species}_i} x_i }\\ & \class{fragment}{=\underbrace{\beta^*_{0,\text{Species}_i}}_{\text{iid}} + \underbrace{\beta^*_{1,\text{Species}_i}}_{\text{iid}} \underbrace{x_i}_{\text{Petal.Length}}} \end{aligned} \]

Interactions of linear covariates in inlabru

The model for the linear predictor is:

cmp = ~ -1 + beta0(Species, model = "iid", initial = -6, fixed = T) +
  beta1(Species, Petal.Length, model = "iid", initial = -6, fixed = T)

lik = bru_obs(formula = Sepal.Length ~ .,
              data = iris)

fit = bru(cmp, lik)

do.call("rbind",fit$summary.random)[,c(1,2)]
                ID      mean
beta0.1     setosa 4.2115909
beta0.2 versicolor 2.4064718
beta0.3  virginica 1.0591448
beta1.1     setosa 0.5433553
beta1.2 versicolor 0.8285246
beta1.3  virginica 0.9958302

Compare this with the lm results

#-1 to remove baseline category
lm(Sepal.Length~ -1 + Petal.Length*Species,iris) %>% coef()
                  Petal.Length                  Speciessetosa 
                     0.5422926                      4.2131682 
             Speciesversicolor               Speciesvirginica 
                     2.4075231                      1.0596591 
Petal.Length:Speciesversicolor  Petal.Length:Speciesvirginica 
                     0.2859884                      0.4534460 

Getting results from the fitted model

The result object

The fitted model is stored in an inlabru object

Let’s

# ask inlabru to compute DIC adn WAIC
bru_options_set(control.compute = list(dic = T, waic = T))

cmp = ~ -1 + 
  spp(Species, model = "iid", initial = -6, fixed = T) +
  petal_length(Petal.Length, model = "linear") +
  petal_width(Petal.Width, model = "linear")


lik = bru_obs(formula =  Sepal.Length ~ .,
              data = iris )


result = bru(cmp, lik)
summary(result)
inlabru version: 2.15.0.9002 
INLA version: 26.08.22 
Latent components:
spp: main = iid(Species)
petal_length: main = linear(Petal.Length)
petal_width: main = linear(Petal.Width)
Observation models:
  Model tag: <No tag>
    Family: 'gaussian'
    Data class: 'data.frame'
    Response class: 'numeric'
    Predictor: Sepal.Length ~ spp + petal_length + petal_width
    Additive/Linear/Rowwise: TRUE/TRUE/TRUE
    Used components: effect[spp, petal_length, petal_width], latent[] 
Time used:
    Pre = 2.97, Running = 0.401, Post = 0.178, Total = 3.54 
Fixed effects:
               mean    sd 0.025quant 0.5quant 0.975quant   mode kld
petal_length  0.906 0.074      0.761    0.906      1.052  0.906   0
petal_width  -0.006 0.156     -0.312   -0.006      0.300 -0.006   0

Random effects:
  Name    Model
    spp IID model

Model hyperparameters:
                                        mean   sd 0.025quant 0.5quant
Precision for the Gaussian observations 8.81 1.03       6.92     8.77
                                        0.975quant mode
Precision for the Gaussian observations      10.94 8.69

Deviance Information Criterion (DIC) ...............: 108.27
Deviance Information Criterion (DIC, saturated) ....: 158.52
Effective number of parameters .....................: 6.01

Watanabe-Akaike information criterion (WAIC) ...: 108.56
Effective number of parameters .................: 6.02

Marginal log-Likelihood:  -86.76 
 is computed 
Posterior summaries for the linear predictor and the fitted values are computed
(Posterior marginals needs also 'control.compute=list(return.marginals.predictor=TRUE)')

Getting results I

Some results are very easy to get as they are contained in the result object:

  • Summaries for fixed effects
result$summary.fixed
                     mean         sd 0.025quant     0.5quant 0.975quant
petal_length  0.906159040 0.07417133  0.7605153  0.906157599  1.0518111
petal_width  -0.005896374 0.15598558 -0.3121987 -0.005897043  0.3004097
                     mode          kld
petal_length  0.906157613 3.799544e-09
petal_width  -0.005897037 3.803449e-09
  • Summaries for random effects
result$summary.random$spp
          ID     mean        sd 0.025quant 0.5quant 0.975quant     mode
1     setosa 3.682625 0.1071961   3.472121 3.682627   3.893116 3.682627
2 versicolor 2.083569 0.2855943   1.522737 2.083576   2.644361 2.083576
3  virginica 1.568942 0.3815775   0.819624 1.568952   2.318206 1.568951
           kld
1 3.798152e-09
2 3.795488e-09
3 3.795355e-09
  • Summaries for hyperparameters
result$summary.hyperpar
                                            mean       sd 0.025quant 0.5quant
Precision for the Gaussian observations 8.811699 1.027758   6.914702 8.771963
                                        0.975quant     mode
Precision for the Gaussian observations   10.93849 8.692133

Getting results I

  • Marginals for fixed effects
result$marginals.fixed$Intercept[1:3,]
NULL
  • Summaries for random effects
result$marginals.random$spp$index.1[1:3,]
            x            y
[1,] 3.214403 0.0004026706
[2,] 3.276436 0.0034576887
[3,] 3.347491 0.0300633269
  • Summaries for hyperparameters
result$marginals.hyperpar$`Precision for the Gaussian observations`[1:3,]
            x            y
[1,] 5.530245 0.0006325368
[2,] 5.642472 0.0010976209
[3,] 5.995541 0.0047232558

inlabru integration with tidy

As of now (version 2.14.1.9005.+) inlabru also provides broom-style tidiers for bru model objects.

  • tidy() — one row per model term (fixed effects or hyperparameters)

  • glance() — one row of model-level fit summaries

  • augment() — original data extended with posterior fitted values

inlabru integration with tidy

As of now (version 2.14.1.9005.+) inlabru also provides broom-style tidiers for bru model objects.

  • tidy() — one row per model term (fixed effects or hyperparameters)

tidy() returns a tibble with one row per fixed-effect term, including the posterior mean, standard deviation, and 95 % credible interval.

tidy(result)
# A tibble: 2 × 5
  term         estimate std.error conf.low conf.high
  <chr>           <dbl>     <dbl>    <dbl>     <dbl>
1 petal_length  0.906      0.0742    0.761     1.05 
2 petal_width  -0.00590    0.156    -0.312     0.300
tidy(result,effects = "hyperpar")
# A tibble: 1 × 5
  term                                    estimate std.error conf.low conf.high
  <chr>                                      <dbl>     <dbl>    <dbl>     <dbl>
1 Precision for the Gaussian observations     8.81      1.03     6.91      10.9

future versions will incorporate summaries for random effects

inlabru integration with tidy

As of now (version 2.14.1.9005.+) inlabru also provides broom-style tidiers for bru model objects.

  • tidy() — one row per model term (fixed effects or hyperparameters)

tidy() returns a tibble with one row per fixed-effect term, including the posterior mean, standard deviation, and 95 % credible interval.

Compatibility with ggplot

Code
tidy(result) |>
  ggplot(aes(x = term, y = estimate, ymin = conf.low, ymax = conf.high)) +
  geom_pointrange() +
  geom_hline(yintercept = 0, linetype = "dashed") +
  coord_flip() +
  labs(title = "Fixed-effect posterior summaries", x = NULL, y = "Estimate")

inlabru integration with tidy

As of now (version 2.14.1.9005.+) inlabru also provides broom-style tidiers for bru model objects.

  • glance() — one row of model-level fit summaries

returns a single-row tibble with the DIC, WAIC, marginal log-likelihood, the number of observations, and total wall-clock time.

glance(result)
# A tibble: 1 × 5
    dic  waic marginal_loglik  nobs elapsed
  <dbl> <dbl>           <dbl> <int>   <dbl>
1  108.  109.           -86.4   150    3.84

Useful for model comparison

cmp2 = ~ -1 + 
  spp(Species, model = "iid", initial = -6, fixed = T) +
  petal_length(Petal.Length, model = "linear") 

lik2 = bru_obs(formula = Sepal.Length ~ .,data = iris)

result2 = bru(cmp2, lik2)

bind_rows(
  glance(result2) %>%  mutate(model = "Species + Petal Length"),
  glance(result) %>% mutate(model = "Species + Petal Length + Petal Width")
) %>%
  select(model, dic, waic, marginal_loglik, nobs)
# A tibble: 2 × 5
  model                                  dic  waic marginal_loglik  nobs
  <chr>                                <dbl> <dbl>           <dbl> <int>
1 Species + Petal Length                106.  106.           -81.1   150
2 Species + Petal Length + Petal Width  108.  109.           -86.4   150

inlabru integration with tidy

As of now (version 2.14.1.9005.+) inlabru also provides broom-style tidiers for bru model objects.

  • augment() — original data extended with posterior fitted values

adds posterior summaries of the linear predictor to a data frame (or a prediction grid as we will see next). Note that you must supply a pred_formula that names what to predict


grid <- expand.grid(Petal.Length = seq(1,6.9,0.1) ,
                 Species = c("setosa","versicolor","virginica"))

augmented <- augment(
  result2,
  data = iris,
  pred_formula = ~ spp + petal_length,
  n_samples = 500L,
  seed = 1L
)
# A tibble: 6 × 9
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species .fitted .fitted_low
         <dbl>       <dbl>        <dbl>       <dbl> <fct>     <dbl>       <dbl>
1          5.1         3.5          1.4         0.2 setosa     4.95        4.86
2          4.9         3            1.4         0.2 setosa     4.95        4.86
3          4.7         3.2          1.3         0.2 setosa     4.86        4.77
4          4.6         3.1          1.5         0.2 setosa     5.04        4.95
5          5           3.6          1.4         0.2 setosa     4.95        4.86
6          5.4         3.9          1.7         0.4 setosa     5.22        5.13
# ℹ 2 more variables: .fitted_high <dbl>, .fitted_sd <dbl>
  • .fitted: posterior mean

  • .fitted_low .fitted_high: 2.5 % and 97.5 % quantiles

  • .fitted_sd: posterior standard deviation.

inlabru integration with tidy

As of now (version 2.14.1.9005.+) inlabru also provides broom-style tidiers for bru model objects.

  • augment() — original data extended with posterior fitted values

adds posterior summaries of the linear predictor to a data frame (or a prediction grid as we will see next). Note that you must supply a pred_formula that names what to predict

augmented <- augment(
  result2,
  data = iris,
  pred_formula = ~ spp + petal_length,
  n_samples = 500L,
  seed = 1L
)

What can you put in the pred_formula?

  • covariate can be accessed as .data$x

  • the effect as x or .effect$x

  • the latent variable as x_latent or .latent$x

  • augment() \(\rightarrow\) predict() \(\rightarrow\) generate()

We can use ggplot to plot the fitted line with credible bands:

Code
ggplot() +
  geom_point(data = iris,
             aes(Petal.Length,
                 Sepal.Length,
                 color=Species),
             alpha = 0.4, size = 0.8) +
  geom_ribbon(
    data = augmented,
    aes(Petal.Length, 
        ymin = .fitted_low, 
        ymax = .fitted_high,
        fill=Species),
   , alpha = 0.3
  ) +
  geom_line(
    data = augmented,
    aes(Petal.Length,
        .fitted,colour=Species),
    , linewidth = 1
  ) +
  labs(
    title = "Posterior fitted line with 95 % CrI",
    x = "Petal Length", y = "Sepal Length"
  ) +
  facet_wrap(~Species,scales="free_x")

predict() and generate() functions

Often, one wants more “complex” results from the model.

For example if we fit the following model to the mtcar data

\[ \eta_i = \beta_{0,\text{Species}_i} + \beta_{1,\text{Species}_i}\text{Petal Length}_i,\ i =1,\dots,n \]

We might want to recover the three regression lines

\[ \beta_{0,\text{Species}_i} + \beta_{1,\text{Species}_i}\text{Petal Length}_i ,\ \text{Species} = 1,2,3 \]

To do this we can use the predict() and generate() functions.

  • predict() simulates from the fitted posterior distribution \(\pi(\mathbf{y}|\mathbf{u},\theta)\), computes what you ask and produces a summary of the samples (mean, sd, quantiles, etc)

  • generate() simulates from the fitted posterior distribution \(\pi(\mathbf{y}|\mathbf{u},\theta)\), computes what you ask and returns the samples!

Example 1

cmp = ~ -1 + fixed_effects(~Species * Petal.Length, model = "fixed")

lik = bru_obs(formula = Sepal.Length ~ .,
              data = iris)

fit = bru(cmp, lik)

pred_grid <- iris %>%
  group_by(Species) %>%
  reframe(Petal.Length = seq(min(Petal.Length), 
                             max(Petal.Length), by = 0.1))

res = predict(fit, pred_grid, ~ fixed_effects)

res[1:5,]
  Species Petal.Length     mean         sd   q0.025     q0.5   q0.975   median
1  setosa          1.0 4.755710 0.14919655 4.492748 4.745633 5.006521 4.745633
2  setosa          1.1 4.810650 0.12061724 4.592047 4.804754 5.025146 4.804754
3  setosa          1.2 4.865590 0.09337071 4.701537 4.866891 5.046524 4.866891
4  setosa          1.3 4.920530 0.06905303 4.798226 4.920336 5.060580 4.920336
5  setosa          1.4 4.975469 0.05195395 4.890673 4.973738 5.089349 4.973738
  mean.mc_std_err sd.mc_std_err
1     0.017311884   0.011961146
2     0.013996808   0.009675420
3     0.010834620   0.007487745
4     0.008003619   0.005491577
5     0.005967543   0.003860738

Example 1

Notice that we predict only within the range of the covariate for each species:

res %>% ggplot() + geom_line(aes(Petal.Length, mean, group = Species, color = Species)) +
  geom_ribbon(aes(Petal.Length, ymin = q0.025 , ymax = q0.975,
                  group = Species, fill = Species), alpha = 0.5)+
  facet_wrap(~Species,scales="free_x")

Example 2

cmp = ~ -1 + beta0(Species, model = "iid", initial = -6, fixed = T) +
  beta1(Species, Petal.Length, model = "iid", initial = -6, fixed = T)


lik = bru_obs(formula = Sepal.Length ~ .,
              data = iris)

fit = bru(cmp, lik)

res = predict(fit, pred_grid, ~ beta0 + beta1)

res[1:5,]
  Species Petal.Length     mean         sd   q0.025     q0.5   q0.975   median
1  setosa          1.0 4.754516 0.14747815 4.492408 4.744297 5.057362 4.744297
2  setosa          1.1 4.808086 0.12008517 4.597748 4.800461 5.057235 4.800461
3  setosa          1.2 4.861657 0.09364703 4.692505 4.854236 5.065953 4.854236
4  setosa          1.3 4.915227 0.06926585 4.794829 4.910235 5.067040 4.910235
5  setosa          1.4 4.968798 0.05004422 4.885144 4.972742 5.078605 4.972742
  mean.mc_std_err sd.mc_std_err
1     0.016772140   0.010121623
2     0.013649102   0.008202926
3     0.010635221   0.006352590
4     0.007857976   0.004656955
5     0.005679451   0.003375142

Example 2

res %>% ggplot() + geom_line(aes(Petal.Length, mean, group = Species, color = Species)) +
  geom_ribbon(aes(Petal.Length, ymin = q0.025 , ymax = q0.975,
                  group = Species, fill = Species), alpha = 0.5)+
  facet_wrap(~Species,scales="free_x")

Yet another example

Let’s fit the model for the Tokyo rainfall data

\[ \begin{aligned} y_t|\eta_t&\sim\text{Bin}(n_t, p_t),\qquad i = 1,\dots,366\\ \eta_t &= \text{logit}(p_t)= \beta_0 + f(\text{time}_t) \end{aligned} \]

data("Tokyo")
cmp= ~ -1 + Intercept(1) + time(time, model ="rw2")
formula = y ~ Intercept + time
lik = bru_obs(formula = formula,
              data = Tokyo,
              Ntrials = n,
              family = "binomial")
fit = bru(cmp, lik)

We now want to extract results…what do we want?

  • The time effect \(f(\text{time}_t)\) ?
  • The linear predictor \(\eta_t = \beta_0 + f(\text{time}_t)\)?
  • The estimated probability offit precipitation \(p_t = \text{inv_logit}(\eta_t)\) ?

We can get all of them with the predict() or generate() functions!

Example - predict()

preds1 = predict(object = fit, newdata = Tokyo, ~ time)
preds2 = predict(object = fit, newdata = Tokyo, ~ Intercept + time)
inv_logit = function(x) ((1 + exp(-x))^(-1))
preds3 = predict(object = fit, newdata = Tokyo, ~ inv_logit(Intercept + time))

or

inv_logit = function(x) ((1 + exp(-x))^(-1))
preds = predict( fit, newdata = Tokyo,
                ~ data.frame(time_eff = time,
                             lin_pred = Intercept + time,
                             probs = inv_logit(Intercept + time)),
                n.samples = 1000
                )
# preds is then a list
round(preds$probs[1:3,],3)
  y n time  mean    sd q0.025  q0.5 q0.975 median mean.mc_std_err sd.mc_std_err
1 0 2    1 0.176 0.083  0.063 0.163  0.369  0.163           0.003         0.003
2 0 2    2 0.174 0.078  0.066 0.161  0.360  0.161           0.003         0.002
3 1 2    3 0.172 0.073  0.068 0.160  0.353  0.160           0.002         0.002

Example - predict()

preds$probs %>% ggplot() + geom_line(aes(time, mean)) +
  geom_ribbon(aes(time, ymin = q0.025, ymax = q0.975), alpha = 0.5)

Example - generate()

samples = generate(fit, newdata =  Tokyo, ~ data.frame(time_eff = time,
                             lin_pred = Intercept + time,
                             probs = inv_logit(Intercept + time)),
               n.samples = 20)


# samples is now a list of length 20 (n.samples) each element of the list looks like:

samples[[1]][1:3,]
    time_eff  lin_pred     probs
1 -0.3753867 -1.720212 0.1518438
2 -0.3621072 -1.706933 0.1535620
3 -0.3508974 -1.695723 0.1550247

Example - generate()

data.frame(time = Tokyo$time, sapply(samples, function(x) x$probs)) %>%
  pivot_longer(-time) %>%
  ggplot() + geom_line(aes(time, value, group = name, color = factor(name))) +
  theme(legend.position = "none")

The _latent suffix

  • Sometimes, one wants to sample directly from latent parameters without specifying any new input data (or, in other words, to sample with an identity projection matrix).

  • The keyword _latent can be appended to a latent component name to retrieve that.

For example, the following code recovers the intercept and the time effect at day 13

p = predict(fit, newdata = c(), ~ data.frame(int = Intercept_latent,
                                                      f_1 = time_latent[13]))

NOTE Here newdata is just an empty object.

Manipulating posterior marginals

Manipulating posterior marginals

We might be interested in functions of the posterior marginals that are computed by the bru() function.

For example, we might want to:

  • compute the mean of a posterior marginal
  • compute the median of a posterior marginal
  • sample from the posterior marginal

All this can be done with the help of the inla.*marginal() family of functions

Example from the Tokyo example

Obtain the posterior marginal for the standard deviation of the random effect, compute its mean and median and sample from it.

post_prec = fit$marginals.hyperpar$`Precision for time`
post_sd = inla.tmarginal(fun = function(x)
                          1/sqrt(x),
                         post_prec)
post_sd_mode = inla.mmarginal(post_sd)
post_sd_mean = inla.emarginal(fun =function(x)x, post_sd )
post_sd_sample = inla.rmarginal(1000, post_sd)
ggplot() + geom_line(data = post_sd, aes(x,y))  +
  geom_histogram(data = data.frame(samples = post_sd_sample),
                 aes(x = samples, y = after_stat(density)),
                 color = "black", fill = "lightblue")+
  geom_vline(xintercept = post_sd_mode, color = "red") +
    geom_vline(xintercept = post_sd_mean, color = "blue")

The inla.*marginal() family

Function Name Usage
inla.dmarginal(x, marginal, ...) Density at a vector of evaluation points \(x\)
inla.pmarginal(q, marginal, ...) Distribution function at a vector of quantiles q
inla.qmarginal(p, marginal, ...) Quantile function at a vector of probabilities p
inla.rmarginal(n, marginal) Generate n random deviates
inla.hpdmarginal(p, marginal, ...) Compute the highest posterior density interval at level p
inla.emarginal(fun, marginal, ...) Compute the expected value assuming transformation given by fun
inla.mmarginal(marginal) Computes the mode
inla.smarginal(marginal, ...) Smoothed density (returns x-values and interpolated y-values)
inla.tmarginal(fun, marginal, ...) Transform the marginal using function fun
inla.zmarginal(marginal) Summary statistics for the marginal

NAs in inlabru

Missing values in inlabru

The bru() function treats missing values in the dataset differently depending on their role in the model.

Take the model definition:

cmp = ~ Intercept(1) + covariate(x, model = "linear") + random(z, model = "iid")
formula = y ~ Intercept + covariate + random
  • NA’s in the response y

    If y[i] = NA, this means that y[i] is not observed, hence gives no contribution to the likelihood.

  • NA’s in fixed effect x

    If x[i] = NA this means that x[i] is not part of the linear predictor for y[i]. For fixed effects, this is equivalent to x[i]=0, hence internally we make this change: x[is.na(x)] = 0

  • NA’s in random effect z

    If z[i] = NA, this means that the random effect does not contribute to the linear predictor for y[i].

Can inlabru deal with missing covariates?

No, inlabru has no way to `impute’ or integrate-out missing covariates.

You have to adjust your model to account for missing covariates.

Sometimes, you can formulate a joint model for the data and the covariates, but this is case-specific.

Getting help while using inlabru

Which priors have I used?

You might wonder which priors have you used in your model..

fit = bru(cmp, lik)

INLA::inla.priors.used(fit)

NB inla.priors.used is a function of the INLA package, so you need to load it explicitly.

Getting help!

The inla.doc() function provides help on the different prior, latent models and likelihood.

inla.doc("ar1")
inla.doc("pc.prior")
inla.doc("gaussian")

Which models are implemented?

Likelihoods

# which likelihoods?
inla.list.models("likelihood")
Section [likelihood]
     0binomial                     New 0-inflated Binomial                 
     0binomialS                    New 0-inflated Binomial Swap            
     0nbinomial                    New 0-inflated nBinomial                
     0nbinomialS                   New 0-inflated nBinomialS               
     0poisson                      New 0-inflated Poisson                  
     0poissonS                     New 0-inflated Poisson Swap             
     1poisson                      New 1-inflated Poisson                  
     1poissonS                     New 1-inflated Poisson Swap             
     agaussian                     The aggregated Gaussian likelihoood     
     bcgaussian                    The Box-Cox Gaussian likelihoood        
     bell                          The Bell likelihood                     
     beta                          The Beta likelihood                     
     betabinomial                  The Beta-Binomial likelihood            
     betabinomialna                The Beta-Binomial Normal approximation likelihood
     bgev                          The blended Generalized Extreme Value likelihood
     binomial                      The Binomial likelihood                 
     binomialmix                   Binomial mixture                        
     cbinomial                     The clustered Binomial likelihood       
     cennbinomial2                 The CenNegBinomial2 likelihood (similar to cenpoisson2)
     cenpoisson                    Then censored Poisson likelihood        
     cenpoisson2                   Then censored Poisson likelihood (version 2)
     circularnormal                The circular Gaussian likelihoood       
     cloglike                      User-defined likelihood                 
     coxph                         Cox-proportional hazard likelihood      
     dgompertzsurv                 destructive gompertz (survival) distribution
     dgp                           Discrete generalized Pareto likelihood  
     egp                           Exteneded Generalized Pareto likelihood 
     exponential                   The Exponential likelihood              
     exponentialsurv               The Exponential likelihood (survival)   
     exppower                      The exponential power likelihoood       
     fl                            The fl likelihood                       
     fmri                          fmri distribution (special nc-chi)      
     fmrisurv                      fmri distribution (special nc-chi)      
     gamma                         The Gamma likelihood                    
     gammacount                    A Gamma generalisation of the Poisson likelihood
     gammacountmean                Another Gamma generalisation of the Poisson likelihood
     gammajw                       A special case of the Gamma likelihood  
     gammajwsurv                   A special case of the Gamma likelihood (survival)
     gammasurv                     The Gamma likelihood (survival)         
     gammasv                       The Gamma likelihood with constant rate 
     gaussian                      The Gaussian likelihoood                
     gaussianjw                    The GaussianJW likelihoood              
     gev                           The Generalized Extreme Value likelihood
     ggaussian                     Generalized Gaussian                    
     ggaussianS                    Generalized GaussianS                   
     gompertz                      gompertz distribution                   
     gompertzsurv                  gompertz distribution                   
     gp                            Generalized Pareto likelihood           
     gpoisson                      The generalized Poisson likelihood      
     iidgamma                      (experimental)                          
     iidlogitbeta                  (experimental)                          
     lavm                          Link adjusted von Mises circular distribution
     loggammafrailty               (experimental)                          
     logistic                      The Logistic likelihoood                
     loglogistic                   The loglogistic likelihood              
     loglogisticsurv               The loglogistic likelihood (survival)   
     lognormal                     The log-Normal likelihood               
     lognormalsurv                 The log-Normal likelihood (survival)    
     logperiodogram                Likelihood for the log-periodogram      
     mgamma                        The modal Gamma likelihood              
     mgammasurv                    The modal Gamma likelihood (survival)   
     nbinomial                     The negBinomial likelihood              
     nbinomial2                    The negBinomial2 likelihood             
     nmix                          Binomial-Poisson mixture                
     nmixnb                        NegBinomial-Poisson mixture             
     npoisson                      The Normal approximation to the Poisson likelihood
     nvm                           Normal approx of the von Mises circular distribution
     nzpoisson                     The nzPoisson likelihood                
     obeta                         The ordered Beta likelihood             
     occupancy                     Occupancy likelihood                    
     poisson                       The Poisson likelihood                  
     poisson.special1              The Poisson.special1 likelihood         
     pom                           Likelihood for the proportional odds model
     qkumar                        A quantile version of the Kumar likelihood
     qloglogistic                  A quantile loglogistic likelihood       
     qloglogisticsurv              A quantile loglogistic likelihood (survival)
     rcpoisson                     Randomly censored Poisson               
     sem                           The SEM likelihoood                     
     simplex                       The simplex likelihood                  
     sn                            The Skew-Normal likelihoood             
     stdgaussian                   The stdGaussian likelihoood             
     stochvol                      The Gaussian stochvol likelihood        
     stochvolln                    The Log-Normal stochvol likelihood      
     stochvolnig                   The Normal inverse Gaussian stochvol likelihood
     stochvolsn                    The SkewNormal stochvol likelihood      
     stochvolt                     The Student-t stochvol likelihood       
     t                             Student-t likelihood                    
     tpoisson                      Thinned Poisson                         
     tstrata                       A stratified version of the Student-t likelihood
     tweedie                       Tweedie distribution                    
     vm                            von Mises circular distribution         
     weibull                       The Weibull likelihood                  
     weibullsurv                   The Weibull likelihood (survival)       
     wrappedcauchy                 The wrapped Cauchy likelihoood          
     xbinomial                     The Binomial likelihood (experimental version)
     xpoisson                      The Poisson likelihood (expert version) 
     zeroinflatedbetabinomial0     Zero-inflated Beta-Binomial, type 0     
     zeroinflatedbetabinomial1     Zero-inflated Beta-Binomial, type 1     
     zeroinflatedbetabinomial2     Zero inflated Beta-Binomial, type 2     
     zeroinflatedbinomial0         Zero-inflated Binomial, type 0          
     zeroinflatedbinomial1         Zero-inflated Binomial, type 1          
     zeroinflatedbinomial2         Zero-inflated Binomial, type 2          
     zeroinflatedcenpoisson0       Zero-inflated censored Poisson, type 0  
     zeroinflatedcenpoisson1       Zero-inflated censored Poisson, type 1  
     zeroinflatednbinomial0        Zero inflated negBinomial, type 0       
     zeroinflatednbinomial1        Zero inflated negBinomial, type 1       
     zeroinflatednbinomial1strata2 Zero inflated negBinomial, type 1, strata 2
     zeroinflatednbinomial1strata3 Zero inflated negBinomial, type 1, strata 3
     zeroinflatednbinomial2        Zero inflated negBinomial, type 2       
     zeroinflatedpoisson0          Zero-inflated Poisson, type 0           
     zeroinflatedpoisson1          Zero-inflated Poisson, type 1           
     zeroinflatedpoisson2          Zero-inflated Poisson, type 2           
     zeroninflatedbinomial2        Zero and N inflated binomial, type 2    
     zeroninflatedbinomial3        Zero and N inflated binomial, type 3    

Which models are implemented?

Components

# which latent models? (components)
inla.list.models("latent")
Section [latent]
     2diid                         (This model is obsolute)                
     ar                            Auto-regressive model of order p (AR(p))
     ar1                           Auto-regressive model of order 1 (AR(1))
     ar1c                          Auto-regressive model of order 1 w/covariates
     besag                         The Besag area model (CAR-model)        
     besag2                        The shared Besag model                  
     besagproper                   A proper version of the Besag model     
     besagproper2                  An alternative proper version of the Besag model
     bym                           The BYM-model (Besag-York-Mollier model)
     bym2                          The BYM-model with the PC priors        
     cgeneric                      Generic latent model specified using C  
     clinear                       Constrained linear effect               
     copy                          Create a copy of a model component      
     crw2                          Exact solution to the random walk of order 2
     dmatern                       Dense Matern field                      
     fgn                           Fractional Gaussian noise model         
     fgn2                          Fractional Gaussian noise model (alt 2) 
     generic                       A generic model                         
     generic0                      A generic model (type 0)                
     generic1                      A generic model (type 1)                
     generic2                      A generic model (type 2)                
     generic3                      A generic model (type 3)                
     iid                           Gaussian random effects in dim=1        
     iid1d                         Gaussian random effect in dim=1 with Wishart prior
     iid2d                         Gaussian random effect in dim=2 with Wishart prior
     iid3d                         Gaussian random effect in dim=3 with Wishart prior
     iid4d                         Gaussian random effect in dim=4 with Wishart prior
     iid5d                         Gaussian random effect in dim=5 with Wishart prior
     iidkd                         Gaussian random effect in dim=k with Wishart prior
     intslope                      Intecept-slope model with Wishart-prior 
     linear                        Alternative interface to an fixed effect
     log1exp                       A nonlinear model of a covariate        
     logdist                       A nonlinear model of a covariate        
     matern2d                      Matern covariance function on a regular grid
     meb                           Berkson measurement error model         
     mec                           Classical measurement error model       
     ou                            The Ornstein-Uhlenbeck process          
     prw2                          Proper random walk of order 2           
     revsigm                       Reverse sigmoidal effect of a covariate 
     rgeneric                      Generic latent model specified using R  
     rw1                           Random walk of order 1                  
     rw2                           Random walk of order 2                  
     rw2d                          Thin-plate spline model                 
     rw2diid                       Thin-plate spline with iid noise        
     scopy                         Create a scopy of a model component     
     seasonal                      Seasonal model for time series          
     sigm                          Sigmoidal effect of a covariate         
     slm                           Spatial lag model                       
     spde                          A SPDE model                            
     spde2                         A SPDE2 model                           
     spde3                         A SPDE3 model                           
     z                             The z-model in a classical mixed model formulation

Which models are implemented?

Priors

# which priors?
inla.list.models("prior")
Section [prior]
     betacorrelation               Beta prior for the correlation          
     dirichlet                     Dirichlet prior                         
     expression:                   A generic prior defined using expressions
     flat                          A constant prior                        
     gamma                         Gamma prior                             
     gaussian                      Gaussian prior                          
     invalid                       Void prior                              
     jeffreystdf                   Jeffreys prior for the doc              
     laplace                       Laplace prior                           
     linksnintercept               Skew-normal-link intercept-prior        
     logflat                       A constant prior for log(theta)         
     loggamma                      Log-Gamma prior                         
     logiflat                      A constant prior for log(1/theta)       
     logitbeta                     Logit prior for a probability           
     logtgaussian                  Truncated Gaussian prior                
     logtnormal                    Truncated Normal prior                  
     minuslogsqrtruncnormal        (obsolete)                              
     mvnorm                        A multivariate Normal prior             
     none                          No prior                                
     normal                        Normal prior                            
     pc                            Generic PC prior                        
     pc.alphaw                     PC prior for alpha in Weibull           
     pc.ar                         PC prior for the AR(p) model            
     pc.cor0                       PC prior correlation, basemodel cor=0   
     pc.cor1                       PC prior correlation, basemodel cor=1   
     pc.dof                        PC prior for log(dof-2)                 
     pc.egptail                    PC prior for the tail in the EGP likelihood
     pc.fgnh                       PC prior for the Hurst parameter in FGN 
     pc.gamma                      PC prior for a Gamma parameter          
     pc.gammacount                 PC prior for the GammaCount likelihood  
     pc.gevtail                    PC prior for the tail in the GEV likelihood
     pc.matern                     PC prior for the Matern SPDE            
     pc.mgamma                     PC prior for a Gamma parameter          
     pc.prec                       PC prior for log(precision)             
     pc.prw2.range                 PCprior for the range in PRW2           
     pc.range                      PC prior for the range in the Matern SPDE
     pc.sn                         PC prior for the skew-normal            
     pc.spde.GA                    (experimental)                          
     pom                           #classes-dependent prior for the POM model
     ref.ar                        Reference prior for the AR(p) model, p<=3
     rprior:                       A R-function defining the prior         
     table:                        A generic tabulated prior               
     wishart1d                     Wishart prior dim=1                     
     wishart2d                     Wishart prior dim=2                     
     wishart3d                     Wishart prior dim=3                     
     wishart4d                     Wishart prior dim=4                     
     wishart5d                     Wishart prior dim=5                     
     wishartkd                     Wishart prior                           

Take home message

Take home message

  • Linear models with interactions

    • inlabru has a special model to implement this

    • but it is also worth to understand that “fixed effects are just random effects with fixed precision 😄

    • inlabru integrates with widely used broom-style tidiers (more features might be addedd soon)

  • predict() and generate() functions are powerful tools (based on sampling from the posterior distribution) to obtain many interesting results!

  • missing values are usually not a problem but in some cases have to be treated carefully.