Parrot vocal repertoire evolution

Statistical analysis SEM on imputed data

Author
Published

June 4, 2026

Code
# print link to github repo if any
if (file.exists("./.git/config")){
  config <- readLines("./.git/config")
  url <- grep("url",  config, value = TRUE)
  url <- gsub("\\turl = |.git$", "", url)
  cat("\nSource code and data found at [", url, "](", url, ")", sep = "")
  }

Source code and data found at

Overview

This document fits a phylogenetic Structural Equation Model (SEM) to investigate the drivers of vocal repertoire size in parrots. The model accounts for shared evolutionary history via a phylogenetic covariance matrix and handles missing trait data through multiple imputation. Three sub-models are linked: body mass predicts longevity and brain size, which in turn — alongside gregariousness, flock size, and coloration — predict repertoire size.


Load Packages

Code
# knitr is require for creating html/pdf/word reports
# formatR is used for soft-wrapping code

# install knitr package if not installed
if (!requireNamespace("sketchy", quietly = TRUE)) {
  install.packages("sketchy")
}

packages <- c(
 "tidyverse",
 "reshape2",
 "ape",
 "phytools",
 "mice",
 "brms",
 "brmsish",
 "cmdstanr",
 "ggplot2",
 "patchwork",
 "dagitty",
 "ggdag",
 "posterior",
 "qs2",
 "pbapply"
 )

# install/ load packages
sketchy::load_packages(packages = packages)


options(knitr.kable.NA = '')

print <- function(x, row.names = FALSE) {
    kb <- kable(x, row.names = row.names, digits = 4, "html")
    kb <- kable_styling(kb,
                        bootstrap_options = c("striped", "hover", "condensed", "responsive"))
    scroll_box(kb, width = "100%")
}

0.1 Data Import and Visualisation

The main trait dataset contains species-level data on repertoire size, brain size, flock size, gregariousness, longevity, and body mass. A separate colour dataset (Carballo et al. 2020) provides chromatic and achromatic colour scores that are matched to the trait data by species name. Species with no repertoire data are excluded, as is one extreme outlier value for Melopsittacus undulatus that is almost an order of magnitude larger than the next largest value for that species.

Code
# main trait dataset
traits <- read.csv("./data/raw/12222025ALLTRAITS.csv")

# rename columns for clarity
traits <- traits |>
  rename(phylo = "gs", repertoire = "sp", flock = "log.maxflock") |>
  mutate(species = phylo)

traits <- traits |> select(phylo, species,
                           repertoire,
                           brain, flock, greg, longevity, mass)

# remove species with no repertoire data
traits <- traits |> filter(!is.na(repertoire))

# colour dataset
parrot_col <- read.csv("./data/raw/carballo_2020_colour_avg.csv")

# capitalise species names for matching
parrot_col$species <- stringr::str_to_title(parrot_col$scinam)

# match colour scores to trait data
traits$cds_avg <- parrot_col$cds_avg[match(traits$phylo, parrot_col$species)]
traits$ces_avg <- parrot_col$ces_avg[match(traits$phylo, parrot_col$species)]

# remove the one outlier M. undulatus repertoire value
traits <- traits |> filter(!(phylo == "Melopsittacus_undulatus" & repertoire == 1050))

A quick look at the raw distributions of all traits before any transformation:

Code
reshape2::melt(traits) |>
  ggplot(aes(x = value)) +
  facet_wrap(~variable, scales = "free") +
  geom_histogram() +
  theme_bw()

Raw distributions of all trait variables prior to transformation.

0.2 Data Transformation

Continuous predictors (brain size, longevity, body mass, flock size, and colour scores) are log-transformed where appropriate and then standardised to mean = 0, SD = 1. Repertoire size is left on its raw count scale, as transforming count data prior to modelling is generally discouraged; instead, it will be modelled with a negative binomial distribution.

Code
traits <- traits |>
  mutate_at(c("brain", "longevity", "mass"), ~(log(.))) |>
  mutate_at(c("brain", "longevity", "mass", "flock", "cds_avg", "ces_avg"),
            ~(scale(.) |> as.vector()))

0.3 Phylogeny: Import and Matching

The phylogenetic tree is pruned to retain only species present in the trait dataset. A variance-covariance matrix is then computed from the pruned tree; this matrix is passed to brms to model the expected covariance among species due to shared evolutionary history (a Brownian motion model of trait evolution).

Code
tree <- read.tree("./data/raw/08112025_BrianSmith.treefile")

# prune to species in trait data
matched_tips <- intersect(tree$tip.label, traits$phylo)
tree <- drop.tip(tree, setdiff(tree$tip.label, matched_tips))

