Bayesian GLMM Part5

Author

Murray Logan

Published

09/09/2025

1 Preparations

Load the necessary libraries

library(tidyverse) # for data wrangling
library(car) # for regression diagnostics
library(broom) # for tidy output
library(ggfortify) # for model diagnostics
library(knitr) # for kable
library(emmeans) # for estimating marginal means
library(MASS) # for glm.nb
library(brms)
library(broom.mixed)
library(tidybayes)
library(bayesplot)
library(standist) # for visualizing distributions
library(rstanarm)
library(cmdstanr) # for cmdstan
library(ggeffects)
library(rstan)
library(DHARMa)
library(ggridges)
library(easystats) # framework for stats, modelling and visualisation
library(patchwork)
library(modelsummary)
library(geoR)
source("helperFunctions.R")

2 Scenario

Some ornithologists were interested in the degree of sibling negotiations in owl chicks. Specifically, they wanted to explore how sibling negotiations were affected by feeding satiety and the sex of the parent returning to the nest. The ornithologists had accessed to a number of owl nests and were able to count (via recording equipment) the number of sibling negotiations (calls) that the owl chicks made when the parent returned to the nest.

We could hypothesise that the chicks might call more if they were hungry. As part of the investigation, the researchers were able to provided supplementary food. As such, they were able to manipulate the conditions such that sometimes the chicks in a nest would be considered deprived of supplementary food and at other times they were satiated.

As a parent returned, the researchers recorded the number of sibling negotiations (calls) along with the sex of the parent. Since the number of calls is likely to be a function of the number of chicks (the more chicks the more calls), the researchers also counted the number of siblings in the brood.

Each nest was measured on multiple occasions. Hence, we must include the nest as a random effect to account for the lack of independence between observations on the same set of siblings.

3 Read in the data

owls <- read_csv("../data/owls.csv", trim_ws = TRUE)
Rows: 599 Columns: 7
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Nest, FoodTreatment, SexParent
dbl (4): ArrivalTime, SiblingNegotiation, BroodSize, NegPerChick

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
glimpse(owls)
Rows: 599
Columns: 7
$ Nest               <chr> "AutavauxTV", "AutavauxTV", "AutavauxTV", "Autavaux…
$ FoodTreatment      <chr> "Deprived", "Satiated", "Deprived", "Deprived", "De…
$ SexParent          <chr> "Male", "Male", "Male", "Male", "Male", "Male", "Ma…
$ ArrivalTime        <dbl> 22.25, 22.38, 22.53, 22.56, 22.61, 22.65, 22.76, 22…
$ SiblingNegotiation <dbl> 4, 0, 2, 2, 2, 2, 18, 4, 18, 0, 0, 3, 0, 3, 3, 6, 0…
$ BroodSize          <dbl> 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, …
$ NegPerChick        <dbl> 0.8, 0.0, 0.4, 0.4, 0.4, 0.4, 3.6, 0.8, 3.6, 0.0, 0…
## Explore the first 6 rows of the data
head(owls)
# A tibble: 6 × 7
  Nest       FoodTreatment SexParent ArrivalTime SiblingNegotiation BroodSize
  <chr>      <chr>         <chr>           <dbl>              <dbl>     <dbl>
1 AutavauxTV Deprived      Male             22.2                  4         5
2 AutavauxTV Satiated      Male             22.4                  0         5
3 AutavauxTV Deprived      Male             22.5                  2         5
4 AutavauxTV Deprived      Male             22.6                  2         5
5 AutavauxTV Deprived      Male             22.6                  2         5
6 AutavauxTV Deprived      Male             22.6                  2         5
# ℹ 1 more variable: NegPerChick <dbl>
str(owls)
spc_tbl_ [599 × 7] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ Nest              : chr [1:599] "AutavauxTV" "AutavauxTV" "AutavauxTV" "AutavauxTV" ...
 $ FoodTreatment     : chr [1:599] "Deprived" "Satiated" "Deprived" "Deprived" ...
 $ SexParent         : chr [1:599] "Male" "Male" "Male" "Male" ...
 $ ArrivalTime       : num [1:599] 22.2 22.4 22.5 22.6 22.6 ...
 $ SiblingNegotiation: num [1:599] 4 0 2 2 2 2 18 4 18 0 ...
 $ BroodSize         : num [1:599] 5 5 5 5 5 5 5 5 5 5 ...
 $ NegPerChick       : num [1:599] 0.8 0 0.4 0.4 0.4 0.4 3.6 0.8 3.6 0 ...
 - attr(*, "spec")=
  .. cols(
  ..   Nest = col_character(),
  ..   FoodTreatment = col_character(),
  ..   SexParent = col_character(),
  ..   ArrivalTime = col_double(),
  ..   SiblingNegotiation = col_double(),
  ..   BroodSize = col_double(),
  ..   NegPerChick = col_double()
  .. )
 - attr(*, "problems")=<externalptr> 
owls |> datawizard::data_codebook()
owls (599 rows and 7 variables, 7 shown)

ID | Name               | Type      | Missings |          Values |           N
---+--------------------+-----------+----------+-----------------+------------
1  | Nest               | character | 0 (0.0%) |      AutavauxTV |  28 ( 4.7%)
   |                    |           |          |          Bochet |  23 ( 3.8%)
   |                    |           |          |     Champmartin |  30 ( 5.0%)
   |                    |           |          |         ChEsard |  20 ( 3.3%)
   |                    |           |          |        Chevroux |  10 ( 1.7%)
   |                    |           |          | CorcellesFavres |  12 ( 2.0%)
   |                    |           |          |        Etrabloz |  34 ( 5.7%)
   |                    |           |          |           Forel |   4 ( 0.7%)
   |                    |           |          |          Franex |  26 ( 4.3%)
   |                    |           |          |            GDLV |  10 ( 1.7%)
   |                    |           |          |           (...) |            
---+--------------------+-----------+----------+-----------------+------------
2  | FoodTreatment      | character | 0 (0.0%) |        Deprived | 320 (53.4%)
   |                    |           |          |        Satiated | 279 (46.6%)
---+--------------------+-----------+----------+-----------------+------------
3  | SexParent          | character | 0 (0.0%) |          Female | 245 (40.9%)
   |                    |           |          |            Male | 354 (59.1%)
---+--------------------+-----------+----------+-----------------+------------
4  | ArrivalTime        | numeric   | 0 (0.0%) |  [21.71, 29.25] |         599
---+--------------------+-----------+----------+-----------------+------------
5  | SiblingNegotiation | numeric   | 0 (0.0%) |         [0, 32] |         599
---+--------------------+-----------+----------+-----------------+------------
6  | BroodSize          | numeric   | 0 (0.0%) |          [1, 7] |         599
---+--------------------+-----------+----------+-----------------+------------
7  | NegPerChick        | numeric   | 0 (0.0%) |        [0, 8.5] |         599
------------------------------------------------------------------------------
owls |> modelsummary::datasummary_skim()
Unique Missing Pct. Mean SD Min Median Max Histogram
ArrivalTime 317 0 24.8 1.9 21.7 24.4 29.2
SiblingNegotiation 29 0 6.7 6.7 0.0 5.0 32.0
BroodSize 7 0 4.4 1.2 1.0 4.0 7.0
NegPerChick 78 0 1.6 1.6 0.0 1.2 8.5
N %
Nest AutavauxTV 28 4.7
Bochet 23 3.8
Champmartin 30 5.0
ChEsard 20 3.3
Chevroux 10 1.7
CorcellesFavres 12 2.0
Etrabloz 34 5.7
Forel 4 0.7
Franex 26 4.3
GDLV 10 1.7
Gletterens 15 2.5
Henniez 13 2.2
Jeuss 19 3.2
LesPlanches 17 2.8
Lucens 29 4.8
Lully 17 2.8
Marnand 27 4.5
Montet 41 6.8
Murist 24 4.0
Oleyes 52 8.7
Payerne 25 4.2
Rueyes 17 2.8
Seiry 26 4.3
Sevaz 4 0.7
StAubin 23 3.8
Trey 19 3.2
Yvonnand 34 5.7
FoodTreatment Deprived 320 53.4
Satiated 279 46.6
SexParent Female 245 40.9
Male 354 59.1
owls |> modelsummary::datasummary_skim(by = c("SexParent", "FoodTreatment"))
SexParent FoodTreatment Unique Missing Pct. Mean SD Min Median Max Histogram
ArrivalTime Male Deprived 160 0 24.9 2.0 22.0 24.4 29.2
Male Satiated 128 0 24.7 1.8 21.8 24.5 29.1
Female Satiated 105 0 24.6 1.9 21.7 24.4 29.2
Female Deprived 107 0 24.8 2.0 22.0 24.2 29.2
SiblingNegotiation Male Deprived 25 0 8.7 6.5 0.0 7.0 31.0
Male Satiated 23 0 5.3 6.6 0.0 3.0 32.0
Female Satiated 22 0 4.8 6.5 0.0 1.5 26.0
Female Deprived 21 0 7.3 6.3 0.0 6.0 28.0
BroodSize Male Deprived 7 0 4.5 1.1 1.0 4.0 7.0
Male Satiated 7 0 4.4 1.1 1.0 5.0 7.0
Female Satiated 7 0 4.5 1.3 1.0 5.0 7.0
Female Deprived 6 0 4.0 1.1 2.0 4.0 7.0
NegPerChick Male Deprived 52 0 2.0 1.5 0.0 1.5 8.5
Male Satiated 45 0 1.2 1.5 0.0 0.6 6.7
Female Satiated 39 0 1.0 1.5 0.0 0.3 8.5
Female Deprived 44 0 1.9 1.8 0.0 1.5 8.0
N %
Nest AutavauxTV 28 4.7
Bochet 23 3.8
Champmartin 30 5.0
ChEsard 20 3.3
Chevroux 10 1.7
CorcellesFavres 12 2.0
Etrabloz 34 5.7
Forel 4 0.7
Franex 26 4.3
GDLV 10 1.7
Gletterens 15 2.5
Henniez 13 2.2
Jeuss 19 3.2
LesPlanches 17 2.8
Lucens 29 4.8
Lully 17 2.8
Marnand 27 4.5
Montet 41 6.8
Murist 24 4.0
Oleyes 52 8.7
Payerne 25 4.2
Rueyes 17 2.8
Seiry 26 4.3
Sevaz 4 0.7
StAubin 23 3.8
Trey 19 3.2
Yvonnand 34 5.7
FoodTreatment Deprived 320 53.4
Satiated 279 46.6
SexParent Female 245 40.9
Male 354 59.1

4 Data preparation

Let start by declaring the categorical variables and random effect as factors.

## Amount of Sibling negotiation (vocalizations when parents are absent)
## Foot treatment (deprived or satiated
## Sex of parent
## Arrival time of parent
## Nest as random
## Brood size offset
owls <- owls |> mutate(
  Nest = factor(Nest),
  FoodTreatment = factor(FoodTreatment),
  SexParent = factor(SexParent),
  NCalls = SiblingNegotiation
)

5 Exploratory data analysis

As the response represents counts (the number of calls), it would make sense to start by considering a Poisson model. We could attempt to model the response as the number of calls divided by the brood size, but this would result in a response that has no natural distribution.

Instead, if we include brood size as an offset, it will standardise the effects according to brood size (similar to having divided the response by brood size), yet retain the Poisson nature of the response.

The effects of offsets, unlike regular covariates, are not estimated. Rather they are assumed to be 1 (on the link scale). This means that since Poisson uses a log link, then the offset should be of a logged version of the brood size.

Random intercept/slope model formula:

\[ \begin{align} y_i &\sim{} \mathcal{NB}(\mu_{ij}, \phi)\\ ln\left(\mu_{ij}\right) &=\boldsymbol{\beta} \bf{X_i} + \boldsymbol{\gamma} \bf{Z_i}\\ \beta_0 &\sim{} \mathcal{N}(0.4, 0.7)\\ \beta_1 &\sim{} \mathcal{N}(0, 1)\\ \boldsymbol{\gamma_j} &\sim{} \mathcal{N}(0, \boldsymbol{\Sigma})\\ \boldsymbol{\Sigma} &= \boldsymbol{D}({\sigma_n^2})\boldsymbol{\Omega}\boldsymbol{D}({\sigma_n^2})\\ \boldsymbol{\Omega} &\sim{} LKJ(\zeta)\\ \sigma_n^2 &\sim{} \mathcal{t}(3,0,0.7)\\ \phi &\sim{} \mathcal{\Gamma}(0.01, 0.01)\\ \end{align} \]

where \(\boldsymbol{\beta}\) and \(\boldsymbol{\gamma}\) are vectors of the fixed and random effects parameters respectively and \(\bf{X}\) is the model matrix representing the overall intercept and effects of food treatment, sex of parent, arrival time (and various interactions) on the number of sibling negotiations. Brood size was also incorporated as an offset. \(\bf{Z}\) represents a cell means model matrix for the random intercepts associated with individual nests.

Perhaps we could start off by exploring the main fixed effects. To mimic the log-link, we will use a log-transformed y axis. Since there may well be zeros (no calls detected), we will use a pseudo log scale). We will also include the raw data (jittered and dodged)

ggplot(data = owls, aes(y = NCalls, x = FoodTreatment, color = SexParent)) +
  geom_violin()

ggplot(data = owls, aes(y = NCalls, x = FoodTreatment, color = SexParent)) +
  geom_violin() +
  geom_point(position = position_jitterdodge(jitter.width = 0.2, dodge.width = 0.9))

ggplot(data = owls, aes(y = NCalls, x = FoodTreatment, color = SexParent)) +
  geom_violin() +
  geom_point(position = position_jitterdodge(jitter.height = 0, dodge.width = 1)) +
  scale_y_continuous(trans = scales::pseudo_log_trans())

Now, a similar plot separated for each nest.

ggplot(data = owls) +
  geom_point(aes(y = NCalls, x = FoodTreatment, color = SexParent), position = position_dodge(0.5)) +
  facet_wrap(~Nest)

ggplot(data = owls) +
  geom_violin(aes(y = NCalls, x = FoodTreatment, color = SexParent)) +
  geom_point(aes(y = NCalls, x = FoodTreatment, color = SexParent), position = position_dodge(0.5)) +
  facet_wrap(~Nest)
Warning: Groups with fewer than two datapoints have been dropped.
ℹ Set `drop = FALSE` to consider such groups for position adjustment purposes.
Groups with fewer than two datapoints have been dropped.
ℹ Set `drop = FALSE` to consider such groups for position adjustment purposes.
Groups with fewer than two datapoints have been dropped.
ℹ Set `drop = FALSE` to consider such groups for position adjustment purposes.
Groups with fewer than two datapoints have been dropped.
ℹ Set `drop = FALSE` to consider such groups for position adjustment purposes.
Groups with fewer than two datapoints have been dropped.
ℹ Set `drop = FALSE` to consider such groups for position adjustment purposes.
Groups with fewer than two datapoints have been dropped.
ℹ Set `drop = FALSE` to consider such groups for position adjustment purposes.
Groups with fewer than two datapoints have been dropped.
ℹ Set `drop = FALSE` to consider such groups for position adjustment purposes.
Groups with fewer than two datapoints have been dropped.
ℹ Set `drop = FALSE` to consider such groups for position adjustment purposes.
Groups with fewer than two datapoints have been dropped.
ℹ Set `drop = FALSE` to consider such groups for position adjustment purposes.
Groups with fewer than two datapoints have been dropped.
ℹ Set `drop = FALSE` to consider such groups for position adjustment purposes.
Groups with fewer than two datapoints have been dropped.
ℹ Set `drop = FALSE` to consider such groups for position adjustment purposes.
Groups with fewer than two datapoints have been dropped.
ℹ Set `drop = FALSE` to consider such groups for position adjustment purposes.
Groups with fewer than two datapoints have been dropped.
ℹ Set `drop = FALSE` to consider such groups for position adjustment purposes.

