
Case study: Ostrich gut microbiome
Source:vignettes/articles/Case study - Ostrich gut microbiome.Rmd
Case study - Ostrich gut microbiome.RmdThis case study is adapted from the mrIML 2.0 supplementary material authored by Ryan K. Leadbetter and Nicholas M. Fountain-Jones (source).
Overview
This case study examines gut microbiome development across three gut sections — caecum, colon, and ileum — in juvenile ostriches (Struthio camelus). The data span the early post-hatching period when the microbiome is rapidly assembling, and host characteristics (primarily age and weight) are expected to be strong drivers alongside microbial co-occurrence.
Each gut section is modelled independently using three configurations:
- Combined — host characteristics (X) + microbial co-occurrence (X₁)
- Host characteristics only — X only
- Co-occurrence only — X₁ only
Key findings: A critical developmental window emerges at 20–40 days post-hatching. Positive associations dominate across all gut sections, and age and weight are the primary host-level predictors.
library(here)
library(readxl)
library(tidyverse)
library(DT)
library(mrIML)
library(tidymodels)
library(future)
library(finetune)
library(flashlight)
library(igraph)
library(ggnetwork)
library(cowplot)
library(patchwork)
n_cores <- parallel::detectCores()
plan("multisession", workers = n_cores - 2)
# Increase memory allowance for parallel workers (large bootstrap objects)
options(future.globals.maxSize = 10 * 1024^3)Data preparation
Data are read and pre-processed by a dedicated curation script that
outputs six objects — Y_caecumF, X_caecum,
Y_colonF, X_colon, Y_ileumF,
X_ileum — one Y and one X per gut section.
# Source the data curation script (adjust path to your local directory)
source(
here("case-studies", "03-ostrich-microbiome", "ostrich_data_curation.r")
)Model specification
model_rf <- rand_forest(
trees = 1000,
mode = "classification",
mtry = tune(),
min_n = tune()
) |>
set_engine("randomForest")Caecum
Model fitting
X1_caecum <- Y_caecumF # co-occurrence predictors = all caecum microbes
X_caecum <- X_caecum # host characteristics (age, weight, etc.)
Y_caecum <- Y_caecumF # response = microbial presence/absence
yhats_rf_caecum_combined <- mrIMLpredicts(
X = X_caecum, Y = Y_caecum, X1 = X1_caecum,
Model = model_rf, balance_data = "no",
tune_grid_size = 5, prop = 0.7, k = 5, racing = FALSE
)
yhats_rf_caecum_noX1 <- mrIMLpredicts(
X = X_caecum, Y = Y_caecum,
Model = model_rf, balance_data = "no",
tune_grid_size = 5, prop = 0.6, k = 5, racing = FALSE
)
yhats_rf_caecum_noX <- mrIMLpredicts(
X = NULL, Y = Y_caecum, X1 = X1_caecum,
Model = model_rf, balance_data = "no",
tune_grid_size = 5, prop = 0.6, k = 5, racing = FALSE
)Performance
model_perf_caecum_combined <- mrIMLperformance(yhats_rf_caecum_combined)
model_perf_caecum_noX1 <- mrIMLperformance(yhats_rf_caecum_noX1)
model_perf_caecum_noX <- mrIMLperformance(yhats_rf_caecum_noX)
data.frame(
Model = c("Host characteristics", "Co-occurrence only", "Combined"),
MCC = c(
model_perf_caecum_combined[[2]],
model_perf_caecum_noX1[[2]],
model_perf_caecum_noX[[2]]
)
)Variable importance
bootstrap_caecum_combined <- mrBootstrap(
yhats_rf_caecum_combined,
num_bootstrap = 10
)
vip_caecum_combined <- mrVip(
yhats_rf_caecum_combined,
bootstrap_caecum_combined
)
vip_caecum_combined[[3]]Age effect
Partial-dependence profile for host age across caecum microbiome taxa:
profilePlot_pd_caecum <- mrCovar(
yhats_rf_caecum_combined,
var = "Age",
sdthresh = 0.1
)
profilePlot_pd_caecum[[1]]Co-occurrence network
assoc_net_caecum <- mrCoOccurNet(bootstrap_caecum_combined)
mrCoOccurNet_plot(
assoc_net_caecum,
strength_thresh = 0.1,
network_title = "Caecum co-occurrence network",
nmds_layout = TRUE,
degree = TRUE,
group_colours = TRUE
)Colon
X1_colon <- Y_colonF
X_colon <- X_colon
Y_colon <- Y_colonF
yhats_rf_colon_combined <- mrIMLpredicts(
X = X_colon, Y = Y_colon, X1 = X1_colon,
Model = model_rf, balance_data = "no",
tune_grid_size = 5, prop = 0.7, k = 5, racing = FALSE
)
yhats_rf_colon_noX1 <- mrIMLpredicts(
X = X_colon, Y = Y_colon,
Model = model_rf, balance_data = "no",
tune_grid_size = 5, prop = 0.6, k = 5, racing = FALSE
)
yhats_rf_colon_noX <- mrIMLpredicts(
X = NULL, Y = Y_colon, X1 = X1_colon,
Model = model_rf, balance_data = "no",
tune_grid_size = 5, prop = 0.6, k = 5, racing = FALSE
)
model_perf_colon_combined <- mrIMLperformance(yhats_rf_colon_combined)
model_perf_colon_noX1 <- mrIMLperformance(yhats_rf_colon_noX1)
model_perf_colon_noX <- mrIMLperformance(yhats_rf_colon_noX)
data.frame(
Model = c("Host characteristics", "Co-occurrence only", "Combined"),
MCC = c(
model_perf_colon_combined[[2]],
model_perf_colon_noX1[[2]],
model_perf_colon_noX[[2]]
)
)
bootstrap_colon_combined <- mrBootstrap(
yhats_rf_colon_combined,
num_bootstrap = 10
)
vip_colon_combined <- mrVip(
yhats_rf_colon_combined,
bootstrap_colon_combined
)
vip_colon_combined[[3]]
profilePlot_pd_colon <- mrCovar(
yhats_rf_colon_combined,
var = "Age",
sdthresh = 0.1
)
profilePlot_pd_colon[[1]]
assoc_net_colon <- mrCoOccurNet(bootstrap_colon_combined)
mrCoOccurNet_plot(
assoc_net_colon,
strength_thresh = 0.1,
network_title = "Colon co-occurrence network",
nmds_layout = TRUE,
degree = TRUE,
group_colours = TRUE
)Ileum
X1_ileum <- Y_ileumF
X_ileum <- X_ileum
Y_ileum <- Y_ileumF
yhats_rf_ileum_combined <- mrIMLpredicts(
X = X_ileum, Y = Y_ileum, X1 = X1_ileum,
Model = model_rf, balance_data = "no",
tune_grid_size = 5, prop = 0.7, k = 5, racing = FALSE
)
yhats_rf_ileum_noX1 <- mrIMLpredicts(
X = X_ileum, Y = Y_ileum,
Model = model_rf, balance_data = "no",
tune_grid_size = 5, prop = 0.6, k = 5, racing = FALSE
)
yhats_rf_ileum_noX <- mrIMLpredicts(
X = NULL, Y = Y_ileum, X1 = X1_ileum,
Model = model_rf, balance_data = "no",
tune_grid_size = 5, prop = 0.6, k = 5, racing = FALSE
)
model_perf_ileum_combined <- mrIMLperformance(yhats_rf_ileum_combined)
model_perf_ileum_noX1 <- mrIMLperformance(yhats_rf_ileum_noX1)
model_perf_ileum_noX <- mrIMLperformance(yhats_rf_ileum_noX)
data.frame(
Model = c("Host characteristics", "Co-occurrence only", "Combined"),
MCC = c(
model_perf_ileum_combined[[2]],
model_perf_ileum_noX1[[2]],
model_perf_ileum_noX[[2]]
)
)
bootstrap_ileum_combined <- mrBootstrap(
yhats_rf_ileum_combined,
num_bootstrap = 10
)
vip_ileum_combined <- mrVip(
yhats_rf_ileum_combined,
bootstrap_ileum_combined
)
vip_ileum_combined[[3]]
profilePlot_pd_ileum <- mrCovar(
yhats_rf_ileum_combined,
var = "Age",
sdthresh = 0.1
)
profilePlot_pd_ileum[[1]]
assoc_net_ileum <- mrCoOccurNet(bootstrap_ileum_combined)
mrCoOccurNet_plot(
assoc_net_ileum,
strength_thresh = 0.1,
network_title = "Ileum co-occurrence network",
nmds_layout = TRUE,
degree = TRUE,
group_colours = TRUE
)