# generate phylogenetic variance-covariance matrix
A <- ape::vcv.phylo(tree)

# trim trait data to match pruned tree
traits_filtered <- traits[traits$phylo %in% matched_tips, ]

Distribution check after filtering to matched species:

Code
reshape2::melt(traits_filtered) |>
  ggplot(aes(x = value)) +
  facet_wrap(~variable, scales = "free") +
  geom_histogram() +
  theme_bw()

Trait distributions after filtering to species present in the phylogeny.

0.4 Multiple Imputation

Missing trait values are handled using Multiple Imputation by Chained Equations (MICE), implemented via the mice package. We generate 100 imputed datasets, each with a different plausible set of values for the missing observations. The model is later run on all 100 datasets and results are combined, propagating imputation uncertainty into the final inference.

Code
md.pattern(traits_filtered)

Missing data pattern across traits.
    phylo species repertoire mass greg cds_avg ces_avg flock longevity brain
886     1       1          1    1    1       1       1     1         1     1
131     1       1          1    1    1       1       1     1         1     0
29      1       1          1    1    1       1       1     1         0     1
29      1       1          1    1    1       1       1     1         0     0
24      1       1          1    1    1       1       1     0         1     1
3       1       1          1    1    1       1       1     0         1     0
11      1       1          1    1    0       0       0     1         1     1
1       1       1          1    1    0       0       0     1         0     0
1       1       1          1    0    1       1       1     0         0     0
2       1       1          1    0    0       0       0     0         0     1
        0       0          0    3   14      14      14    30        62   165
       
886   0
131   1
29    1
29    2
24    1
3     2
11    3
1     5
1     4
2     6
    302
Code
# 100 imputations, default mice algorithm (non-phylogenetic)
imp <- mice(traits_filtered, m = 100, seed = 1859)

# store as long-format data frame with .imp variable (1:100)
imp_long <- complete(imp, action = "long")
qs_save(imp_long, "./data/raw/imputed_data.qs")
rm(imp)

0.5 Model Specification

The SEM consists of three linked sub-models:

  • Longevity: predicted by body mass and phylogeny
  • Brain size: predicted by body mass and phylogeny
  • Repertoire size: predicted by longevity, brain size, body mass, flock size, gregariousness, and chromatic colour score — plus phylogeny

All sub-models include a phylogenetic random effect via gr(phylo, cov = A) and a species-level random intercept to capture residual non-phylogenetic species variation. The set_rescor(FALSE) call means residual correlations among the three responses are not estimated (i.e., any correlation is assumed to be fully mediated by the explicit paths in the model).

Code
# longevity sub-model
long_mod <- bf(
  longevity ~ mass +
    (1 | gr(phylo, cov = A)) + (1 | species)
)

# brain size sub-model
br_mod <- bf(
  brain ~ mass +
    (1 | gr(phylo, cov = A)) + (1 | species)
)

# repertoire sub-model (negative binomial for count data)
rep_mod <- bf(
  repertoire ~ longevity + brain + mass + flock + greg + cds_avg +
    (1 | gr(phylo, cov = A)) + (1 | species),
  family = negbinomial()
)

0.5.1 Priors

Weakly informative priors are used throughout. Priors on the standardised predictors in the brain and longevity sub-models are more regularising (SD = 0.5) than those on repertoire predictors (SD = 1), reflecting the fact that repertoire is on its original count scale.

Code
priors <- c(
  prior(normal(0, 1),   class = "b", resp = "repertoire"),
  prior(normal(0, 0.5), class = "b", resp = "brain"),
  prior(normal(0, 0.5), class = "b", resp = "longevity")
)

0.6 Initial Model Fit (Single Imputation)

Before running the full 100-imputation pipeline, the model is first fit on a single imputed dataset to check for convergence, inspect posterior predictive fit, and confirm the model structure is sensible.

Code
mod_SEM <- brm(
  rep_mod + br_mod + long_mod + set_rescor(FALSE),
  data     = imp_long |> filter(.imp == 1),
  data2    = list(A = A),
  prior    = priors,
  backend  = "cmdstanr",
  chains   = 4,
  cores    = 4,
  iter     = 5000,
  seed     = 123,
  file = "./data/processed/base_SEM_model_fit"
  control  = list(adapt_delta = 0.95)
)

0.6.1 Model Summary

Rhat values close to 1.0 and large effective sample sizes (ESS) indicate good convergence.

Code
summary(mod_SEM)
 Family: MV(negbinomial, gaussian, gaussian) 
  Links: mu = log
         mu = identity
         mu = identity 