It might also be worth establishing that there is a linear relationship between the number of calls and brood size. Again, we will mimic the use of the log-link by transforming the axes.

ggplot(data = owls, aes(y = NCalls, x = BroodSize, color = SexParent)) +
  geom_point() +
  geom_smooth(method = "lm") +
  facet_grid(~FoodTreatment) +
  scale_y_continuous(trans = scales::pseudo_log_trans()) +
  scale_x_log10()
`geom_smooth()` using formula = 'y ~ x'

6 Fit the model

This model has the potential to be more complex than most of the models in previous worksheets. Therefore, we will use the current example to illustrate the process of building a model up gradually rather than attempting to fit a more complex model from the start. The benifit of gradually building a model is that it becomes much easier to construct more sensible and appropriate models that perform nicely and meet all the various assumptions.

As we intend to build a number of models, we will nest the MCMC sampling diagnostics and Model validation sections under the Fit the model section since each model will have its own associated diagnostic testing.

Typically, when we are building up models, we start by constructing a model that only contains the hierarchical (random effects) structure.

In rstanarm, the default priors are designed to be weakly informative. They are chosen to provide moderate regularisation (to help prevent over-fitting) and help stabilise the computations.

owls_rstanP <- stan_glmer(
  NCalls ~ FoodTreatment * SexParent +
    offset(log(BroodSize)) + (1 | Nest),
  data = owls,
  family = poisson(link = "log"),
  refresh = 0,
  iter = 5000,
  warmup = 2000,
  thin = 10,
  chains = 3,
  cores = 3
)
owls_rstanP |> prior_summary()
Priors for model 'owls_rstanP' 
------
Intercept (after predictors centered)
 ~ normal(location = 0, scale = 2.5)

Coefficients
  Specified prior:
    ~ normal(location = [0,0,0], scale = [2.5,2.5,2.5])
  Adjusted prior:
    ~ normal(location = [0,0,0], scale = [5.01,5.08,5.68])

Covariance
 ~ decov(reg. = 1, conc. = 1, shape = 1, scale = 1)
------
See help('prior_summary.stanreg') for more details

This tells us:

  • for the intercept (when the family is Gaussian), a normal prior with a mean of 0 and a standard deviation of 2.5 is used. The 2.5 is used for all intercepts. This is then scaled to the scale of the data by multiplying by the standard deviation of the response. When this results in values less than 2.5, it is replaced with 2.5.
2.5 / sd(owls$NCalls)
[1] 0.3747667
  • for the coefficients (in this case, just the difference between strong and weak inoculation), the default prior is a normal prior centred around 0 with a standard deviation of 2.5. This is then adjusted for the scale of the data by multiplying the 2.5 by the ratio of the standard deviation of the response by the standard deviation of the numerical dummy variables for the predictor (then rounded).
model.matrix(~ FoodTreatment * SexParent + offset(log(BroodSize)), data = owls) |>
  apply(2, sd) * 1 / 2.5
                        (Intercept)               FoodTreatmentSatiated 
                          0.0000000                           0.1996977 
                      SexParentMale FoodTreatmentSatiated:SexParentMale 
                          0.1968252                           0.1760585 

Lets now run with priors only so that we can explore the range of values they allow in the posteriors.

owls_rstanarmP1 <- update(owls_rstanP, prior_PD = TRUE)
owls_rstanarmP1 |>
  ggpredict(~ FoodTreatment * SexParent) |>
  plot(show_data = TRUE, jitter = c(0.25, 0)) +
  scale_y_continuous("", trans = scales::pseudo_log_trans())
You are calculating adjusted predictions on the population-level (i.e.
  `type = "fixed"`) for a *generalized* linear mixed model.
  This may produce biased estimates due to Jensen's inequality. Consider
  setting `bias_correction = TRUE` to correct for this bias.
  See also the documentation of the `bias_correction` argument.
Model uses a transformed offset term. Predictions may not be correct.
  It is recommended to fix the offset term using the `condition` argument,
  e.g. `condition = c(BroodSize = 1)`.
  You could also transform the offset variable before fitting the model
  and use `offset(BroodSize)` in the model formula.
Warning in sweep(eta, 2L, offset, `+`): STATS is longer than the extent of
'dim(x)[MARGIN]'
Note: uncertainty of error terms are not taken into account. Consider
  setting `interval` to "prediction". This will call `posterior_predict()`
  instead of `posterior_epred()`.
Scale for y is already present.
Adding another scale for y, which will replace the existing scale.

Conclusions:

  • we see that the range of predictions is fairly wide and the predicted means could range from a small value to a relatively large value.