Formula: repertoire ~ longevity + brain + mass + flock + greg + cds_avg + (1 | gr(phylo, cov = A)) + (1 | species) 
         brain ~ mass + (1 | gr(phylo, cov = A)) + (1 | species) 
         longevity ~ mass + (1 | gr(phylo, cov = A)) + (1 | species) 
   Data: filter(imp_long, .imp == i) (Number of observations: 1117) 
  Draws: 400 chains, each with iter = 2200; warmup = 200; thin = 1;
         total post-warmup draws = 800000

Multilevel Hyperparameters:
~phylo (Number of levels: 74) 
                         Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
sd(repertoire_Intercept)     0.07      0.03     0.01     0.12 1.03     7012
sd(brain_Intercept)          0.16      0.07     0.02     0.28 1.31      967
sd(longevity_Intercept)      0.06      0.05     0.00     0.17 1.05     4472
                         Tail_ESS
sd(repertoire_Intercept)    21648
sd(brain_Intercept)          2696
sd(longevity_Intercept)      5900

~species (Number of levels: 74) 
                         Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
sd(repertoire_Intercept)     0.25      0.12     0.02     0.47 1.03     8845
sd(brain_Intercept)          0.43      0.28     0.02     0.97 1.32      949
sd(longevity_Intercept)      0.91      0.11     0.69     1.14 1.10     2414
                         Tail_ESS
sd(repertoire_Intercept)    31735
sd(brain_Intercept)          2795
sd(longevity_Intercept)      7403

Regression Coefficients:
                     Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
repertoire_Intercept     2.39      0.20     1.96     2.77 1.04     6271
brain_Intercept         -0.61      0.46    -1.61     0.22 1.10     2316
longevity_Intercept     -0.35      0.23    -0.80     0.12 1.08     2995
repertoire_longevity     0.04      0.06    -0.09     0.16 1.55      692
repertoire_brain         0.02      0.05    -0.08     0.11 1.66      633
repertoire_mass          0.00      0.06    -0.11     0.12 1.54      696
repertoire_flock        -0.03      0.07    -0.16     0.10 1.05     4406
repertoire_greg          0.56      0.20     0.16     0.95 1.17     1502
repertoire_cds_avg      -0.09      0.08    -0.23     0.06 1.14     1806
brain_mass               0.45      0.18     0.12     0.77 4.27      425
longevity_mass           0.17      0.09     0.03     0.35 3.11      448
                     Tail_ESS
repertoire_Intercept    28858
brain_Intercept          7273
longevity_Intercept      9251
repertoire_longevity     1026
repertoire_brain         1113
repertoire_mass          1209
repertoire_flock        14926
repertoire_greg          2501
repertoire_cds_avg       4573
brain_mass                614
longevity_mass            677

Further Distributional Parameters:
                 Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape_repertoire     1.51      0.07     1.39     1.65 1.01    38481   391115
sigma_brain          0.88      0.09     0.68     1.02 3.57      436      495
sigma_longevity      0.57      0.06     0.46     0.67 4.14      427      499

Draws were sampled using sample(hmc). 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).

0.6.2 Posterior Predictive Checks

Visual inspection of the posterior predictive distribution against the observed data. The model-predicted distributions (blue lines) should closely follow the observed data distribution (black line).

Code
p1 <- pp_check(mod_SEM, ndraws = 100, resp = "repertoire") +
  ggtitle("Response: repertoire")
p2 <- pp_check(mod_SEM, ndraws = 100, resp = "brain") +
  ggtitle("Response: brain")
p3 <- pp_check(mod_SEM, ndraws = 100, resp = "longevity") +
  ggtitle("Response: longevity")

p1 + p2 + p3 +
  plot_annotation("Posterior predictive checks (blue: model, black: data)")

Posterior predictive checks for the initial single-imputation model fit.

0.7 Full Pipeline: All 100 Imputed Datasets

The model is first compiled with zero chains (no sampling), producing a compiled Stan program. This compiled object is then updated via update() for each of the 100 imputed datasets in parallel, avoiding recompilation on every iteration.

0.7.1 Compile (No Sampling)

Code
mod_SEM_empty <- brm(
  rep_mod + br_mod + long_mod + set_rescor(FALSE),
  data    = imp_long |> filter(.imp == 1),
  data2   = list(A = A),
  prior   = priors,
  backend = "cmdstanr",
  chains  = 0,
  cores   = 0,
  iter    = 2200,
  warmup  = 200,
  seed    = 123,
  file    = "./data/processed/SEM_model_fit_empty.rds",
  control = list(adapt_delta = 0.95)
)

0.7.2 Run Across All Imputations