The following link provides some guidance about defining priors. [https://github.com/stan-dev/stan/wiki/Prior-Choice-Recommendations]

When defining our own priors, we typically do not want them to be scaled.

If we wanted to define our own priors that were less vague, yet still not likely to bias the outcomes, we could try the following priors (mainly plucked out of thin air):

  • \(\beta_0\): normal centred at 1.5 with a standard deviation of 1.5
    • mean of 1.5: since mean(log(owls$NCalls+1)) or mean(asinh(owls$NCalls/(2*1))/log(exp(1)))
    • sd of 1.5: since sd(log(owls$NCalls+1)) or sd(asinh(owls$NCalls/(2*1))/log(exp(1)))
  • \(\beta_1\): normal centred at 0 with a standard deviation of 2.2
    • sd of 2.2: since sd(log(owls$NCalls+1))/model.matrix(~FoodTreatment*SexParent+offset(log(BroodSize)), data = owls) |> apply(2, sd)
  • \(\beta_2\): normal centred at 0 with a standard deviation of 2.2
    • sd of 2.2: since sd(log(owls$NCalls+1))/model.matrix(~FoodTreatment*SexParent+offset(log(BroodSize)), data = owls) |> apply(2, sd)
  • \(\beta_3\): normal centred at 0 with a standard deviation of 2.5
    • sd of 2.5: since sd(log(owls$NCalls+1))/model.matrix(~FoodTreatment*SexParent+offset(log(BroodSize)), data = owls) |> apply(2, sd)
  • \(\sigma\): exponential with rate of 1
  • \(\Sigma\): decov with:
    • regularisation: the exponent for a LKJ prior on the correlation matrix. A value of 1 (default) implies a joint uniform prior
    • concentration: the concentration parameter for a symmetric Dirichlet distribution. A value of 1 (default) implies a joint uniform distribution
    • shape and scale: the shape and scale parameters for a gamma prior on the scale and scale parameters of the decov prior. A value of 1 for both (default) simplifies the gamma prior to a unit-exponential distribution.

I will also overlay the raw data for comparison.

owls_rstanarmP2 <- stan_glmer(
  NCalls ~ FoodTreatment * SexParent +
    offset(log(BroodSize)) + (1 | Nest),
  data = owls,
  family = poisson(link = "log"),
  prior_intercept = normal(0, 1.5, autoscale = FALSE),
  prior = normal(0, c(2.2, 2.2, 2.5), autoscale = FALSE),
  prior_aux = exponential(1),
  prior_covariance = decov(1, 1, 1, 1),
  refresh = 0,
  iter = 5000,
  prior_PD = TRUE,
  warmup = 2000,
  thin = 10,
  chains = 3,
  cores = 3
)
owls_rstanarmP2 |>
  ggpredict(~ FoodTreatment * SexParent) |>
  plot(show_data = TRUE, jitter = c(0.25, 0)) +
  scale_y_continuous("", trans = scales::pseudo_log_trans())
Model uses a transformed offset term. Predictions may not be correct.
  It is recommended to fix the offset term using the `condition` argument,
  e.g. `condition = c(BroodSize = 1)`.
  You could also transform the offset variable before fitting the model
  and use `offset(BroodSize)` in the model formula.
Warning in sweep(eta, 2L, offset, `+`): STATS is longer than the extent of
'dim(x)[MARGIN]'
Note: uncertainty of error terms are not taken into account. Consider
  setting `interval` to "prediction". This will call `posterior_predict()`
  instead of `posterior_epred()`.
Scale for y is already present.
Adding another scale for y, which will replace the existing scale.

Now lets refit, conditioning on the data.

owls_rstanarmP3 <- update(owls_rstanarmP2, prior_PD = FALSE)
posterior_vs_prior(owls_rstanarmP3,
  color_by = "vs", group_by = TRUE,
  facet_args = list(scales = "free_y")
)

Drawing from prior...

Conclusions:

  • in each case, the prior is substantially wider than the posterior, suggesting that the posterior is not biased towards the prior.

In brms, the default priors are designed to be weakly informative. They are chosen to provide moderate regularisation (to help prevent over fitting) and help stabilise the computations.

Unlike rstanarm, brms models must be compiled before they start sampling. For most models, the compilation of the stan code takes around 45 seconds.

owls_form <- bf(NCalls ~ FoodTreatment*SexParent +
                    offset(log(BroodSize)) + (1|Nest),
                family=poisson(link='log'))
options(width=150)
owls_form |> get_prior(data = owls)
                               prior     class                                coef group resp dpar nlpar lb ub       source
                              (flat)         b                                                                      default
                              (flat)         b               FoodTreatmentSatiated                             (vectorized)
                              (flat)         b FoodTreatmentSatiated:SexParentMale                             (vectorized)
                              (flat)         b                       SexParentMale                             (vectorized)
 student_t(3, 0.16097150412244, 2.5) Intercept                                                                      default
                student_t(3, 0, 2.5)        sd                                                            0         default
                student_t(3, 0, 2.5)        sd                                      Nest                  0    (vectorized)
                student_t(3, 0, 2.5)        sd                           Intercept  Nest                  0    (vectorized)
options(width=80)

The following link provides some guidance about defining priors. [https://github.com/stan-dev/stan/wiki/Prior-Choice-Recommendations]

When defining our own priors, we typically do not want them to be scaled.

If we wanted to define our own priors that were less vague, yet still not likely to bias the outcomes, we could try the following priors (mainly plucked out of thin air):

  • \(\beta_0\): normal centred at 1.5 with a standard deviation of 1.5
    • mean of 1.5: since mean(log(owls$NCalls+1)) or mean(asinh(owls$NCalls/(2*1))/log(exp(1)))
    • sd of 1.5: since sd(log(owls$NCalls+1)) or sd(asinh(owls$NCalls/(2*1))/log(exp(1)))
  • \(\beta_1\): normal centred at 0 with a standard deviation of 2.2
    • sd of 2.2: since sd(log(owls$NCalls+1))/model.matrix(~FoodTreatment*SexParent+offset(log(BroodSize)), data = owls) |> apply(2, sd)
  • \(\beta_2\): normal centred at 0 with a standard deviation of 2.2
    • sd of 2.2: since sd(log(owls$NCalls+1))/model.matrix(~FoodTreatment*SexParent+offset(log(BroodSize)), data = owls) |> apply(2, sd)
  • \(\beta_3\): normal centred at 0 with a standard deviation of 2.5
    • sd of 2.5: since sd(log(owls$NCalls+1))/model.matrix(~FoodTreatment*SexParent+offset(log(BroodSize)), data = owls) |> apply(2, sd)
  • \(\sigma_j\): half-cauchy with parameters 0 and 5.
  • \(\Sigma\): decov with:
    • regularisation: the exponent for a LKJ prior on the correlation matrix. A value of 1 (default) implies a joint uniform prior
    • concentration: the concentration parameter for a symmetric Dirichlet distribution. A value of 1 (default) implies a joint uniform distribution
    • shape and scale: the shape and scale parameters for a gamma prior on the scale and scale parameters of the decov prior. A value of 1 for both (default) simplifies the gamma prior to a unit-exponential distribution.

Note, for hierarchical models, the model will tend to want to have a large \(sigma\) in order to fit the data better. It is a good idea to regularise this tendency by applying a prior that has most mass around zero. Suitable candidates include:

  • half-t: as the degrees of freedom approach infinity, this will approach a half-normal
  • half-cauchy: this is essentially a half-t with 1 degree of freedom
  • exponential

I will also overlay the raw data for comparison.

owls_form <- bf(
  NCalls ~ +
    offset(log(BroodSize)) + (1 | Nest),
  family = poisson(link = "log")
)
options(width = 150)
owls_form |> get_prior(data = owls)
                               prior     class      coef group resp dpar nlpar lb ub       source
 student_t(3, 0.16097150412244, 2.5) Intercept                                            default
                student_t(3, 0, 2.5)        sd                                  0         default
                student_t(3, 0, 2.5)        sd            Nest                  0    (vectorized)
                student_t(3, 0, 2.5)        sd Intercept  Nest                  0    (vectorized)
options(width = 80)
owls |>
  summarise(
    Mean = log(median(NCalls / BroodSize)),
    SD = log(sd(NCalls / BroodSize)),
    MAD = log(mad(NCalls / BroodSize))
  )
# A tibble: 1 × 3
   Mean    SD   MAD
  <dbl> <dbl> <dbl>
1 0.182 0.479 0.576
priors <- prior(normal(0.2, 0.6), class = "Intercept") +
  prior(student_t(3, 0, 0.6), class = "sd")
owls_brm1a <- brm(owls_form,
  data = owls,
  prior = priors,
  sample_prior = "only",
  iter = 5000,
  warmup = 2500,
  chains = 3,
  cores = 3,
  thin = 10,
  refresh = 0,
  seed = 123,
  control = list(adapt_delta = 0.99),
  backend = "rstan"
)
Compiling Stan program...
Start sampling
owls_brm1a |>
  emmeans(~1, type = "response") |>
  as.data.frame() |>
  ggplot(aes(x = 1, y = rate)) +
  geom_pointrange(aes(ymin = lower.HPD, ymax = upper.HPD)) +
  geom_point(
    data = owls, aes(y = NCalls / BroodSize),
    position = position_jitter(width = 0.2)
  )
Warning: Method 'parse_bf' is deprecated. Please use 'brmsterms' instead.

owls_brm1b <- update(owls_brm1a,
  sample_prior = "yes",
  iter = 5000,
  warmup = 2500,
  control = list(adapt_delta = 0.99, max_treedepth = 20),
  backend = "rstan",
  refresh = 0
)
The desired updates require recompiling the model
Compiling Stan program...
Start sampling
owls_brm1b |>
  emmeans(~1, type = "response") |>
  as.data.frame() |>
  ggplot(aes(x = 1, y = rate)) +
  geom_pointrange(aes(ymin = lower.HPD, ymax = upper.HPD)) +
  geom_point(
    data = owls, aes(y = NCalls / BroodSize),
    position = position_jitter(width = 0.2)
  )
Warning: Method 'parse_bf' is deprecated. Please use 'brmsterms' instead.

owls_brm1b |> SUYR_prior_and_posterior()

owls |>
  group_by(FoodTreatment, SexParent) |>
  summarise(
    Mean = log(median(NCalls / BroodSize)),
    SD = log(sd(NCalls / BroodSize)),
    MAD = log(mad(NCalls / BroodSize))
  )
`summarise()` has grouped output by 'FoodTreatment'. You can override using the
`.groups` argument.
# A tibble: 4 × 5
# Groups:   FoodTreatment [2]
  FoodTreatment SexParent   Mean    SD    MAD
  <fct>         <fct>      <dbl> <dbl>  <dbl>
1 Deprived      Female     0.405 0.562  0.656
2 Deprived      Male       0.405 0.416  0.489
3 Satiated      Female    -1.23  0.399 -0.838
4 Satiated      Male      -0.511 0.431 -0.117
standist::visualize("normal(0.4, 0.5)", xlim = c(0, 20))

standist::visualize("student_t(3, 0, 2.5)",
  "cauchy(0,1)",
  xlim = c(-10, 25)
)

The bayesplot package offers a range of MCMC diagnostics as well as Posterior Probability Checks (PPC), all of which have a convenient plot() interface. Lets start with the MCMC diagnostics.

available_mcmc()
bayesplot MCMC module:
  mcmc_acf
  mcmc_acf_bar
  mcmc_areas
  mcmc_areas_ridges
  mcmc_combo
  mcmc_dens
  mcmc_dens_chains
  mcmc_dens_overlay
  mcmc_hex
  mcmc_hist
  mcmc_hist_by_chain
  mcmc_intervals
  mcmc_neff
  mcmc_neff_hist
  mcmc_nuts_acceptance
  mcmc_nuts_divergence
  mcmc_nuts_energy
  mcmc_nuts_stepsize
  mcmc_nuts_treedepth
  mcmc_pairs
  mcmc_parcoord
  mcmc_rank_ecdf
  mcmc_rank_hist
  mcmc_rank_overlay
  mcmc_recover_hist
  mcmc_recover_intervals
  mcmc_recover_scatter
  mcmc_rhat
  mcmc_rhat_hist
  mcmc_scatter
  mcmc_trace
  mcmc_trace_highlight
  mcmc_violin

Of these, we will focus on:

  • trace: this plots the estimates of each parameter over the post-warmup length of each MCMC chain. Each chain is plotted in a different shade of blue, with each parameter in its own facet. Ideally, each trace should just look like noise without any discernible drift and each of the traces for a specific parameter should look the same (i.e, should not be displaced above or below any other trace for that parameter).
pars <- owls_brm1b |> get_variables()
pars <- pars |>
  str_extract("^b.Intercept|^b_FoodTreatment.*|^b_SexParent.*|[sS]igma|^sd.*") |>
  na.omit()
pars
[1] "b_Intercept"        "sd_Nest__Intercept"
attr(,"na.action")
 [1]  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
[26] 28 29 30 31 32 33 34 35 36 37 38 39 40
attr(,"class")
[1] "omit"
owls_brm1b |> mcmc_plot(type = "trace", variable = pars)
No divergences to plot.

## OR
owls_brm1b |> mcmc_plot(
  type = "trace",
  variable = "^b.Intercept|^b_FoodTreatment.*|^b_SexParent.*|[sS]igma|^sd.*",
  regex = TRUE
)
No divergences to plot.

The chains appear well mixed and very similar

  • acf_bar (auto-correlation function): plots the auto-correlation between successive MCMC sample lags for each parameter and each chain
owls_brm1b |> mcmc_plot(type = "acf_bar", variable = pars)

## OR
owls_brm1b |> mcmc_plot(
  type = "acf_bar",
  variable = "^b.Intercept|^b_FoodTreatment.*|^b_SexParent.*|[sS]igma|^sd.*",
  regex = TRUE
)

There is no evidence of auto-correlation in the MCMC samples

  • rhat_hist: Rhat is a scale reduction factor measure of convergence between the chains. The closer the values are to 1, the more the chains have converged. Values greater than 1.05 indicate a lack of convergence. There will be an Rhat value for each parameter estimated.
owls_brm1b |> mcmc_plot(type = "rhat_hist")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

All Rhat values are below 1.05, suggesting the chains have converged.

  • neff_hist (number of effective samples): the ratio of the number of effective samples (those not rejected by the sampler) to the number of samples provides an indication of the effectiveness (and efficiency) of the MCMC sampler. Ratios that are less than 0.5 for a parameter suggest that the sampler spent considerable time in difficult areas of the sampling domain and rejected more than half of the samples (replacing them with the previous effective sample).

    If the ratios are low, tightening the priors may help.

owls_brm1b |> mcmc_plot(type = "neff_hist")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Ratios all very high.

More diagnostics
owls_brm1b |> mcmc_plot(type = "combo", pars = pars)
Warning: Argument 'pars' is deprecated. Please use 'variable' instead.

owls_brm1b |> mcmc_plot(type = "violin", pars = pars)
Warning: Argument 'pars' is deprecated. Please use 'variable' instead.

The rstan package offers a range of MCMC diagnostics. Lets start with the MCMC diagnostics.

Of these, we will focus on:

  • stan_trace: this plots the estimates of each parameter over the post-warmup length of each MCMC chain. Each chain is plotted in a different colour, with each parameter in its own facet. Ideally, each trace should just look like noise without any discernible drift and each of the traces for a specific parameter should look the same (i.e, should not be displaced above or below any other trace for that parameter).
owls_brm1b |> get_variables()
 [1] "b_Intercept"                       "sd_Nest__Intercept"               
 [3] "Intercept"                         "r_Nest[AutavauxTV,Intercept]"     
 [5] "r_Nest[Bochet,Intercept]"          "r_Nest[Champmartin,Intercept]"    
 [7] "r_Nest[ChEsard,Intercept]"         "r_Nest[Chevroux,Intercept]"       
 [9] "r_Nest[CorcellesFavres,Intercept]" "r_Nest[Etrabloz,Intercept]"       
[11] "r_Nest[Forel,Intercept]"           "r_Nest[Franex,Intercept]"         
[13] "r_Nest[GDLV,Intercept]"            "r_Nest[Gletterens,Intercept]"     
[15] "r_Nest[Henniez,Intercept]"         "r_Nest[Jeuss,Intercept]"          
[17] "r_Nest[LesPlanches,Intercept]"     "r_Nest[Lucens,Intercept]"         
[19] "r_Nest[Lully,Intercept]"           "r_Nest[Marnand,Intercept]"        
[21] "r_Nest[Montet,Intercept]"          "r_Nest[Murist,Intercept]"         
[23] "r_Nest[Oleyes,Intercept]"          "r_Nest[Payerne,Intercept]"        
[25] "r_Nest[Rueyes,Intercept]"          "r_Nest[Seiry,Intercept]"          
[27] "r_Nest[Sevaz,Intercept]"           "r_Nest[StAubin,Intercept]"        
[29] "r_Nest[Trey,Intercept]"            "r_Nest[Yvonnand,Intercept]"       
[31] "prior_Intercept"                   "prior_sd_Nest"                    
[33] "lprior"                            "lp__"                             
[35] "accept_stat__"                     "stepsize__"                       
[37] "treedepth__"                       "n_leapfrog__"                     
[39] "divergent__"                       "energy__"                         
pars <- owls_brm1b |> get_variables()
pars <- str_extract(pars, "^b_.*|^sigma$|^sd.*") |> na.omit()

owls_brm1b$fit |>
  stan_trace(pars = pars)

The chains appear well mixed and very similar

  • stan_acf (auto-correlation function): plots the auto-correlation between successive MCMC sample lags for each parameter and each chain
owls_brm1b$fit |>
  stan_ac(pars = pars)

There is no evidence of auto-correlation in the MCMC samples

  • stan_rhat: Rhat is a scale reduction factor measure of convergence between the chains. The closer the values are to 1, the more the chains have converged. Values greater than 1.05 indicate a lack of convergence. There will be an Rhat value for each parameter estimated.
owls_brm1b$fit |> stan_rhat()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

All Rhat values are below 1.05, suggesting the chains have converged.

  • stan_ess (number of effective samples): the ratio of the number of effective samples (those not rejected by the sampler) to the number of samples provides an indication of the effectiveness (and efficiency) of the MCMC sampler. Ratios that are less than 0.5 for a parameter suggest that the sampler spent considerable time in difficult areas of the sampling domain and rejected more than half of the samples (replacing them with the previous effective sample).

    If the ratios are low, tightening the priors may help.

owls_brm1b$fit |> stan_ess()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Ratios all very high.

owls_brm1b$fit |>
  stan_dens(separate_chains = TRUE, pars = pars)

The ggmean package also as a set of MCMC diagnostic functions. Lets start with the MCMC diagnostics.

Of these, we will focus on:

  • ggs_traceplot: this plots the estimates of each parameter over the post-warmup length of each MCMC chain. Each chain is plotted in a different colour, with each parameter in its own facet. Ideally, each trace should just look like noise without any discernible drift and each of the traces for a specific parameter should look the same (i.e, should not be displaced above or below any other trace for that parameter).
## owls_ggs <- owls_brm3 |> ggs(burnin = FALSE, inc_warmup = FALSE)
## owls_ggs |> ggs_traceplot()

The chains appear well mixed and very similar

  • gss_autocorrelation (autocorrelation function): plots the autocorrelation between successive MCMC sample lags for each parameter and each chain
## ggs_autocorrelation(owls_ggs)

There is no evidence of auto-correlation in the MCMC samples

  • stan_rhat: Rhat is a scale reduction factor measure of convergence between the chains. The closer the values are to 1, the more the chains have converged. Values greater than 1.05 indicate a lack of convergence. There will be an Rhat value for each parameter estimated.
## ggs_Rhat(owls_ggs)

All Rhat values are below 1.05, suggesting the chains have converged.

  • stan_ess (number of effective samples): the ratio of the number of effective samples (those not rejected by the sampler) to the number of samples provides an indication of the effectiveness (and efficiency) of the MCMC sampler. Ratios that are less than 0.5 for a parameter suggest that the sampler spent considerable time in difficult areas of the sampling domain and rejected more than half of the samples (replacing them with the previous effective sample).

    If the ratios are low, tightening the priors may help.

## ggs_effective(owls_ggs)

Ratios all very high.

More diagnostics
## ggs_crosscorrelation(owls_ggs)
## ggs_grb(owls_ggs)

Post predictive checks provide additional diagnostics about the fit of the model. Specifically, they provide a comparison between predictions drawn from the model and the observed data used to train the model.

available_ppc()
bayesplot PPC module:
  ppc_bars
  ppc_bars_grouped
  ppc_boxplot
  ppc_dens
  ppc_dens_overlay
  ppc_dens_overlay_grouped
  ppc_dots
  ppc_ecdf_overlay
  ppc_ecdf_overlay_grouped
  ppc_error_binned
  ppc_error_hist
  ppc_error_hist_grouped
  ppc_error_scatter
  ppc_error_scatter_avg
  ppc_error_scatter_avg_grouped
  ppc_error_scatter_avg_vs_x
  ppc_freqpoly
  ppc_freqpoly_grouped
  ppc_hist
  ppc_intervals
  ppc_intervals_grouped
  ppc_km_overlay
  ppc_km_overlay_grouped
  ppc_loo_intervals
  ppc_loo_pit_ecdf
  ppc_loo_pit_overlay
  ppc_loo_pit_qq
  ppc_loo_ribbon
  ppc_pit_ecdf
  ppc_pit_ecdf_grouped
  ppc_ribbon
  ppc_ribbon_grouped
  ppc_rootogram
  ppc_scatter
  ppc_scatter_avg
  ppc_scatter_avg_grouped
  ppc_stat
  ppc_stat_2d
  ppc_stat_freqpoly
  ppc_stat_freqpoly_grouped
  ppc_stat_grouped
  ppc_violin_grouped
  • dens_overlay: plots the density distribution of the observed data (black line) overlayed on top of 50 density distributions generated from draws from the model (light blue). Ideally, the 50 realisations should be roughly consistent with the observed data.
owls_brm1b |> pp_check(type = "dens_overlay", ndraws = 100)

The model draws appear to differ substantially from the observed data.

  • error_scatter_avg: this plots the observed values against the average residuals. Similar to a residual plot, we do not want to see any patterns in this plot. Note, this is not really that useful for models that involve a binomial response
## owls_brm1b |> pp_check(type = 'error_scatter_avg')

This is not really interpretable

  • intervals: plots the observed data overlayed on top of posterior predictions associated with each level of the predictor. Ideally, the observed data should all fall within the predictive intervals.
owls_brm1b |> pp_check(group = "Nest", type = "intervals")
Using all posterior draws for ppc type 'intervals' by default.
Warning: The following arguments were unrecognized and ignored: group

The shinystan package allows the full suite of MCMC diagnostics and posterior predictive checks to be accessed via a web interface.

# library(shinystan)
# launch_shinystan(owls_brm2)

DHARMa residuals provide very useful diagnostics. Unfortunately, we cannot directly use the simulateResiduals() function to generate the simulated residuals. However, if we are willing to calculate some of the components yourself, we can still obtain the simulated residuals from the fitted stan model.

We need to supply:

  • simulated (predicted) responses associated with each observation.
  • observed values
  • fitted (predicted) responses (averaged) associated with each observation
owls_resids <- make_brms_dharma_res(owls_brm1b, integerResponse = TRUE)
wrap_elements(~ testUniformity(owls_resids)) +
  wrap_elements(~ plotResiduals(owls_resids, form = factor(rep(1, nrow(owls))))) +
  wrap_elements(~ plotResiduals(owls_resids, quantreg = TRUE)) +
  wrap_elements(~ testDispersion(owls_resids))

Conclusions:

  • the model does not appear to be a very good fit
  • the Q-Q plot deviates substantially from a straight line
  • there are outliers

Perhaps we should specifically explore zero-inflation.

owls_resids |> testZeroInflation()


    DHARMa zero-inflation test via comparison to expected zeros with
    simulation under H0 = fitted model

data:  simulationOutput
ratioObsSim = 14.022, p-value < 2.2e-16
alternative hypothesis: two.sided

Conclusions:

  • there is strong evidence of zero-inflation


The data were collected at various times throughout the night. It is possible that this could lead to patterns of dependency that are not already accounted for. For example, perhaps observations that are collected at similar time of the night (within a given nest) have more similar residuals than those at very different time of the night. We can explore whether there are any temporal auto-correlation patterns.

owls_resids |> testTemporalAutocorrelation(time = owls$ArrivalTime)
Error in testTemporalAutocorrelation(owls_resids, time = owls$ArrivalTime): testing for temporal autocorrelation requires unique time values - if you have several observations per time value, either use the recalculateResiduals function to aggregate residuals per time step, or extract the residuals from the fitted object, and plot / test each of them independently for temporally repeated subgroups (typical choices would be location / subject etc.). Note that the latter must be done by hand, outside testTemporalAutocorrelation.
## owls_resid1 <- owls_resids |> recalculateResiduals(group=interaction(owls$ArrivalTime,  owls$Nest),  aggregateBy = mean)
## owls_resid1 <- owls_resids |> recalculateResiduals(group=interaction(owls$ArrivalTime,  owls$Nest),  aggregateBy = sum)
## resids1 <- owls_resids |> recalculateResiduals(group = interaction(owls$ArrivalTime), aggregateBy = sum)
resids1 <- owls_resids |> recalculateResiduals(group = interaction(owls$ArrivalTime), aggregateBy = mean)
resids1 |> testTemporalAutocorrelation(time = unique(owls$ArrivalTime))


    Durbin-Watson test

data:  simulationOutput$scaledResiduals ~ 1
DW = 2.117, p-value = 0.2962
alternative hypothesis: true autocorrelation is not 0
autocor_check(owls, owls_brm1b,
  variable = "ArrivalTime",
  grouping = "Nest",
  n.sim = 250
)
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin
variog: computing omnidirectional variogram
variog: co-locatted data found, adding one bin at the origin

Conclusions:

  • there is no evidence of temporal auto-correlation

Conclusions:

  • there is evidence that the model does not fit that well. It is evidently zero inflated and possibly also over-dispersed.
  • it would seem that a zero-inflated Poisson or even a zero-inflated Negative Binomial would be a sensible next step.
  • zero-inflated models cannot be fit in glmer(), so we will proceed with glmmTMB() only.

Zero-inflated vs hurdle models

  • zero-inflated models: are a mixture of Bernoulli and Poisson (or negative binomial) distributions to model situations where it is believed that the observed data are the result of two combined processes (a count process that governs how many items there are to count and a Bernoulli process that governs whether the items are detectable). In this way, zero-inflated models are useful in situations where we believe that some of the zeros are false zeros (recorded as zeros when they should not have been).
  • hurdle models: are for situations where the response itself is thought to be the result of two processes: one that governs whether there is a response and then another that governs the value of the response (must be positive).
owls_form <- bf(
  NCalls ~ +
    offset(log(BroodSize)) + (1 | Nest),
  zi = ~1,
  family = zero_inflated_poisson(link = "log")
)
options(width = 150)
owls_form |> get_prior(data = owls)
                               prior     class      coef group resp dpar nlpar lb ub       source
 student_t(3, 0.16097150412244, 2.5) Intercept                                            default
                student_t(3, 0, 2.5)        sd                                  0         default
                student_t(3, 0, 2.5)        sd            Nest                  0    (vectorized)
                student_t(3, 0, 2.5)        sd Intercept  Nest                  0    (vectorized)
                      logistic(0, 1) Intercept                        zi                  default
options(width = 80)
owls |>
  summarise(
    Mean = log(median(NCalls / BroodSize)),
    SD = log(sd(NCalls / BroodSize)),
    MAD = log(mad(NCalls / BroodSize))
  )
# A tibble: 1 × 3
   Mean    SD   MAD
  <dbl> <dbl> <dbl>
1 0.182 0.479 0.576
priors <- prior(normal(0.2, 0.6), class = "Intercept") +
  prior(student_t(3, 0, 0.6), class = "sd") +
  prior(normal(0, 1), class = "Intercept", dpar = "zi")
owls_brm2a <- brm(owls_form,
  data = owls,
  prior = priors,
  sample_prior = "only",
  iter = 5000,
  warmup = 2500,
  chains = 3,
  cores = 3,
  thin = 10,
  refresh = 0,
  seed = 123,
  control = list(adapt_delta = 0.99),
  backend = "rstan"
)
Compiling Stan program...
Start sampling
owls_brm2a |>
  emmeans(~1, type = "response") |>
  as.data.frame() |>
  ggplot(aes(x = 1, y = rate)) +
  geom_pointrange(aes(ymin = lower.HPD, ymax = upper.HPD)) +
  geom_point(
    data = owls, aes(y = NCalls / BroodSize),
    position = position_jitter(width = 0.2)
  )
Warning: Method 'parse_bf' is deprecated. Please use 'brmsterms' instead.

owls_brm2b <- update(owls_brm2a,
  sample_prior = "yes",
  iter = 5000,
  warmup = 2500,
  control = list(adapt_delta = 0.99, max_treedepth = 20),
  backend = "rstan",
  refresh = 0
)
The desired updates require recompiling the model
Compiling Stan program...
Start sampling
owls_brm2b |>
  emmeans(~1, type = "response") |>
  as.data.frame() |>
  ggplot(aes(x = 1, y = rate)) +
  geom_pointrange(aes(ymin = lower.HPD, ymax = upper.HPD)) +
  geom_point(
    data = owls, aes(y = NCalls / BroodSize),
    position = position_jitter(width = 0.2)
  )
Warning: Method 'parse_bf' is deprecated. Please use 'brmsterms' instead.

owls_brm2b |> SUYR_prior_and_posterior()

owls_brm2b |> get_variables()
 [1] "b_Intercept"                       "b_zi_Intercept"                   
 [3] "sd_Nest__Intercept"                "Intercept"                        
 [5] "Intercept_zi"                      "r_Nest[AutavauxTV,Intercept]"     
 [7] "r_Nest[Bochet,Intercept]"          "r_Nest[Champmartin,Intercept]"    
 [9] "r_Nest[ChEsard,Intercept]"         "r_Nest[Chevroux,Intercept]"       
[11] "r_Nest[CorcellesFavres,Intercept]" "r_Nest[Etrabloz,Intercept]"       
[13] "r_Nest[Forel,Intercept]"           "r_Nest[Franex,Intercept]"         
[15] "r_Nest[GDLV,Intercept]"            "r_Nest[Gletterens,Intercept]"     
[17] "r_Nest[Henniez,Intercept]"         "r_Nest[Jeuss,Intercept]"          
[19] "r_Nest[LesPlanches,Intercept]"     "r_Nest[Lucens,Intercept]"         
[21] "r_Nest[Lully,Intercept]"           "r_Nest[Marnand,Intercept]"        
[23] "r_Nest[Montet,Intercept]"          "r_Nest[Murist,Intercept]"         
[25] "r_Nest[Oleyes,Intercept]"          "r_Nest[Payerne,Intercept]"        
[27] "r_Nest[Rueyes,Intercept]"          "r_Nest[Seiry,Intercept]"          
[29] "r_Nest[Sevaz,Intercept]"           "r_Nest[StAubin,Intercept]"        
[31] "r_Nest[Trey,Intercept]"            "r_Nest[Yvonnand,Intercept]"       
[33] "prior_Intercept"                   "prior_Intercept_zi"               
[35] "prior_sd_Nest"                     "lprior"                           
[37] "lp__"                              "accept_stat__"                    
[39] "stepsize__"                        "treedepth__"                      
[41] "n_leapfrog__"                      "divergent__"                      
[43] "energy__"                         
pars <- owls_brm2b |> get_variables()
pars <- str_extract(pars, "^b_.*|^sigma$|^sd.*") |> na.omit()

owls_brm2b$fit |>
  stan_trace(pars = pars)

owls_brm2b$fit |>
  stan_ac(pars = pars)

owls_brm2b$fit |> stan_rhat()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

owls_brm2b$fit |> stan_ess()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

owls_brm2b$fit |>
  stan_dens(separate_chains = TRUE, pars = pars)

owls_brm2b |> pp_check(type = "dens_overlay", ndraws = 100)

## owls_brm2b |> pp_check(type = 'error_scatter_avg')
owls_brm2b |> pp_check(group = "Nest", type = "intervals")
Using all posterior draws for ppc type 'intervals' by default.
Warning: The following arguments were unrecognized and ignored: group

owls_resids <- make_brms_dharma_res(owls_brm2b, integerResponse = TRUE)
wrap_elements(~ testUniformity(owls_resids)) +
  wrap_elements(~ plotResiduals(owls_resids, form = factor(rep(1, nrow(owls))))) +
  wrap_elements(~ plotResiduals(owls_resids, quantreg = TRUE)) +
  wrap_elements(~ testDispersion(owls_resids))

owls_form <- bf(
  NCalls ~ +
    offset(log(BroodSize)) + (1 | Nest),
  zi = ~1,
  family = zero_inflated_negbinomial(link = "log")
)
options(width = 150)
owls_form |> get_prior(data = owls)
                               prior     class      coef group resp dpar nlpar lb ub       source
 student_t(3, 0.16097150412244, 2.5) Intercept                                            default
                student_t(3, 0, 2.5)        sd                                  0         default
                student_t(3, 0, 2.5)        sd            Nest                  0    (vectorized)
                student_t(3, 0, 2.5)        sd Intercept  Nest                  0    (vectorized)
                   gamma(0.01, 0.01)     shape                                  0         default
                      logistic(0, 1) Intercept                        zi                  default
options(width = 80)
owls |>
  summarise(
    Mean = log(median(NCalls / BroodSize)),
    SD = log(sd(NCalls / BroodSize)),
    MAD = log(mad(NCalls / BroodSize))
  )
# A tibble: 1 × 3
   Mean    SD   MAD
  <dbl> <dbl> <dbl>
1 0.182 0.479 0.576
priors <- prior(normal(0.2, 0.6), class = "Intercept") +
  prior(student_t(3, 0, 0.6), class = "sd") +
  prior(normal(0, 1), class = "Intercept", dpar = "zi") +
  prior(gamma(0.01, 0.01), class = "shape")
owls_brm3a <- brm(owls_form,
  data = owls,
  prior = priors,
  sample_prior = "only",
  iter = 5000,
  warmup = 2500,
  chains = 3,
  cores = 3,
  thin = 10,
  refresh = 0,
  seed = 123,
  control = list(adapt_delta = 0.99),
  backend = "rstan"
)
Compiling Stan program...
Start sampling
Warning: There were 4 divergent transitions after warmup. See
https://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
to find out why this is a problem and how to eliminate them.
Warning: Examine the pairs() plot to diagnose sampling problems
owls_brm3b <- update(owls_brm3a,
  sample_prior = "yes",
  iter = 5000,
  warmup = 2500,
  control = list(adapt_delta = 0.99, max_treedepth = 20),
  backend = "rstan",
  refresh = 0
)
The desired updates require recompiling the model
Compiling Stan program...
Start sampling
owls_brm3b |>
  emmeans(~1, type = "response") |>
  as.data.frame() |>
  ggplot(aes(x = 1, y = prob)) +
  geom_pointrange(aes(ymin = lower.HPD, ymax = upper.HPD)) +
  geom_point(
    data = owls, aes(y = NCalls / BroodSize),
    position = position_jitter(width = 0.2)
  )
Warning: Method 'parse_bf' is deprecated. Please use 'brmsterms' instead.

owls_brm3b |> SUYR_prior_and_posterior()

owls_brm3b |> get_variables()
 [1] "b_Intercept"                       "b_zi_Intercept"                   
 [3] "sd_Nest__Intercept"                "shape"                            
 [5] "Intercept"                         "Intercept_zi"                     
 [7] "r_Nest[AutavauxTV,Intercept]"      "r_Nest[Bochet,Intercept]"         
 [9] "r_Nest[Champmartin,Intercept]"     "r_Nest[ChEsard,Intercept]"        
[11] "r_Nest[Chevroux,Intercept]"        "r_Nest[CorcellesFavres,Intercept]"
[13] "r_Nest[Etrabloz,Intercept]"        "r_Nest[Forel,Intercept]"          
[15] "r_Nest[Franex,Intercept]"          "r_Nest[GDLV,Intercept]"           
[17] "r_Nest[Gletterens,Intercept]"      "r_Nest[Henniez,Intercept]"        
[19] "r_Nest[Jeuss,Intercept]"           "r_Nest[LesPlanches,Intercept]"    
[21] "r_Nest[Lucens,Intercept]"          "r_Nest[Lully,Intercept]"          
[23] "r_Nest[Marnand,Intercept]"         "r_Nest[Montet,Intercept]"         
[25] "r_Nest[Murist,Intercept]"          "r_Nest[Oleyes,Intercept]"         
[27] "r_Nest[Payerne,Intercept]"         "r_Nest[Rueyes,Intercept]"         
[29] "r_Nest[Seiry,Intercept]"           "r_Nest[Sevaz,Intercept]"          
[31] "r_Nest[StAubin,Intercept]"         "r_Nest[Trey,Intercept]"           
[33] "r_Nest[Yvonnand,Intercept]"        "prior_Intercept"                  
[35] "prior_shape"                       "prior_Intercept_zi"               
[37] "prior_sd_Nest"                     "lprior"                           
[39] "lp__"                              "accept_stat__"                    
[41] "stepsize__"                        "treedepth__"                      
[43] "n_leapfrog__"                      "divergent__"                      
[45] "energy__"                         
pars <- owls_brm3b |> get_variables()
pars <- str_extract(pars, "^b_.*|^sigma$|^sd.*") |> na.omit()

owls_brm3b$fit |>
  stan_trace(pars = pars)

owls_brm3b$fit |>
  stan_ac(pars = pars)

owls_brm3b$fit |> stan_rhat()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

owls_brm3b$fit |> stan_ess()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

owls_brm3b$fit |>
  stan_dens(separate_chains = TRUE, pars = pars)

owls_brm3b |> pp_check(type = "dens_overlay", ndraws = 100)

## owls_brm3b |> pp_check(type = 'error_scatter_avg')
owls_brm3b |> pp_check(group = "Nest", type = "intervals")
Using all posterior draws for ppc type 'intervals' by default.
Warning: The following arguments were unrecognized and ignored: group

owls_resids <- make_brms_dharma_res(owls_brm3b, integerResponse = TRUE)
wrap_elements(~ testUniformity(owls_resids)) +
  wrap_elements(~ plotResiduals(owls_resids, form = factor(rep(1, nrow(owls))))) +
  wrap_elements(~ plotResiduals(owls_resids, quantreg = TRUE)) +
  wrap_elements(~ testDispersion(owls_resids))

owls_form <- bf(
  NCalls ~ FoodTreatment * SexParent +
    offset(log(BroodSize)) + (1 | Nest),
  zi = ~1,
  family = zero_inflated_negbinomial(link = "log")
)
options(width = 150)
owls_form |> get_prior(data = owls)
                               prior     class                                coef group resp dpar nlpar lb ub       source
                              (flat)         b                                                                      default
                              (flat)         b               FoodTreatmentSatiated                             (vectorized)
                              (flat)         b FoodTreatmentSatiated:SexParentMale                             (vectorized)
                              (flat)         b                       SexParentMale                             (vectorized)
 student_t(3, 0.16097150412244, 2.5) Intercept                                                                      default
                student_t(3, 0, 2.5)        sd                                                            0         default
                student_t(3, 0, 2.5)        sd                                      Nest                  0    (vectorized)
                student_t(3, 0, 2.5)        sd                           Intercept  Nest                  0    (vectorized)
                   gamma(0.01, 0.01)     shape                                                            0         default
                      logistic(0, 1) Intercept                                                  zi                  default
options(width = 80)
owls |>
  group_by(FoodTreatment, SexParent) |>
  summarise(
    Mean = log(median(NCalls / BroodSize)),
    SD = log(sd(NCalls / BroodSize)),
    MAD = log(mad(NCalls / BroodSize))
  )
`summarise()` has grouped output by 'FoodTreatment'. You can override using the
`.groups` argument.
# A tibble: 4 × 5
# Groups:   FoodTreatment [2]
  FoodTreatment SexParent   Mean    SD    MAD
  <fct>         <fct>      <dbl> <dbl>  <dbl>
1 Deprived      Female     0.405 0.562  0.656
2 Deprived      Male       0.405 0.416  0.489
3 Satiated      Female    -1.23  0.399 -0.838
4 Satiated      Male      -0.511 0.431 -0.117
priors <- prior(normal(0.4, 0.7), class = "Intercept") +
  prior(normal(0, 1), class = "b") +
  prior(student_t(3, 0, 0.7), class = "sd") +
  prior(normal(0, 1), class = "Intercept", dpar = "zi") +
  prior(gamma(0.01, 0.01), class = "shape")
owls_brm4a <- brm(owls_form,
  data = owls,
  prior = priors,
  sample_prior = "only",
  iter = 5000,
  warmup = 2500,
  chains = 3,
  cores = 3,
  thin = 10,
  refresh = 0,
  seed = 123,
  control = list(adapt_delta = 0.99),
  backend = "rstan"
)
Compiling Stan program...
Start sampling
Warning: There were 5 divergent transitions after warmup. See
https://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
to find out why this is a problem and how to eliminate them.
Warning: Examine the pairs() plot to diagnose sampling problems
owls_brm4b <- update(owls_brm4a,
  sample_prior = "yes",
  iter = 5000,
  warmup = 2500,
  control = list(adapt_delta = 0.99, max_treedepth = 20),
  backend = "rstan",
  refresh = 0
)
The desired updates require recompiling the model
Compiling Stan program...
Start sampling
owls_brm4b |>
  conditional_effects("FoodTreatment:SexParent") |>
  plot(points = TRUE)

owls_brm4b |> SUYR_prior_and_posterior()

owls_brm4b |> get_variables()
 [1] "b_Intercept"                          
 [2] "b_zi_Intercept"                       
 [3] "b_FoodTreatmentSatiated"              
 [4] "b_SexParentMale"                      
 [5] "b_FoodTreatmentSatiated:SexParentMale"
 [6] "sd_Nest__Intercept"                   
 [7] "shape"                                
 [8] "Intercept"                            
 [9] "Intercept_zi"                         
[10] "r_Nest[AutavauxTV,Intercept]"         
[11] "r_Nest[Bochet,Intercept]"             
[12] "r_Nest[Champmartin,Intercept]"        
[13] "r_Nest[ChEsard,Intercept]"            
[14] "r_Nest[Chevroux,Intercept]"           
[15] "r_Nest[CorcellesFavres,Intercept]"    
[16] "r_Nest[Etrabloz,Intercept]"           
[17] "r_Nest[Forel,Intercept]"              
[18] "r_Nest[Franex,Intercept]"             
[19] "r_Nest[GDLV,Intercept]"               
[20] "r_Nest[Gletterens,Intercept]"         
[21] "r_Nest[Henniez,Intercept]"            
[22] "r_Nest[Jeuss,Intercept]"              
[23] "r_Nest[LesPlanches,Intercept]"        
[24] "r_Nest[Lucens,Intercept]"             
[25] "r_Nest[Lully,Intercept]"              
[26] "r_Nest[Marnand,Intercept]"            
[27] "r_Nest[Montet,Intercept]"             
[28] "r_Nest[Murist,Intercept]"             
[29] "r_Nest[Oleyes,Intercept]"             
[30] "r_Nest[Payerne,Intercept]"            
[31] "r_Nest[Rueyes,Intercept]"             
[32] "r_Nest[Seiry,Intercept]"              
[33] "r_Nest[Sevaz,Intercept]"              
[34] "r_Nest[StAubin,Intercept]"            
[35] "r_Nest[Trey,Intercept]"               
[36] "r_Nest[Yvonnand,Intercept]"           
[37] "prior_Intercept"                      
[38] "prior_b"                              
[39] "prior_shape"                          
[40] "prior_Intercept_zi"                   
[41] "prior_sd_Nest"                        
[42] "lprior"                               
[43] "lp__"                                 
[44] "accept_stat__"                        
[45] "stepsize__"                           
[46] "treedepth__"                          
[47] "n_leapfrog__"                         
[48] "divergent__"                          
[49] "energy__"                             
pars <- owls_brm4b |> get_variables()
pars <- str_extract(pars, "^b_.*|^sigma$|^sd.*") |> na.omit()

owls_brm4b$fit |>
  stan_trace(pars = pars)

owls_brm4b$fit |>
  stan_ac(pars = pars)

owls_brm4b$fit |> stan_rhat()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

owls_brm4b$fit |> stan_ess()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

owls_brm4b$fit |>
  stan_dens(separate_chains = TRUE, pars = pars)

owls_brm4b |> pp_check(type = "dens_overlay", ndraws = 100)

## owls_brm4b |> pp_check(type = 'error_scatter_avg')
owls_brm4b |> pp_check(group = "Nest", type = "intervals")
Using all posterior draws for ppc type 'intervals' by default.
Warning: The following arguments were unrecognized and ignored: group

owls_resids <- make_brms_dharma_res(owls_brm4b, integerResponse = TRUE)
wrap_elements(~ testUniformity(owls_resids)) +
  wrap_elements(~ plotResiduals(owls_resids, form = factor(rep(1, nrow(owls))))) +
  wrap_elements(~ plotResiduals(owls_resids, quantreg = TRUE)) +
  wrap_elements(~ testDispersion(owls_resids))

owls_form <- bf(
  NCalls ~ FoodTreatment * SexParent +
    offset(log(BroodSize)) +
    (FoodTreatment * SexParent | Nest),
  zi = ~ FoodTreatment * SexParent,
  family = zero_inflated_negbinomial(link = "log")
)
options(width = 150)
owls_form |> get_prior(data = owls)
                               prior     class                                coef group resp dpar nlpar lb ub       source
                              (flat)         b                                                                      default
                              (flat)         b               FoodTreatmentSatiated                             (vectorized)
                              (flat)         b FoodTreatmentSatiated:SexParentMale                             (vectorized)
                              (flat)         b                       SexParentMale                             (vectorized)
                              lkj(1)       cor                                                                      default
                              lkj(1)       cor                                      Nest                       (vectorized)
 student_t(3, 0.16097150412244, 2.5) Intercept                                                                      default
                student_t(3, 0, 2.5)        sd                                                            0         default
                student_t(3, 0, 2.5)        sd                                      Nest                  0    (vectorized)
                student_t(3, 0, 2.5)        sd               FoodTreatmentSatiated  Nest                  0    (vectorized)
                student_t(3, 0, 2.5)        sd FoodTreatmentSatiated:SexParentMale  Nest                  0    (vectorized)
                student_t(3, 0, 2.5)        sd                           Intercept  Nest                  0    (vectorized)
                student_t(3, 0, 2.5)        sd                       SexParentMale  Nest                  0    (vectorized)
                   gamma(0.01, 0.01)     shape                                                            0         default
                              (flat)         b                                                  zi                  default
                              (flat)         b               FoodTreatmentSatiated              zi             (vectorized)
                              (flat)         b FoodTreatmentSatiated:SexParentMale              zi             (vectorized)
                              (flat)         b                       SexParentMale              zi             (vectorized)
                      logistic(0, 1) Intercept                                                  zi                  default
options(width = 80)
owls |>
  group_by(FoodTreatment, SexParent) |>
  summarise(
    Mean = log(median(NCalls / BroodSize)),
    SD = log(sd(NCalls / BroodSize)),
    MAD = log(mad(NCalls / BroodSize))
  )
`summarise()` has grouped output by 'FoodTreatment'. You can override using the
`.groups` argument.
# A tibble: 4 × 5
# Groups:   FoodTreatment [2]
  FoodTreatment SexParent   Mean    SD    MAD
  <fct>         <fct>      <dbl> <dbl>  <dbl>
1 Deprived      Female     0.405 0.562  0.656
2 Deprived      Male       0.405 0.416  0.489
3 Satiated      Female    -1.23  0.399 -0.838
4 Satiated      Male      -0.511 0.431 -0.117
priors <- prior(normal(0.4, 0.7), class = "Intercept") +
  prior(normal(0, 1), class = "b") +
  prior(student_t(3, 0, 0.7), class = "sd") +
  prior(normal(0, 1), class = "Intercept", dpar = "zi") +
  prior(normal(0, 1), class = "b", dpar = "zi") +
  prior(gamma(0.01, 0.01), class = "shape")
owls_brm5a <- brm(owls_form,
  data = owls,
  prior = priors,
  sample_prior = "only",
  iter = 5000,
  warmup = 2500,
  chains = 3,
  cores = 3,
  thin = 10,
  refresh = 0,
  seed = 123,
  control = list(adapt_delta = 0.99),
  backend = "rstan"
)
Compiling Stan program...
Start sampling
Warning: There were 2 divergent transitions after warmup. See
https://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
to find out why this is a problem and how to eliminate them.
Warning: Examine the pairs() plot to diagnose sampling problems
owls_brm5b <- update(owls_brm5a,
  sample_prior = "yes",
  iter = 5000,
  warmup = 2500,
  control = list(adapt_delta = 0.99, max_treedepth = 20),
  backend = "rstan",
  refresh = 0
)
The desired updates require recompiling the model
Compiling Stan program...
Start sampling
owls_brm5b |>
  conditional_effects("FoodTreatment:SexParent") |>
  plot(points = TRUE)

## owls_brm5b |> SUYR_prior_and_posterior()
owls_brm5b |> get_variables()
  [1] "b_Intercept"                                                         
  [2] "b_zi_Intercept"                                                      
  [3] "b_FoodTreatmentSatiated"                                             
  [4] "b_SexParentMale"                                                     
  [5] "b_FoodTreatmentSatiated:SexParentMale"                               
  [6] "b_zi_FoodTreatmentSatiated"                                          
  [7] "b_zi_SexParentMale"                                                  
  [8] "b_zi_FoodTreatmentSatiated:SexParentMale"                            
  [9] "sd_Nest__Intercept"                                                  
 [10] "sd_Nest__FoodTreatmentSatiated"                                      
 [11] "sd_Nest__SexParentMale"                                              
 [12] "sd_Nest__FoodTreatmentSatiated:SexParentMale"                        
 [13] "cor_Nest__Intercept__FoodTreatmentSatiated"                          
 [14] "cor_Nest__Intercept__SexParentMale"                                  
 [15] "cor_Nest__FoodTreatmentSatiated__SexParentMale"                      
 [16] "cor_Nest__Intercept__FoodTreatmentSatiated:SexParentMale"            
 [17] "cor_Nest__FoodTreatmentSatiated__FoodTreatmentSatiated:SexParentMale"
 [18] "cor_Nest__SexParentMale__FoodTreatmentSatiated:SexParentMale"        
 [19] "shape"                                                               
 [20] "Intercept"                                                           
 [21] "Intercept_zi"                                                        
 [22] "r_Nest[AutavauxTV,Intercept]"                                        
 [23] "r_Nest[Bochet,Intercept]"                                            
 [24] "r_Nest[Champmartin,Intercept]"                                       
 [25] "r_Nest[ChEsard,Intercept]"                                           
 [26] "r_Nest[Chevroux,Intercept]"                                          
 [27] "r_Nest[CorcellesFavres,Intercept]"                                   
 [28] "r_Nest[Etrabloz,Intercept]"                                          
 [29] "r_Nest[Forel,Intercept]"                                             
 [30] "r_Nest[Franex,Intercept]"                                            
 [31] "r_Nest[GDLV,Intercept]"                                              
 [32] "r_Nest[Gletterens,Intercept]"                                        
 [33] "r_Nest[Henniez,Intercept]"                                           
 [34] "r_Nest[Jeuss,Intercept]"                                             
 [35] "r_Nest[LesPlanches,Intercept]"                                       
 [36] "r_Nest[Lucens,Intercept]"                                            
 [37] "r_Nest[Lully,Intercept]"                                             
 [38] "r_Nest[Marnand,Intercept]"                                           
 [39] "r_Nest[Montet,Intercept]"                                            
 [40] "r_Nest[Murist,Intercept]"                                            
 [41] "r_Nest[Oleyes,Intercept]"                                            
 [42] "r_Nest[Payerne,Intercept]"                                           
 [43] "r_Nest[Rueyes,Intercept]"                                            
 [44] "r_Nest[Seiry,Intercept]"                                             
 [45] "r_Nest[Sevaz,Intercept]"                                             
 [46] "r_Nest[StAubin,Intercept]"                                           
 [47] "r_Nest[Trey,Intercept]"                                              
 [48] "r_Nest[Yvonnand,Intercept]"                                          
 [49] "r_Nest[AutavauxTV,FoodTreatmentSatiated]"                            
 [50] "r_Nest[Bochet,FoodTreatmentSatiated]"                                
 [51] "r_Nest[Champmartin,FoodTreatmentSatiated]"                           
 [52] "r_Nest[ChEsard,FoodTreatmentSatiated]"                               
 [53] "r_Nest[Chevroux,FoodTreatmentSatiated]"                              
 [54] "r_Nest[CorcellesFavres,FoodTreatmentSatiated]"                       
 [55] "r_Nest[Etrabloz,FoodTreatmentSatiated]"                              
 [56] "r_Nest[Forel,FoodTreatmentSatiated]"                                 
 [57] "r_Nest[Franex,FoodTreatmentSatiated]"                                
 [58] "r_Nest[GDLV,FoodTreatmentSatiated]"                                  
 [59] "r_Nest[Gletterens,FoodTreatmentSatiated]"                            
 [60] "r_Nest[Henniez,FoodTreatmentSatiated]"                               
 [61] "r_Nest[Jeuss,FoodTreatmentSatiated]"                                 
 [62] "r_Nest[LesPlanches,FoodTreatmentSatiated]"                           
 [63] "r_Nest[Lucens,FoodTreatmentSatiated]"                                
 [64] "r_Nest[Lully,FoodTreatmentSatiated]"                                 
 [65] "r_Nest[Marnand,FoodTreatmentSatiated]"                               
 [66] "r_Nest[Montet,FoodTreatmentSatiated]"                                
 [67] "r_Nest[Murist,FoodTreatmentSatiated]"                                
 [68] "r_Nest[Oleyes,FoodTreatmentSatiated]"                                
 [69] "r_Nest[Payerne,FoodTreatmentSatiated]"                               
 [70] "r_Nest[Rueyes,FoodTreatmentSatiated]"                                
 [71] "r_Nest[Seiry,FoodTreatmentSatiated]"                                 
 [72] "r_Nest[Sevaz,FoodTreatmentSatiated]"                                 
 [73] "r_Nest[StAubin,FoodTreatmentSatiated]"                               
 [74] "r_Nest[Trey,FoodTreatmentSatiated]"                                  
 [75] "r_Nest[Yvonnand,FoodTreatmentSatiated]"                              
 [76] "r_Nest[AutavauxTV,SexParentMale]"                                    
 [77] "r_Nest[Bochet,SexParentMale]"                                        
 [78] "r_Nest[Champmartin,SexParentMale]"                                   
 [79] "r_Nest[ChEsard,SexParentMale]"                                       
 [80] "r_Nest[Chevroux,SexParentMale]"                                      
 [81] "r_Nest[CorcellesFavres,SexParentMale]"                               
 [82] "r_Nest[Etrabloz,SexParentMale]"                                      
 [83] "r_Nest[Forel,SexParentMale]"                                         
 [84] "r_Nest[Franex,SexParentMale]"                                        
 [85] "r_Nest[GDLV,SexParentMale]"                                          
 [86] "r_Nest[Gletterens,SexParentMale]"                                    
 [87] "r_Nest[Henniez,SexParentMale]"                                       
 [88] "r_Nest[Jeuss,SexParentMale]"                                         
 [89] "r_Nest[LesPlanches,SexParentMale]"                                   
 [90] "r_Nest[Lucens,SexParentMale]"                                        
 [91] "r_Nest[Lully,SexParentMale]"                                         
 [92] "r_Nest[Marnand,SexParentMale]"                                       
 [93] "r_Nest[Montet,SexParentMale]"                                        
 [94] "r_Nest[Murist,SexParentMale]"                                        
 [95] "r_Nest[Oleyes,SexParentMale]"                                        
 [96] "r_Nest[Payerne,SexParentMale]"                                       
 [97] "r_Nest[Rueyes,SexParentMale]"                                        
 [98] "r_Nest[Seiry,SexParentMale]"                                         
 [99] "r_Nest[Sevaz,SexParentMale]"                                         
[100] "r_Nest[StAubin,SexParentMale]"                                       
[101] "r_Nest[Trey,SexParentMale]"                                          
[102] "r_Nest[Yvonnand,SexParentMale]"                                      
[103] "r_Nest[AutavauxTV,FoodTreatmentSatiated:SexParentMale]"              
[104] "r_Nest[Bochet,FoodTreatmentSatiated:SexParentMale]"                  
[105] "r_Nest[Champmartin,FoodTreatmentSatiated:SexParentMale]"             
[106] "r_Nest[ChEsard,FoodTreatmentSatiated:SexParentMale]"                 
[107] "r_Nest[Chevroux,FoodTreatmentSatiated:SexParentMale]"                
[108] "r_Nest[CorcellesFavres,FoodTreatmentSatiated:SexParentMale]"         
[109] "r_Nest[Etrabloz,FoodTreatmentSatiated:SexParentMale]"                
[110] "r_Nest[Forel,FoodTreatmentSatiated:SexParentMale]"                   
[111] "r_Nest[Franex,FoodTreatmentSatiated:SexParentMale]"                  
[112] "r_Nest[GDLV,FoodTreatmentSatiated:SexParentMale]"                    
[113] "r_Nest[Gletterens,FoodTreatmentSatiated:SexParentMale]"              
[114] "r_Nest[Henniez,FoodTreatmentSatiated:SexParentMale]"                 
[115] "r_Nest[Jeuss,FoodTreatmentSatiated:SexParentMale]"                   
[116] "r_Nest[LesPlanches,FoodTreatmentSatiated:SexParentMale]"             
[117] "r_Nest[Lucens,FoodTreatmentSatiated:SexParentMale]"                  
[118] "r_Nest[Lully,FoodTreatmentSatiated:SexParentMale]"                   
[119] "r_Nest[Marnand,FoodTreatmentSatiated:SexParentMale]"                 
[120] "r_Nest[Montet,FoodTreatmentSatiated:SexParentMale]"                  
[121] "r_Nest[Murist,FoodTreatmentSatiated:SexParentMale]"                  
[122] "r_Nest[Oleyes,FoodTreatmentSatiated:SexParentMale]"                  
[123] "r_Nest[Payerne,FoodTreatmentSatiated:SexParentMale]"                 
[124] "r_Nest[Rueyes,FoodTreatmentSatiated:SexParentMale]"                  
[125] "r_Nest[Seiry,FoodTreatmentSatiated:SexParentMale]"                   
[126] "r_Nest[Sevaz,FoodTreatmentSatiated:SexParentMale]"                   
[127] "r_Nest[StAubin,FoodTreatmentSatiated:SexParentMale]"                 
[128] "r_Nest[Trey,FoodTreatmentSatiated:SexParentMale]"                    
[129] "r_Nest[Yvonnand,FoodTreatmentSatiated:SexParentMale]"                
[130] "prior_Intercept"                                                     
[131] "prior_b"                                                             
[132] "prior_shape"                                                         
[133] "prior_b_zi"                                                          
[134] "prior_Intercept_zi"                                                  
[135] "prior_sd_Nest"                                                       
[136] "prior_cor_Nest"                                                      
[137] "lprior"                                                              
[138] "lp__"                                                                
[139] "accept_stat__"                                                       
[140] "stepsize__"                                                          
[141] "treedepth__"                                                         
[142] "n_leapfrog__"                                                        
[143] "divergent__"                                                         
[144] "energy__"                                                            
pars <- owls_brm5b |> get_variables()
pars <- str_extract(pars, "^b_.*|^sigma$|^sd.*") |> na.omit()

owls_brm5b$fit |>
  stan_trace(pars = pars)

owls_brm5b$fit |>
  stan_ac(pars = pars)

owls_brm5b$fit |> stan_rhat()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

owls_brm5b$fit |> stan_ess()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

owls_brm5b$fit |>
  stan_dens(separate_chains = TRUE, pars = pars)

owls_brm5b |> pp_check(type = "dens_overlay", ndraws = 100)

## owls_brm5b |> pp_check(type = 'error_scatter_avg')
owls_brm5b |> pp_check(group = "Nest", type = "intervals")
Using all posterior draws for ppc type 'intervals' by default.
Warning: The following arguments were unrecognized and ignored: group

owls_resids <- make_brms_dharma_res(owls_brm5b, integerResponse = TRUE)
wrap_elements(~ testUniformity(owls_resids)) +
  wrap_elements(~ plotResiduals(owls_resids, form = factor(rep(1, nrow(owls))))) +
  wrap_elements(~ plotResiduals(owls_resids, quantreg = TRUE)) +
  wrap_elements(~ testDispersion(owls_resids))

(loo_3 <- loo::loo(owls_brm3b))

Computed from 750 by 599 log-likelihood matrix.

         Estimate   SE
elpd_loo  -1714.5 26.9
p_loo        17.9  1.5
looic      3429.0 53.8
------
MCSE of elpd_loo is 0.2.
MCSE and ESS estimates assume MCMC draws (r_eff in [0.8, 1.2]).

All Pareto k estimates are good (k < 0.65).
See help('pareto-k-diagnostic') for details.
(loo_4 <- loo::loo(owls_brm4b))
Warning: Found 1 observations with a pareto_k > 0.7 in model 'owls_brm4b'. We
recommend to set 'moment_match = TRUE' in order to perform moment matching for
problematic observations.

Computed from 750 by 599 log-likelihood matrix.

         Estimate   SE
elpd_loo  -1709.9 27.4
p_loo        23.0  2.3
looic      3419.8 54.8
------
MCSE of elpd_loo is NA.
MCSE and ESS estimates assume MCMC draws (r_eff in [0.6, 1.2]).

Pareto k diagnostic values:
                          Count Pct.    Min. ESS
(-Inf, 0.65]   (good)     598   99.8%   248     
   (0.65, 1]   (bad)        1    0.2%   <NA>    
    (1, Inf)   (very bad)   0    0.0%   <NA>    
See help('pareto-k-diagnostic') for details.
(loo_5 <- loo::loo(owls_brm5b))
Warning: Found 7 observations with a pareto_k > 0.65 in model 'owls_brm5b'. We
recommend to run more iterations to get at least about 2200 posterior draws to
improve LOO-CV approximation accuracy.

Computed from 750 by 599 log-likelihood matrix.

         Estimate   SE
elpd_loo  -1656.8 29.0
p_loo        50.0  4.0
looic      3313.6 58.0
------
MCSE of elpd_loo is NA.
MCSE and ESS estimates assume MCMC draws (r_eff in [0.6, 1.2]).

Pareto k diagnostic values:
                          Count Pct.    Min. ESS
(-Inf, 0.65]   (good)     592   98.8%   82      
   (0.65, 1]   (bad)        7    1.2%   <NA>    
    (1, Inf)   (very bad)   0    0.0%   <NA>    
See help('pareto-k-diagnostic') for details.
loo::loo_compare(loo_3, loo_4, loo_5)
           elpd_diff se_diff
owls_brm5b   0.0       0.0  
owls_brm4b -53.1       9.1  
owls_brm3b -57.7       9.8  

Conclusions: - evidently, the zero-inflated negative binomial model with random intercepts/slopes (owls_brm5b) is the best model…

7 Partial effects plots

owls_brm5b |>
  conditional_effects("FoodTreatment:SexParent") |>
  plot(points = TRUE, jitter_width = 0.25)
Warning: 'jitter_width' is deprecated. Please use 'point_args = list(width =
<width>)' instead.

## If we want to present the conditional effects on the scale of calls
## per chick, then we need to condition on a broodsize of 1
owls_brm5b |>
  conditional_effects("FoodTreatment:SexParent", conditions = list(BroodSize = 1))

These predictions appear to be based on the mean BroodSize of approximately 4.39. That is, the predictions are for a nest, not per chick. There does not appear to be a way to indicate the offset value.

owls_brm5b |>
  ggpredict(~ FoodTreatment * SexParent) |>
  plot(show_data = TRUE, jitter = c(0.25, 0))
Note: uncertainty of error terms are not taken into account. Consider
  setting `interval` to "prediction". This will call `posterior_predict()`
  instead of `posterior_epred()`.
Warning in glmmTMB::glmmTMB(formula = cond_formula, ziformula = ziformula, :
some components missing from 'family': downstream methods may fail
Warning in glmmTMB::glmmTMB(formula = cond_formula, ziformula = ziformula, :
some components missing from 'family': downstream methods may fail

These predictions appear to be based on the mean BroodSize of approximately 4.39. That is, the predictions are for a nest, not per chick. There does not appear to be a way to indicate the offset value.

ggemmeans() can accommodate the offset correctly. There are two sensible choices:

  • set the offset to the (log) of the mean BroodSize (similar to other partial effects), hence giving predictions appropriate for the average brood size conclusion.
off <- owls |> summarize(Mean = mean(BroodSize))
owls_brm5b |>
  ggemmeans(~ FoodTreatment * SexParent, offset = log(off$Mean)) |>
  plot()
Warning in glmmTMB::glmmTMB(formula = cond_formula, ziformula = ziformula, :
some components missing from 'family': downstream methods may fail
Warning in glmmTMB::glmmTMB(formula = cond_formula, ziformula = ziformula, :
some components missing from 'family': downstream methods may fail
Warning in glmmTMB::glmmTMB(formula = cond_formula, ziformula = ziformula, :
some components missing from 'family': downstream methods may fail
Warning in glmmTMB::glmmTMB(formula = cond_formula, ziformula = ziformula, :
some components missing from 'family': downstream methods may fail

8 Model investigation

The summary() method generates simple summaries (mean, standard deviation as well as 10, 50 and 90 percentiles).

owls_brm5b |> summary()
 Family: zero_inflated_negbinomial 
  Links: mu = log; shape = identity; zi = logit 
Formula: NCalls ~ FoodTreatment * SexParent + offset(log(BroodSize)) + (FoodTreatment * SexParent | Nest) 
         zi ~ FoodTreatment * SexParent
   Data: owls (Number of observations: 599) 
  Draws: 3 chains, each with iter = 5000; warmup = 2500; thin = 10;
         total post-warmup draws = 750

Multilevel Hyperparameters:
~Nest (Number of levels: 27) 
                                                               Estimate
sd(Intercept)                                                      0.31
sd(FoodTreatmentSatiated)                                          1.10
sd(SexParentMale)                                                  0.17
sd(FoodTreatmentSatiated:SexParentMale)                            0.34
cor(Intercept,FoodTreatmentSatiated)                               0.10
cor(Intercept,SexParentMale)                                      -0.17
cor(FoodTreatmentSatiated,SexParentMale)                          -0.21
cor(Intercept,FoodTreatmentSatiated:SexParentMale)                -0.10
cor(FoodTreatmentSatiated,FoodTreatmentSatiated:SexParentMale)    -0.04
cor(SexParentMale,FoodTreatmentSatiated:SexParentMale)            -0.10
                                                               Est.Error
sd(Intercept)                                                       0.09
sd(FoodTreatmentSatiated)                                           0.27
sd(SexParentMale)                                                   0.11
sd(FoodTreatmentSatiated:SexParentMale)                             0.22
cor(Intercept,FoodTreatmentSatiated)                                0.28
cor(Intercept,SexParentMale)                                        0.42
cor(FoodTreatmentSatiated,SexParentMale)                            0.40
cor(Intercept,FoodTreatmentSatiated:SexParentMale)                  0.40
cor(FoodTreatmentSatiated,FoodTreatmentSatiated:SexParentMale)      0.43
cor(SexParentMale,FoodTreatmentSatiated:SexParentMale)              0.46
                                                               l-95% CI
sd(Intercept)                                                      0.14
sd(FoodTreatmentSatiated)                                          0.60
sd(SexParentMale)                                                  0.01
sd(FoodTreatmentSatiated:SexParentMale)                            0.02
cor(Intercept,FoodTreatmentSatiated)                              -0.44
cor(Intercept,SexParentMale)                                      -0.83
cor(FoodTreatmentSatiated,SexParentMale)                          -0.87
cor(Intercept,FoodTreatmentSatiated:SexParentMale)                -0.83
cor(FoodTreatmentSatiated,FoodTreatmentSatiated:SexParentMale)    -0.78
cor(SexParentMale,FoodTreatmentSatiated:SexParentMale)            -0.88
                                                               u-95% CI Rhat
sd(Intercept)                                                      0.50 1.00
sd(FoodTreatmentSatiated)                                          1.67 1.00
sd(SexParentMale)                                                  0.43 1.00
sd(FoodTreatmentSatiated:SexParentMale)                            0.83 1.00
cor(Intercept,FoodTreatmentSatiated)                               0.63 1.00
cor(Intercept,SexParentMale)                                       0.71 1.00
cor(FoodTreatmentSatiated,SexParentMale)                           0.65 1.00
cor(Intercept,FoodTreatmentSatiated:SexParentMale)                 0.63 1.00
cor(FoodTreatmentSatiated,FoodTreatmentSatiated:SexParentMale)     0.73 1.01
cor(SexParentMale,FoodTreatmentSatiated:SexParentMale)             0.81 1.00
                                                               Bulk_ESS
sd(Intercept)                                                       714
sd(FoodTreatmentSatiated)                                           784
sd(SexParentMale)                                                   866
sd(FoodTreatmentSatiated:SexParentMale)                             687
cor(Intercept,FoodTreatmentSatiated)                                637
cor(Intercept,SexParentMale)                                        657
cor(FoodTreatmentSatiated,SexParentMale)                            722
cor(Intercept,FoodTreatmentSatiated:SexParentMale)                  806
cor(FoodTreatmentSatiated,FoodTreatmentSatiated:SexParentMale)      851
cor(SexParentMale,FoodTreatmentSatiated:SexParentMale)              808
                                                               Tail_ESS
sd(Intercept)                                                       680
sd(FoodTreatmentSatiated)                                           656
sd(SexParentMale)                                                   683
sd(FoodTreatmentSatiated:SexParentMale)                             543
cor(Intercept,FoodTreatmentSatiated)                                677
cor(Intercept,SexParentMale)                                        717
cor(FoodTreatmentSatiated,SexParentMale)                            756
cor(Intercept,FoodTreatmentSatiated:SexParentMale)                  527
cor(FoodTreatmentSatiated,FoodTreatmentSatiated:SexParentMale)      694
cor(SexParentMale,FoodTreatmentSatiated:SexParentMale)              730

Regression Coefficients:
                                       Estimate Est.Error l-95% CI u-95% CI
Intercept                                  0.83      0.10     0.63     1.03
zi_Intercept                              -1.59      0.25    -2.09    -1.14
FoodTreatmentSatiated                     -0.68      0.26    -1.25    -0.18
SexParentMale                             -0.09      0.11    -0.30     0.14
FoodTreatmentSatiated:SexParentMale        0.10      0.20    -0.31     0.47
zi_FoodTreatmentSatiated                   0.83      0.34     0.21     1.52
zi_SexParentMale                          -0.81      0.35    -1.51    -0.12
zi_FoodTreatmentSatiated:SexParentMale     0.60      0.43    -0.18     1.48
                                       Rhat Bulk_ESS Tail_ESS
Intercept                              1.00      766      675
zi_Intercept                           1.00      553      758
FoodTreatmentSatiated                  1.00      813      717
SexParentMale                          1.00      812      801
FoodTreatmentSatiated:SexParentMale    1.00      723      578
zi_FoodTreatmentSatiated               1.00      644      671
zi_SexParentMale                       1.00      608      682
zi_FoodTreatmentSatiated:SexParentMale 1.00      742      711

Further Distributional Parameters:
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape     2.74      0.32     2.19     3.44 1.00      696      606

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).

Conclusions:

  • the average number of calls made per food deprived owl chicks when the female parent returns to the nest is 0.83 (on the link scale). When back-transformed, this is 2.28.
  • on average, satiated chicks negotiate -1 (link scale) less when the female returns than deprived chicks. This equates to 0.51 fold fewer times and represents a 49% decline.
  • on average, when the male parent returns, deprived chicks negotiate 0 (link scale) less when the female returns. This equates to 0.91 fold fewer times and represents a 9% decline (although this is not significant).
  • there was not significantly detectable interaction suggesting that the effect of food treatment was consistent across both parents and vice versa.
  • the estimated rate of non-detection of calls (false zeros) for deprived chicks when the female parent returns is -1.59 (logit scale). When back-transformed to the odds scale, this equates to the odds of a zero being false are 0.2:1. Expressed on a probability scale, it would suggest that the probability of a zero being false is 0.17.
  • when the chicks are satiated, the odds not detecting a call (false zero) are increased 2.3 fold. That is, the odds increase by 30.33%.
  • when the returning parent is male (for deprived chicks), the odds of not detecting a call (false zeros) are reduced 0.45 fold. That is, the odds decline by 69.13%.
  • there is substantially more variation in sibling negotiations between food treatment effects within a nest than either between nests or between the sex of the parent effects within nests.
  • variation in the sex of the parent effect is slightly negatively correlated to the variation between nests
  • variation in the sex of the parent effect is negatively correlated to the variation in the interaction effect.
# A draws_df: 250 iterations, 3 chains, and 138 variables
   b_Intercept b_zi_Intercept b_FoodTreatmentSatiated b_SexParentMale
1         0.81           -1.8                   -0.93           0.085
2         0.72           -1.7                   -1.03           0.019
3         0.76           -1.4                   -0.74          -0.045
4         0.78           -1.6                   -0.78          -0.077
5         0.62           -2.0                   -0.64           0.012
6         0.93           -1.6                   -0.73          -0.228
7         0.92           -1.4                   -0.56          -0.243
8         0.97           -1.6                   -0.61          -0.216
9         0.86           -1.6                   -0.49          -0.158
10        0.79           -1.6                   -0.92           0.023
   b_FoodTreatmentSatiated:SexParentMale b_zi_FoodTreatmentSatiated
1                                 -0.032                       0.79
2                                  0.313                       0.91
3                                  0.134                       0.74
4                                  0.332                       1.23
5                                 -0.131                       0.93
6                                 -0.134                       0.87
7                                  0.070                       0.52
8                                  0.129                       1.37
9                                 -0.111                       0.78
10                                 0.146                       0.58
   b_zi_SexParentMale b_zi_FoodTreatmentSatiated:SexParentMale
1               -0.41                                    0.574
2               -0.78                                    0.719
3               -1.03                                    0.610
4               -0.59                                    0.231
5               -0.71                                    0.609
6               -0.96                                    0.647
7               -0.78                                    0.590
8               -0.63                                    0.018
9               -0.62                                    0.580
10              -1.28                                    1.123
# ... with 740 more draws, and 130 more variables
# ... hidden reserved variables {'.chain', '.iteration', '.draw'}
# A tibble: 138 × 10
   variable    median lower upper      Pl      Pg  rhat length ess_bulk ess_tail
   <chr>        <dbl> <dbl> <dbl>   <dbl>   <dbl> <dbl>  <dbl>    <dbl>    <dbl>
 1 b_Intercept  2.28  1.86  2.78  0       1       1.00     750     766.     675.
 2 b_zi_Inter…  0.208 0.116 0.306 1       0       1.00     750     554.     758.
 3 b_FoodTrea…  0.507 0.252 0.778 0.996   0.004   1.000    750     813.     717.
 4 b_SexParen…  0.913 0.732 1.12  0.791   0.209   1.00     750     812.     801.
 5 b_FoodTrea…  1.10  0.732 1.59  0.279   0.721   0.999    750     722.     578.
 6 b_zi_FoodT…  2.25  1.12  4.18  0.00267 0.997   1.00     750     644.     671.
 7 b_zi_SexPa…  0.455 0.170 0.800 0.991   0.00933 1.00     750     610.     682.
 8 b_zi_FoodT…  1.83  0.728 3.85  0.0827  0.917   1.000    750     742.     711.
 9 sd_Nest__I…  1.35  1.15  1.64  0       1       1.00     750     715.     680.
10 sd_Nest__F…  2.94  1.76  5.10  0       1       1.00     750     783.     656.
# ℹ 128 more rows
[1] 0.1701245
[1] 0.3166131
[1] 0.08428682

~17% of zeros are false zeros = 1/detectability

owls_brm5b$fit |>
  tidyMCMC(
    estimate.method = "median",
    conf.int = TRUE, conf.method = "HPDinterval",
    rhat = TRUE, ess = TRUE
  )
# A tibble: 137 × 7
   term                        estimate std.error conf.low conf.high  rhat   ess
   <chr>                          <dbl>     <dbl>    <dbl>     <dbl> <dbl> <int>
 1 b_Intercept                   0.826     0.104     0.621    1.02   0.998   751
 2 b_zi_Intercept               -1.59      0.248    -2.09    -1.14   1.00    501
 3 b_FoodTreatmentSatiated      -0.681     0.262    -1.17    -0.132  0.997   798
 4 b_SexParentMale              -0.0899    0.110    -0.312    0.115  0.997   807
 5 b_FoodTreatmentSatiated:Se…   0.100     0.200    -0.312    0.462  0.998   693
 6 b_zi_FoodTreatmentSatiated    0.831     0.337     0.179    1.47   1.00    622
 7 b_zi_SexParentMale           -0.806     0.354    -1.44    -0.0801 1.00    571
 8 b_zi_FoodTreatmentSatiated…   0.604     0.428    -0.203    1.42   0.998   731
 9 sd_Nest__Intercept            0.310     0.0946    0.153    0.506  0.997   699
10 sd_Nest__FoodTreatmentSati…   1.10      0.273     0.577    1.64   1.00    726
# ℹ 127 more rows

Conclusions:

see above

Due to the presence of a log transform in the predictor, it is better to use the regex version.

owls_brm5b |> get_variables()
  [1] "b_Intercept"                                                         
  [2] "b_zi_Intercept"                                                      
  [3] "b_FoodTreatmentSatiated"                                             
  [4] "b_SexParentMale"                                                     
  [5] "b_FoodTreatmentSatiated:SexParentMale"                               
  [6] "b_zi_FoodTreatmentSatiated"                                          
  [7] "b_zi_SexParentMale"                                                  
  [8] "b_zi_FoodTreatmentSatiated:SexParentMale"                            
  [9] "sd_Nest__Intercept"                                                  
 [10] "sd_Nest__FoodTreatmentSatiated"                                      
 [11] "sd_Nest__SexParentMale"                                              
 [12] "sd_Nest__FoodTreatmentSatiated:SexParentMale"                        
 [13] "cor_Nest__Intercept__FoodTreatmentSatiated"                          
 [14] "cor_Nest__Intercept__SexParentMale"                                  
 [15] "cor_Nest__FoodTreatmentSatiated__SexParentMale"                      
 [16] "cor_Nest__Intercept__FoodTreatmentSatiated:SexParentMale"            
 [17] "cor_Nest__FoodTreatmentSatiated__FoodTreatmentSatiated:SexParentMale"
 [18] "cor_Nest__SexParentMale__FoodTreatmentSatiated:SexParentMale"        
 [19] "shape"                                                               
 [20] "Intercept"                                                           
 [21] "Intercept_zi"                                                        
 [22] "r_Nest[AutavauxTV,Intercept]"                                        
 [23] "r_Nest[Bochet,Intercept]"                                            
 [24] "r_Nest[Champmartin,Intercept]"                                       
 [25] "r_Nest[ChEsard,Intercept]"                                           
 [26] "r_Nest[Chevroux,Intercept]"                                          
 [27] "r_Nest[CorcellesFavres,Intercept]"                                   
 [28] "r_Nest[Etrabloz,Intercept]"                                          
 [29] "r_Nest[Forel,Intercept]"                                             
 [30] "r_Nest[Franex,Intercept]"                                            
 [31] "r_Nest[GDLV,Intercept]"                                              
 [32] "r_Nest[Gletterens,Intercept]"                                        
 [33] "r_Nest[Henniez,Intercept]"                                           
 [34] "r_Nest[Jeuss,Intercept]"                                             
 [35] "r_Nest[LesPlanches,Intercept]"                                       
 [36] "r_Nest[Lucens,Intercept]"                                            
 [37] "r_Nest[Lully,Intercept]"                                             
 [38] "r_Nest[Marnand,Intercept]"                                           
 [39] "r_Nest[Montet,Intercept]"                                            
 [40] "r_Nest[Murist,Intercept]"                                            
 [41] "r_Nest[Oleyes,Intercept]"                                            
 [42] "r_Nest[Payerne,Intercept]"                                           
 [43] "r_Nest[Rueyes,Intercept]"                                            
 [44] "r_Nest[Seiry,Intercept]"                                             
 [45] "r_Nest[Sevaz,Intercept]"                                             
 [46] "r_Nest[StAubin,Intercept]"                                           
 [47] "r_Nest[Trey,Intercept]"                                              
 [48] "r_Nest[Yvonnand,Intercept]"                                          
 [49] "r_Nest[AutavauxTV,FoodTreatmentSatiated]"                            
 [50] "r_Nest[Bochet,FoodTreatmentSatiated]"                                
 [51] "r_Nest[Champmartin,FoodTreatmentSatiated]"                           
 [52] "r_Nest[ChEsard,FoodTreatmentSatiated]"                               
 [53] "r_Nest[Chevroux,FoodTreatmentSatiated]"                              
 [54] "r_Nest[CorcellesFavres,FoodTreatmentSatiated]"                       
 [55] "r_Nest[Etrabloz,FoodTreatmentSatiated]"                              
 [56] "r_Nest[Forel,FoodTreatmentSatiated]"                                 
 [57] "r_Nest[Franex,FoodTreatmentSatiated]"                                
 [58] "r_Nest[GDLV,FoodTreatmentSatiated]"                                  
 [59] "r_Nest[Gletterens,FoodTreatmentSatiated]"                            
 [60] "r_Nest[Henniez,FoodTreatmentSatiated]"                               
 [61] "r_Nest[Jeuss,FoodTreatmentSatiated]"                                 
 [62] "r_Nest[LesPlanches,FoodTreatmentSatiated]"                           
 [63] "r_Nest[Lucens,FoodTreatmentSatiated]"                                
 [64] "r_Nest[Lully,FoodTreatmentSatiated]"                                 
 [65] "r_Nest[Marnand,FoodTreatmentSatiated]"                               
 [66] "r_Nest[Montet,FoodTreatmentSatiated]"                                
 [67] "r_Nest[Murist,FoodTreatmentSatiated]"                                
 [68] "r_Nest[Oleyes,FoodTreatmentSatiated]"                                
 [69] "r_Nest[Payerne,FoodTreatmentSatiated]"                               
 [70] "r_Nest[Rueyes,FoodTreatmentSatiated]"                                
 [71] "r_Nest[Seiry,FoodTreatmentSatiated]"                                 
 [72] "r_Nest[Sevaz,FoodTreatmentSatiated]"                                 
 [73] "r_Nest[StAubin,FoodTreatmentSatiated]"                               
 [74] "r_Nest[Trey,FoodTreatmentSatiated]"                                  
 [75] "r_Nest[Yvonnand,FoodTreatmentSatiated]"                              
 [76] "r_Nest[AutavauxTV,SexParentMale]"                                    
 [77] "r_Nest[Bochet,SexParentMale]"                                        
 [78] "r_Nest[Champmartin,SexParentMale]"                                   
 [79] "r_Nest[ChEsard,SexParentMale]"                                       
 [80] "r_Nest[Chevroux,SexParentMale]"                                      
 [81] "r_Nest[CorcellesFavres,SexParentMale]"                               
 [82] "r_Nest[Etrabloz,SexParentMale]"                                      
 [83] "r_Nest[Forel,SexParentMale]"                                         
 [84] "r_Nest[Franex,SexParentMale]"                                        
 [85] "r_Nest[GDLV,SexParentMale]"                                          
 [86] "r_Nest[Gletterens,SexParentMale]"                                    
 [87] "r_Nest[Henniez,SexParentMale]"                                       
 [88] "r_Nest[Jeuss,SexParentMale]"                                         
 [89] "r_Nest[LesPlanches,SexParentMale]"                                   
 [90] "r_Nest[Lucens,SexParentMale]"                                        
 [91] "r_Nest[Lully,SexParentMale]"                                         
 [92] "r_Nest[Marnand,SexParentMale]"                                       
 [93] "r_Nest[Montet,SexParentMale]"                                        
 [94] "r_Nest[Murist,SexParentMale]"                                        
 [95] "r_Nest[Oleyes,SexParentMale]"                                        
 [96] "r_Nest[Payerne,SexParentMale]"                                       
 [97] "r_Nest[Rueyes,SexParentMale]"                                        
 [98] "r_Nest[Seiry,SexParentMale]"                                         
 [99] "r_Nest[Sevaz,SexParentMale]"                                         
[100] "r_Nest[StAubin,SexParentMale]"                                       
[101] "r_Nest[Trey,SexParentMale]"                                          
[102] "r_Nest[Yvonnand,SexParentMale]"                                      
[103] "r_Nest[AutavauxTV,FoodTreatmentSatiated:SexParentMale]"              
[104] "r_Nest[Bochet,FoodTreatmentSatiated:SexParentMale]"                  
[105] "r_Nest[Champmartin,FoodTreatmentSatiated:SexParentMale]"             
[106] "r_Nest[ChEsard,FoodTreatmentSatiated:SexParentMale]"                 
[107] "r_Nest[Chevroux,FoodTreatmentSatiated:SexParentMale]"                
[108] "r_Nest[CorcellesFavres,FoodTreatmentSatiated:SexParentMale]"         
[109] "r_Nest[Etrabloz,FoodTreatmentSatiated:SexParentMale]"                
[110] "r_Nest[Forel,FoodTreatmentSatiated:SexParentMale]"                   
[111] "r_Nest[Franex,FoodTreatmentSatiated:SexParentMale]"                  
[112] "r_Nest[GDLV,FoodTreatmentSatiated:SexParentMale]"                    
[113] "r_Nest[Gletterens,FoodTreatmentSatiated:SexParentMale]"              
[114] "r_Nest[Henniez,FoodTreatmentSatiated:SexParentMale]"                 
[115] "r_Nest[Jeuss,FoodTreatmentSatiated:SexParentMale]"                   
[116] "r_Nest[LesPlanches,FoodTreatmentSatiated:SexParentMale]"             
[117] "r_Nest[Lucens,FoodTreatmentSatiated:SexParentMale]"                  
[118] "r_Nest[Lully,FoodTreatmentSatiated:SexParentMale]"                   
[119] "r_Nest[Marnand,FoodTreatmentSatiated:SexParentMale]"                 
[120] "r_Nest[Montet,FoodTreatmentSatiated:SexParentMale]"                  
[121] "r_Nest[Murist,FoodTreatmentSatiated:SexParentMale]"                  
[122] "r_Nest[Oleyes,FoodTreatmentSatiated:SexParentMale]"                  
[123] "r_Nest[Payerne,FoodTreatmentSatiated:SexParentMale]"                 
[124] "r_Nest[Rueyes,FoodTreatmentSatiated:SexParentMale]"                  
[125] "r_Nest[Seiry,FoodTreatmentSatiated:SexParentMale]"                   
[126] "r_Nest[Sevaz,FoodTreatmentSatiated:SexParentMale]"                   
[127] "r_Nest[StAubin,FoodTreatmentSatiated:SexParentMale]"                 
[128] "r_Nest[Trey,FoodTreatmentSatiated:SexParentMale]"                    
[129] "r_Nest[Yvonnand,FoodTreatmentSatiated:SexParentMale]"                
[130] "prior_Intercept"                                                     
[131] "prior_b"                                                             
[132] "prior_shape"                                                         
[133] "prior_b_zi"                                                          
[134] "prior_Intercept_zi"                                                  
[135] "prior_sd_Nest"                                                       
[136] "prior_cor_Nest"                                                      
[137] "lprior"                                                              
[138] "lp__"                                                                
[139] "accept_stat__"                                                       
[140] "stepsize__"                                                          
[141] "treedepth__"                                                         
[142] "n_leapfrog__"                                                        
[143] "divergent__"                                                         
[144] "energy__"                                                            
owls_draw <- owls_brm5b |>
  gather_draws(`b.Intercept.*|b_FoodTreatment.*|b_SexParent.*`, regex = TRUE)
owls_draw
# A tibble: 3,000 × 5
# Groups:   .variable [4]
   .chain .iteration .draw .variable   .value
    <int>      <int> <int> <chr>        <dbl>
 1      1          1     1 b_Intercept  0.808
 2      1          2     2 b_Intercept  0.720
 3      1          3     3 b_Intercept  0.764
 4      1          4     4 b_Intercept  0.783
 5      1          5     5 b_Intercept  0.620
 6      1          6     6 b_Intercept  0.929
 7      1          7     7 b_Intercept  0.918
 8      1          8     8 b_Intercept  0.965
 9      1          9     9 b_Intercept  0.860
10      1         10    10 b_Intercept  0.787
# ℹ 2,990 more rows

We can then summarise this

owls_draw |> median_hdci()
# A tibble: 4 × 7
  .variable                         .value .lower .upper .width .point .interval
  <chr>                              <dbl>  <dbl>  <dbl>  <dbl> <chr>  <chr>    
1 b_FoodTreatmentSatiated          -0.679  -1.18  -0.132   0.95 median hdci     
2 b_FoodTreatmentSatiated:SexPare…  0.0993 -0.314  0.462   0.95 median hdci     
3 b_Intercept                       0.824   0.620  1.02    0.95 median hdci     
4 b_SexParentMale                  -0.0912 -0.312  0.117   0.95 median hdci     
## On a fractional scale
owls_draw |>
  mutate(.value = exp(.value)) |>
  median_hdci()
# A tibble: 4 × 7
  .variable                         .value .lower .upper .width .point .interval
  <chr>                              <dbl>  <dbl>  <dbl>  <dbl> <chr>  <chr>    
1 b_FoodTreatmentSatiated            0.507  0.252  0.781   0.95 median hdci     
2 b_FoodTreatmentSatiated:SexParen…  1.10   0.704  1.57    0.95 median hdci     
3 b_Intercept                        2.28   1.86   2.78    0.95 median hdci     
4 b_SexParentMale                    0.913  0.719  1.11    0.95 median hdci     

Lets plot the parameter posteriors (on the link scale - since we are including the intercept).

owls_brm5b |>
  gather_draws(`b_Intercept.*|b_FoodTreatment.*|b_SexParent.*`, regex = TRUE) |>
  ## mutate(.value = exp(.value)) |>
  ggplot() +
  geom_vline(xintercept = 0, linetype = "dashed") +
  stat_slab(aes(
    x = .value, y = .variable,
    fill = stat(ggdist::cut_cdf_qi(cdf,
      .width = c(0.5, 0.8, 0.95),
      labels = scales::percent_format()
    ))
  ), color = "black") +
  scale_fill_brewer("Interval", direction = -1, na.translate = FALSE)
Warning: `stat(ggdist::cut_cdf_qi(cdf, .width = c(0.5, 0.8, 0.95), labels =
scales::percent_format()))` was deprecated in ggplot2 3.4.0.
ℹ Please use `after_stat(ggdist::cut_cdf_qi(cdf, .width = c(0.5, 0.8, 0.95),
  labels = scales::percent_format()))` instead.

owls_brm5b |>
  gather_draws(`.Intercept.*|b_FoodTreatment.*|b_SexParent.*`, regex = TRUE) |>
  ggplot() +
  geom_vline(xintercept = 0, linetype = "dashed") +
  stat_halfeye(aes(x = .value, y = .variable)) +
  theme_classic()

owls_brm5b$fit |> plot(type = "intervals")
'pars' not specified. Showing first 10 parameters by default.
ci_level: 0.8 (80% intervals)
outer_level: 0.95 (95% intervals)

owls_brm5b |>
  gather_draws(`^b_.*`, regex = TRUE) |>
  filter(.variable != "b_Intercept") |>
  ggplot() +
  stat_halfeye(aes(x = .value, y = .variable)) +
  facet_wrap(~.variable, scales = "free") +
  theme(axis.text.y = element_blank())

owls_brm5b |>
  gather_draws(`^b_.*`, regex = TRUE) |>
  filter(.variable != "b_Intercept") |>
  ggplot() +
  stat_halfeye(aes(x = .value, y = .variable)) +
  geom_vline(xintercept = 0, linetype = "dashed")

owls_brm5b |>
  gather_draws(`^b_.*`, regex = TRUE) |>
  filter(str_detect(.variable, "b_.*Intercept", negate = TRUE)) |>
  ggplot() +
  geom_density_ridges(aes(x = .value, y = .variable), alpha = 0.4) +
  geom_vline(xintercept = 0, linetype = "dashed")
Picking joint bandwidth of 0.0649

## Or in colour
owls_brm5b |>
  gather_draws(`^b_.*`, regex = TRUE) |>
  filter(str_detect(.variable, "b_.*Intercept", negate = TRUE)) |>
  ggplot() +
  geom_density_ridges_gradient(
    aes(
      x = (.value),
      y = .variable,
      fill = stat(x)
    ),
    alpha = 0.4, colour = "white",
    quantile_lines = TRUE,
    quantiles = c(0.025, 0.975)
  ) +
  geom_vline(xintercept = 1, linetype = "dashed") +
  scale_x_continuous() +
  scale_fill_viridis_c(option = "C")
Picking joint bandwidth of 0.0649

## Fractional scale
owls_brm5b |>
  gather_draws(`^b_.*`, regex = TRUE) |>
  filter(str_detect(.variable, "b_.*Intercept", negate = TRUE)) |>
  ggplot() +
  geom_density_ridges_gradient(
    aes(
      x = exp(.value),
      y = .variable,
      fill = stat(x)
    ),
    alpha = 0.4, colour = "white",
    quantile_lines = TRUE,
    quantiles = c(0.025, 0.975)
  ) +
  geom_vline(xintercept = 1, linetype = "dashed") +
  scale_x_continuous(trans = scales::log2_trans()) +
  scale_fill_viridis_c(option = "C")
Picking joint bandwidth of 0.0937

This is purely a graphical depiction on the posteriors.

owls_brm5b |> tidy_draws()
# A tibble: 750 × 147
   .chain .iteration .draw b_Intercept b_zi_Intercept b_FoodTreatmentSatiated
    <int>      <int> <int>       <dbl>          <dbl>                   <dbl>
 1      1          1     1       0.808          -1.83                  -0.932
 2      1          2     2       0.720          -1.72                  -1.03 
 3      1          3     3       0.764          -1.35                  -0.739
 4      1          4     4       0.783          -1.62                  -0.785
 5      1          5     5       0.620          -1.97                  -0.644
 6      1          6     6       0.929          -1.57                  -0.731
 7      1          7     7       0.918          -1.42                  -0.558
 8      1          8     8       0.965          -1.57                  -0.612
 9      1          9     9       0.860          -1.62                  -0.490
10      1         10    10       0.787          -1.65                  -0.919
# ℹ 740 more rows
# ℹ 141 more variables: b_SexParentMale <dbl>,
#   `b_FoodTreatmentSatiated:SexParentMale` <dbl>,
#   b_zi_FoodTreatmentSatiated <dbl>, b_zi_SexParentMale <dbl>,
#   `b_zi_FoodTreatmentSatiated:SexParentMale` <dbl>, sd_Nest__Intercept <dbl>,
#   sd_Nest__FoodTreatmentSatiated <dbl>, sd_Nest__SexParentMale <dbl>,
#   `sd_Nest__FoodTreatmentSatiated:SexParentMale` <dbl>, …
owls_brm5b |> spread_draws(`.*Intercept.*|b_FoodTreatment.*|b_SexParent.*`, regex = TRUE)
# A tibble: 750 × 43
   .chain .iteration .draw b_Intercept b_zi_Intercept b_FoodTreatmentSatiated
    <int>      <int> <int>       <dbl>          <dbl>                   <dbl>
 1      1          1     1       0.808          -1.83                  -0.932
 2      1          2     2       0.720          -1.72                  -1.03 
 3      1          3     3       0.764          -1.35                  -0.739
 4      1          4     4       0.783          -1.62                  -0.785
 5      1          5     5       0.620          -1.97                  -0.644
 6      1          6     6       0.929          -1.57                  -0.731
 7      1          7     7       0.918          -1.42                  -0.558
 8      1          8     8       0.965          -1.57                  -0.612
 9      1          9     9       0.860          -1.62                  -0.490
10      1         10    10       0.787          -1.65                  -0.919
# ℹ 740 more rows
# ℹ 37 more variables: b_SexParentMale <dbl>,
#   `b_FoodTreatmentSatiated:SexParentMale` <dbl>, sd_Nest__Intercept <dbl>,
#   cor_Nest__Intercept__FoodTreatmentSatiated <dbl>,
#   cor_Nest__Intercept__SexParentMale <dbl>,
#   `cor_Nest__Intercept__FoodTreatmentSatiated:SexParentMale` <dbl>,
#   Intercept <dbl>, Intercept_zi <dbl>, …
owls_brm5b |>
  posterior_samples() |>
  as_tibble()
Warning: Method 'posterior_samples' is deprecated. Please see ?as_draws for
recommended alternatives.
# A tibble: 750 × 138
   b_Intercept b_zi_Intercept b_FoodTreatmentSatiated b_SexParentMale
         <dbl>          <dbl>                   <dbl>           <dbl>
 1       0.808          -1.83                  -0.932          0.0850
 2       0.720          -1.72                  -1.03           0.0189
 3       0.764          -1.35                  -0.739         -0.0453
 4       0.783          -1.62                  -0.785         -0.0766
 5       0.620          -1.97                  -0.644          0.0116
 6       0.929          -1.57                  -0.731         -0.228 
 7       0.918          -1.42                  -0.558         -0.243 
 8       0.965          -1.57                  -0.612         -0.216 
 9       0.860          -1.62                  -0.490         -0.158 
10       0.787          -1.65                  -0.919          0.0234
# ℹ 740 more rows
# ℹ 134 more variables: `b_FoodTreatmentSatiated:SexParentMale` <dbl>,
#   b_zi_FoodTreatmentSatiated <dbl>, b_zi_SexParentMale <dbl>,
#   `b_zi_FoodTreatmentSatiated:SexParentMale` <dbl>, sd_Nest__Intercept <dbl>,
#   sd_Nest__FoodTreatmentSatiated <dbl>, sd_Nest__SexParentMale <dbl>,
#   `sd_Nest__FoodTreatmentSatiated:SexParentMale` <dbl>,
#   cor_Nest__Intercept__FoodTreatmentSatiated <dbl>, …
owls_brm5b |>
  bayes_R2(re.form = NA, summary = FALSE) |>
  median_hdci()
         y       ymin      ymax .width .point .interval
1 0.168987 0.09713091 0.2391206   0.95 median      hdci
owls_brm5b |>
  bayes_R2(re.form = ~ (1 | Nest), summary = FALSE) |>
  median_hdci()
          y      ymin      ymax .width .point .interval
1 0.1995561 0.1204286 0.2785771   0.95 median      hdci
owls_brm5b |>
  bayes_R2(re.form = ~ (FoodTreatment * SexParent | Nest), summary = FALSE) |>
  median_hdci()
          y      ymin      ymax .width .point .interval
1 0.2426973 0.1871904 0.2976328   0.95 median      hdci
owls_brm5b |> modelsummary(
  statistic = c("conf.low", "conf.high"),
  shape = term ~ statistic,
  exponentiate = TRUE
)
owls_brm5b |> modelplot(exponentiate = TRUE)

9 Further investigations

## ## The following should work, but there is a bug and therefore it does not
## ## (although it has been reported - so may get fixed at some point).
## ## The offset seems to get handled incorrectly
## newdata <- owls_brm5b |>
##     emmeans(~FoodTreatment|SexParent, offset=0, type='response') |>
##     as.data.frame()
newdata <- owls_brm5b |>
  emmeans(~ FoodTreatment | SexParent, type = "response") |>
  as.data.frame()
Warning: Method 'parse_bf' is deprecated. Please use 'brmsterms' instead.
head(newdata)
 FoodTreatment SexParent     prob lower.HPD upper.HPD
 Deprived      Female    2.279234 1.8602755  2.776168
 Satiated      Female    1.161633 0.6145225  1.786211
 Deprived      Male      2.091114 1.7092598  2.456610
 Satiated      Male      1.174281 0.6697113  1.814994

Point estimate displayed: median 
Results are back-transformed from the log scale 
HPD interval probability: 0.95 
## As an alternative, we can do the following...
newdata <- owls_brm5b |>
  emmeans(~ FoodTreatment | SexParent,
    at = list(BroodSize = 1), type = "response"
  ) |>
  as.data.frame()
Warning: Method 'parse_bf' is deprecated. Please use 'brmsterms' instead.
head(newdata)
 FoodTreatment SexParent     prob lower.HPD upper.HPD
 Deprived      Female    2.279234 1.8602755  2.776168
 Satiated      Female    1.161633 0.6145225  1.786211
 Deprived      Male      2.091114 1.7092598  2.456610
 Satiated      Male      1.174281 0.6697113  1.814994

Point estimate displayed: median 
Results are back-transformed from the log scale 
HPD interval probability: 0.95 
ggplot(newdata) +
  geom_pointrange(
    aes(
      y = prob, x = FoodTreatment, color = SexParent,
      ymin = lower.HPD, ymax = upper.HPD
    ),
    position = position_dodge(width = 0.2)
  ) +
  theme_classic()

10 References