Each imputed dataset gets its own set of 2 chains × 5000 iterations (1000 warmup). Running in parallel across 20 cores substantially reduces wall-clock time.

Code
models <- pblapply(1:100, cl = 20, function(i) {
  update(mod_SEM_empty,
         newdata  = imp_long |> filter(.imp == i),
         data2    = list(A = A),
         prior    = priors,
         backend  = "cmdstanr",
         chains   = 2,
         cores    = 2,
         iter     = 5000,
         seed     = 123,
         control  = list(adapt_delta = 0.95))
})

saveRDS(models, "./data/processed/SEM_models_all_imputations.rds")

0.8 Convergence Diagnostics

After fitting all 100 models, Rhat values are checked for each. Rhat > 1.05 is considered a convergence warning. The table below summarises how many parameters with Rhat > 1.05 each model has.

Code
models <- readRDS("./data/processed/SEM_models_all_imputations.rds")

n_bad_rhat <- sapply(models, function(mod) {
  rhats <- summarise_draws(as_draws_array(mod))$rhat
  sum(rhats > 1.05, na.rm = TRUE)
})

max_rhat <- sapply(models, function(mod) {

  rhats <- summarise_draws(
    as_draws_array(mod)
  )$rhat

  max(rhats, na.rm = TRUE)
})

df_rhats <- data.frame(
  model = 1:length(models),
  n_bad_rhat = n_bad_rhat,
  max_rhat = max_rhat
)

saveRDS(df_rhats, "./data/processed/n_bad_rhat.rds")

Check R hats across all models. The majority of models should have zero parameters with Rhat > 1.05, and the maximum Rhat values should be close to 1.0.

Code
df_rhats <- readRDS("./data/processed/n_bad_rhat.rds")

df_rhats |>  subset(max_rhat > 1.05)
model n_bad_rhat max_rhat
52 52 40 1.077751
Code
# proportion of models with any bad Rhats
table(df_rhats$n_bad_rhat > 0)

FALSE  TRUE 
   54     1 
Code
# distribution of bad Rhat counts
summary(df_rhats$n_bad_rhat)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.0000  0.0000  0.0000  0.7273  0.0000 40.0000 

0.9 Combine Models and Final Inference

The 100 individual model fits are combined into a single brmsfit object using combine_models(). This pools the posterior draws across all imputed datasets, so that subsequent inference integrates over both sampling uncertainty and imputation uncertainty.

Code
comb_mod <- combine_models(mlist = models, check_data = FALSE)
saveRDS(comb_mod, "./data/processed/SEM_combined_model.rds")

0.9.1 Results Summary

Fixed effect estimates with 95% credible intervals. Predictors whose credible intervals exclude zero are interpreted as having a meaningful effect on the response.

Code
extended_summary(
  comb_mod,
  highlight = TRUE,
  trace.palette = viridis::mako,
  remove.intercepts = TRUE,
  trace = FALSE
)

0.10 comb_mod

formula family priors iterations chains thinning warmup diverg_transitions rhats > 1.05 min_bulk_ESS min_tail_ESS seed
1 list(repertoire = list(formula = repertoire ~ longevity + brain + mass + flock + greg + cds_avg + (1 | gr(phylo, cov = A)) + (1 | species), pforms = list(), pfix = list(), family = list(family = “negbinomial”, link = “log”, linkfun = function (mu) link(mu, link = slink), linkinv = function (eta) inv_link(eta, link = slink), dpars = c(“mu”, “shape”), type = “int”, ybounds = c(0, Inf), closed = c(TRUE, NA), ad = c(“weights”, “subset”, “cens”, “trunc”, “rate”, “index”), specials = “sbi_log”, prior = function (dpar, link = “identity”, …) { if (dpar == “shape” && link == “identity”) { return(“inv_gamma(0.4, 0.3)”) } NULL }, link_shape = “log”), resp = “repertoire”, mecor = TRUE), brain = list(formula = brain ~ mass + (1 | gr(phylo, cov = A)) + (1 | species), pforms = list(), pfix = list(), resp = “brain”, family = list(family = “gaussian”, link = “identity”, linkfun = function (mu) link(mu, link = slink), linkinv = function (eta) inv_link(eta, link = slink), dpars = c(“mu”, “sigma”), type = “real”, ybounds = c(-Inf, Inf), closed = c(NA, NA), ad = c(“weights”, “subset”, “se”, “cens”, “trunc”, “mi”, “index”), normalized = c(“_time_hom”, “_time_het”, “_lagsar”, “_errorsar”, “_fcor”), specials = c(“residuals”, “rescor”)), mecor = TRUE), longevity = list(formula = longevity ~ mass + (1 | gr(phylo, cov = A)) + (1 | species), pforms = list(), pfix = list(), resp = “longevity”, family = list(family = “gaussian”, link = “identity”, linkfun = function (mu) link(mu, link = slink), linkinv = function (eta) inv_link(eta, link = slink), dpars = c(“mu”, “sigma”), type = “real”, ybounds = c(-Inf, Inf), closed = c(NA, NA), ad = c(“weights”, “subset”, “se”, “cens”, “trunc”, “mi”, “index”), normalized = c(“_time_hom”, “_time_het”, “_lagsar”, “_errorsar”, “_fcor”), specials = c(“residuals”, “rescor”)), mecor = TRUE)) () b-normal(0, 0.5) b-normal(0, 0.5) b-normal(0, 1) Intercept-student_t(3, -0.1, 2.5) Intercept-student_t(3, -0.1, 2.5) Intercept-student_t(3, 2.4, 2.5) sd-student_t(3, 0, 2.5) sd-student_t(3, 0, 2.5) sd-student_t(3, 0, 2.5) shape-inv_gamma(0.4, 0.3) sigma-student_t(3, 0, 2.5) sigma-student_t(3, 0, 2.5) 5000 200 1 2500 3657 (0.0073%) 9 212.327 307.283 123
Estimate l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
b_repertoire_Intercept 2.388 1.957 2.769 1.037 3013.692 9532.431
b_brain_Intercept -0.609 -1.608 0.219 1.104 1138.671 3603.219
b_longevity_Intercept -0.350 -0.800 0.129 1.078 1478.698 4918.833
b_repertoire_longevity 0.044 -0.092 0.161 1.543 346.405 515.745
b_repertoire_brain 0.017 -0.084 0.109 1.656 316.205 550.669
b_repertoire_mass 0.003 -0.111 0.124 1.541 347.166 614.765
b_repertoire_flock -0.033 -0.161 0.100 1.049 2272.522 8035.299
b_repertoire_greg 0.565 0.157 0.949 1.17 751.071 1222.692
b_repertoire_cds_avg -0.088 -0.230 0.065 1.135 905.268 2312.961
b_brain_mass 0.448 0.125 0.769 4.27 212.327 307.283
b_longevity_mass 0.171 0.026 0.348 3.119 223.702 338.484

0.10.1 Repertoire Effects Plot

Marginal posterior distributions for all fixed effects on repertoire size:

Code
mcmc_plot(comb_mod, variable = "^b_rep.*", type = "areas", regex = TRUE)

Posterior distributions of fixed effects on vocal repertoire size.

Takeaways

  • Repertoire size is positively associated with gregariousness
  • Body mass is positively associated with brain size and longevity

 


─ Session info ───────────────────────────────────────────────────────────────
 setting  value
 version  R version 4.5.2 (2025-10-31)
 os       Ubuntu 22.04.5 LTS
 system   x86_64, linux-gnu
 ui       X11
 language (EN)
 collate  en_US.UTF-8
 ctype    en_US.UTF-8
 tz       America/Costa_Rica
 date     2026-06-04
 pandoc   3.2 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
 quarto   1.7.31 @ /usr/local/bin/quarto

─ Packages ───────────────────────────────────────────────────────────────────
 package           * version    date (UTC) lib source
 abind               1.4-8      2024-09-12 [1] CRAN (R 4.5.0)
 ape               * 5.8-1      2024-12-16 [1] CRAN (R 4.5.0)
 arrayhelpers        1.1-0      2020-02-04 [1] CRAN (R 4.5.0)
 backports           1.5.1      2026-04-03 [1] CRAN (R 4.5.2)
 bayesplot           1.15.0     2025-12-12 [1] CRAN (R 4.5.2)
 boot                1.3-32     2025-08-29 [4] CRAN (R 4.5.1)
 bridgesampling      1.2-1      2025-11-19 [1] CRAN (R 4.5.0)
 brms              * 2.23.0     2025-09-09 [1] CRAN (R 4.5.0)
 brmsish           * 1.0.0      2026-01-06 [1] CRANs (R 4.5.2)
 Brobdingnag         1.2-9      2022-10-19 [1] CRAN (R 4.5.0)
 broom               1.0.8      2025-03-28 [3] CRAN (R 4.5.0)
 cachem              1.1.0      2024-05-16 [1] CRAN (R 4.5.0)
 checkmate           2.3.4      2026-02-03 [1] CRAN (R 4.5.2)
 cli                 3.6.6      2026-04-09 [1] CRAN (R 4.5.2)
 clusterGeneration   1.3.8      2023-08-16 [1] CRAN (R 4.5.0)
 cmdstanr          * 0.9.0      2025-08-21 [1] https://stan-dev.r-universe.dev (R 4.5.0)
 coda                0.19-4.1   2024-01-31 [1] CRAN (R 4.5.0)
 codetools           0.2-20     2024-03-31 [4] CRAN (R 4.5.0)
 combinat            0.0-8      2012-10-29 [1] CRAN (R 4.5.0)
 cowplot             1.2.0      2025-07-07 [1] CRAN (R 4.5.0)
 crayon              1.5.3      2024-06-20 [1] CRAN (R 4.5.0)
 curl                7.1.0      2026-04-22 [1] CRAN (R 4.5.2)
 dagitty           * 0.3-4      2023-12-07 [1] CRAN (R 4.5.0)
 DEoptim             2.2-8      2022-11-11 [1] CRAN (R 4.5.0)
 devtools            2.4.5      2022-10-11 [1] CRAN (R 4.5.0)
 digest              0.6.39     2025-11-19 [1] CRAN (R 4.5.0)
 distributional      0.5.0      2024-09-17 [1] CRAN (R 4.5.0)
 doParallel          1.0.17     2022-02-07 [1] CRAN (R 4.5.0)
 dplyr             * 1.1.4      2023-11-17 [1] CRAN (R 4.5.0)
 ellipsis            0.3.2      2021-04-29 [3] CRAN (R 4.1.1)
 emmeans             1.11.1     2025-05-04 [3] CRAN (R 4.5.0)
 estimability        1.5.1      2024-05-12 [3] CRAN (R 4.5.0)
 evaluate            1.0.5      2025-08-27 [1] CRAN (R 4.5.0)
 expm                1.0-0      2024-08-19 [3] CRAN (R 4.5.0)
 farver              2.1.2      2024-05-13 [1] CRAN (R 4.5.0)
 fastmap             1.2.0      2024-05-15 [1] CRAN (R 4.5.0)
 fastmatch           1.1-6      2024-12-23 [3] CRAN (R 4.5.0)
 forcats           * 1.0.0      2023-01-29 [1] CRAN (R 4.5.0)
 foreach             1.5.2      2022-02-02 [3] CRAN (R 4.1.2)
 fs                  2.1.0      2026-04-18 [1] CRAN (R 4.5.2)
 generics            0.1.4      2025-05-09 [1] CRAN (R 4.5.0)
 ggdag             * 0.2.13     2024-07-22 [1] CRAN (R 4.5.0)
 ggdist              3.3.3      2025-04-23 [1] CRAN (R 4.5.0)
 ggplot2           * 4.0.3      2026-04-22 [1] CRAN (R 4.5.2)
 ggridges            0.5.7      2025-08-27 [1] CRAN (R 4.5.0)
 glmnet              4.1-8      2023-08-22 [1] CRAN (R 4.5.0)
 glue                1.8.1      2026-04-17 [1] CRAN (R 4.5.2)
 gridExtra           2.3        2017-09-09 [1] CRAN (R 4.5.0)
 gtable              0.3.6      2024-10-25 [1] CRAN (R 4.5.0)
 hms                 1.1.3      2023-03-21 [3] CRAN (R 4.5.0)
 htmltools           0.5.9      2025-12-04 [1] CRAN (R 4.5.0)
 htmlwidgets         1.6.4      2023-12-06 [1] RSPM (R 4.5.0)
 httpuv              1.6.16     2025-04-16 [1] RSPM (R 4.5.0)
 igraph              2.2.1      2025-10-27 [1] CRAN (R 4.5.0)
 inline              0.3.21     2025-01-09 [1] CRAN (R 4.5.0)
 iterators           1.0.14     2022-02-05 [3] CRAN (R 4.1.2)
 jomo                2.7-6      2023-04-15 [1] CRAN (R 4.5.2)
 jsonlite            2.0.0      2025-03-27 [1] CRAN (R 4.5.0)
 kableExtra          1.4.0      2024-01-24 [1] CRAN (R 4.5.0)
 knitr               1.51       2025-12-20 [1] CRAN (R 4.5.2)
 labeling            0.4.3      2023-08-29 [1] CRAN (R 4.5.0)
 later               1.4.2      2025-04-08 [1] RSPM (R 4.5.0)
 lattice             0.22-9     2026-02-09 [4] CRAN (R 4.5.2)
 lifecycle           1.0.5      2026-01-08 [1] CRAN (R 4.5.2)
 lme4                1.1-37     2025-03-26 [1] CRAN (R 4.5.0)
 loo                 2.9.0      2025-12-23 [1] CRAN (R 4.5.2)
 lubridate         * 1.9.5      2026-02-04 [1] CRAN (R 4.5.2)
 magrittr            2.0.5      2026-04-04 [1] CRAN (R 4.5.2)
 maps              * 3.4.2.1    2024-11-10 [3] CRAN (R 4.5.0)
 MASS                7.3-65     2025-02-28 [4] CRAN (R 4.4.3)
 Matrix              1.7-4      2025-08-28 [4] CRAN (R 4.5.1)
 matrixStats         1.5.0      2025-01-07 [1] CRAN (R 4.5.0)
 memoise             2.0.1      2021-11-26 [1] CRAN (R 4.5.0)
 mice              * 3.19.0     2025-12-10 [1] CRAN (R 4.5.2)
 mime                0.13       2025-03-17 [1] CRAN (R 4.5.0)
 miniUI              0.1.2      2025-04-17 [3] CRAN (R 4.5.0)
 minqa               1.2.4      2014-10-09 [3] CRAN (R 4.0.1)
 mitml               0.4-5      2023-03-08 [1] CRAN (R 4.5.2)
 mnormt              2.1.1      2022-09-26 [3] CRAN (R 4.5.0)
 multcomp            1.4-28     2025-01-29 [3] CRAN (R 4.5.0)
 mvtnorm             1.3-3      2025-01-10 [1] CRAN (R 4.5.0)
 nlme                3.1-168    2025-03-31 [4] CRAN (R 4.4.3)
 nloptr              2.2.1      2025-03-17 [3] CRAN (R 4.5.0)
 nnet                7.3-20     2025-01-01 [4] CRAN (R 4.4.2)
 numDeriv            2016.8-1.1 2019-06-06 [1] CRAN (R 4.5.0)
 optimParallel       1.0-2      2021-02-11 [1] CRAN (R 4.5.0)
 otel                0.2.0      2025-08-29 [1] CRAN (R 4.5.2)
 packrat             0.9.3      2025-06-16 [1] CRAN (R 4.5.2)
 pan                 1.9        2023-12-07 [1] CRAN (R 4.5.2)
 patchwork         * 1.3.0      2024-09-16 [1] CRAN (R 4.5.0)
 pbapply           * 1.7-4      2025-07-20 [1] CRAN (R 4.5.0)
 phangorn            2.12.1     2024-09-17 [1] CRAN (R 4.5.0)
 phytools          * 2.4-4      2025-01-08 [1] CRAN (R 4.5.0)
 pillar              1.11.1     2025-09-17 [1] CRAN (R 4.5.0)
 pkgbuild            1.4.8      2025-05-26 [1] CRAN (R 4.5.0)
 pkgconfig           2.0.3      2019-09-22 [1] CRAN (R 4.5.0)
 pkgload             1.4.1      2025-09-23 [1] CRAN (R 4.5.0)
 plyr                1.8.9      2023-10-02 [1] CRAN (R 4.5.0)
 posterior         * 1.6.1      2025-02-27 [1] CRAN (R 4.5.0)
 processx            3.8.6      2025-02-21 [1] CRAN (R 4.5.0)
 profvis             0.4.0      2024-09-20 [1] CRAN (R 4.5.0)
 promises            1.3.3      2025-05-29 [1] RSPM (R 4.5.0)
 ps                  1.9.1      2025-04-12 [1] CRAN (R 4.5.0)
 purrr             * 1.2.0      2025-11-04 [1] CRAN (R 4.5.0)
 qs2               * 0.2.1      2026-05-04 [1] CRAN (R 4.5.2)
 quadprog            1.5-8      2019-11-20 [3] CRAN (R 4.0.1)
 QuickJSR            1.8.1      2025-09-20 [1] CRAN (R 4.5.0)
 R6                  2.6.1      2025-02-15 [1] CRAN (R 4.5.0)
 rbibutils           2.3        2024-10-04 [1] CRAN (R 4.5.0)
 RColorBrewer        1.1-3      2022-04-03 [1] CRAN (R 4.5.0)
 Rcpp              * 1.1.1-1.1  2026-04-24 [1] CRAN (R 4.5.2)
 RcppParallel        5.1.11-1   2025-08-27 [1] CRAN (R 4.5.0)
 Rdpack              2.6.4      2025-04-09 [1] CRAN (R 4.5.0)
 readr             * 2.1.5      2024-01-10 [1] CRAN (R 4.5.0)
 reformulas          0.4.1      2025-04-30 [1] CRAN (R 4.5.0)
 remotes             2.5.0      2024-03-17 [1] CRAN (R 4.5.0)
 reshape2          * 1.4.5      2025-11-12 [1] CRAN (R 4.5.0)
 rlang               1.2.0      2026-04-06 [1] CRAN (R 4.5.2)
 rmarkdown           2.31       2026-03-26 [1] CRAN (R 4.5.2)
 rpart               4.1.24     2025-01-07 [4] CRAN (R 4.4.2)
 rstan               2.32.7     2025-03-10 [1] CRAN (R 4.5.0)
 rstantools          2.5.0      2025-09-01 [1] CRAN (R 4.5.0)
 rstudioapi          0.17.1     2024-10-22 [1] CRAN (R 4.5.0)
 S7                  0.2.2      2026-04-22 [1] CRAN (R 4.5.2)
 sandwich            3.1-1      2024-09-15 [3] CRAN (R 4.5.0)
 scales              1.4.0      2025-04-24 [1] CRAN (R 4.5.0)
 scatterplot3d       0.3-44     2023-05-05 [1] CRAN (R 4.5.0)
 sessioninfo         1.2.3      2025-02-05 [3] CRAN (R 4.5.0)
 shape               1.4.6.1    2024-02-23 [3] CRAN (R 4.5.0)
 shiny               1.10.0     2024-12-14 [1] CRAN (R 4.5.0)
 sketchy             1.0.7      2026-01-28 [1] CRANs (R 4.5.2)
 StanHeaders         2.32.10    2024-07-15 [1] CRAN (R 4.5.0)
 stringfish          0.19.0     2026-04-21 [1] CRAN (R 4.5.2)
 stringi             1.8.7      2025-03-27 [1] CRAN (R 4.5.0)
 stringr           * 1.6.0      2025-11-04 [1] CRAN (R 4.5.0)
 survival            3.8-6      2026-01-16 [4] CRAN (R 4.5.2)
 svglite             2.2.2      2025-10-21 [1] CRAN (R 4.5.0)
 svUnit              1.0.8      2025-08-26 [1] CRAN (R 4.5.0)
 systemfonts         1.3.1      2025-10-01 [1] CRAN (R 4.5.0)
 tensorA             0.36.2.1   2023-12-13 [1] CRAN (R 4.5.0)
 textshaping         1.0.4      2025-10-10 [1] CRAN (R 4.5.0)
 TH.data             1.1-3      2025-01-17 [3] CRAN (R 4.5.0)
 tibble            * 3.3.0      2025-06-08 [1] RSPM (R 4.5.0)
 tidybayes           3.0.7      2024-09-15 [1] CRAN (R 4.5.0)
 tidygraph           1.2.0      2020-05-12 [3] CRAN (R 4.0.1)
 tidyr             * 1.3.2      2025-12-19 [1] CRAN (R 4.5.2)
 tidyselect          1.2.1      2024-03-11 [1] CRAN (R 4.5.0)
 tidyverse         * 2.0.0      2023-02-22 [1] RSPM (R 4.5.0)
 timechange          0.4.0      2026-01-29 [1] CRAN (R 4.5.2)
 tzdb                0.5.0      2025-03-15 [1] CRAN (R 4.5.0)
 urlchecker          1.0.1      2021-11-30 [1] CRAN (R 4.5.0)
 usethis             3.1.0      2024-11-26 [3] CRAN (R 4.5.0)
 V8                  6.0.4      2025-06-04 [1] RSPM (R 4.5.0)
 vctrs               0.7.3      2026-04-11 [1] CRAN (R 4.5.2)
 viridis             0.6.5      2024-01-29 [1] CRAN (R 4.5.0)
 viridisLite         0.4.3      2026-02-04 [1] CRAN (R 4.5.2)
 withr               3.0.2      2024-10-28 [1] CRAN (R 4.5.0)
 xaringanExtra       0.8.0      2024-05-19 [1] CRAN (R 4.5.0)
 xfun                0.57       2026-03-20 [1] CRAN (R 4.5.2)
 xml2                1.5.2      2026-01-17 [1] CRAN (R 4.5.2)
 xtable              1.8-8      2026-02-22 [1] CRAN (R 4.5.2)
 yaml                2.3.12     2025-12-10 [1] CRAN (R 4.5.2)
 zoo                 1.8-14     2025-04-10 [3] CRAN (R 4.5.0)

 [1] /home/m/R/x86_64-pc-linux-gnu-library/4.5
 [2] /usr/local/lib/R/site-library
 [3] /usr/lib/R/site-library
 [4] /usr/lib/R/library
 * ── Packages attached to the search path.

──────────────────────────────────────────────────────────────────────────────