# Diet Analysis of Horses Using Dirichlet and Beta Regression Models
# Load libraries
library(readxl)
library(tidyverse)
## Warning: package 'ggplot2' was built under R version 4.3.3
## Warning: package 'tidyr' was built under R version 4.3.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.0     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(patchwork)
library(DirichletReg)
## Loading required package: Formula
library(zCompositions)
## Loading required package: MASS
## 
## Attaching package: 'MASS'
## 
## The following object is masked from 'package:patchwork':
## 
##     area
## 
## The following object is masked from 'package:dplyr':
## 
##     select
## 
## Loading required package: NADA
## Loading required package: survival
## 
## Attaching package: 'NADA'
## 
## The following object is masked from 'package:stats':
## 
##     cor
## 
## Loading required package: truncnorm
library(betareg)
library(lmtest)
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## 
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
library(emmeans)
library(dplyr)

theme_set(theme_bw())
# Section 1: Przewalski's Horses 
# Load and prepare data
dieta <- read_excel("Przewalski.xlsx")
dieta$Season <- factor(dieta$Season, levels = c("winter", "spring", "summer", "autumn"))

# Prepare compositional data for Dirichlet regression
items <- dieta %>% dplyr::select(Graminoids:Other_herbaceous) %>% DR_data() 
## Warning in DR_data(.): not all rows sum up to 1 => normalization forced
##   some entries are 0 or 1 => transformation forced
# Dirichlet Regression Models
m0 <- DirichReg(items ~ 1, data = dieta)
ms <- DirichReg(items ~ Season, data = dieta)

# Model comparison using AIC and Likelihood Ratio Test
models <- list(Null = m0, Season = ms)
AIC_models <- sapply(models, AIC) %>% as.data.frame()
colnames(AIC_models) <- "AIC"
AIC_models$K <- sapply(models, \(m) m$npar)
AIC_models$LL <- sapply(models, logLik)
AIC_models <- AIC_models[order(AIC_models$AIC), ]
AIC_models$deltaAIC <- AIC_models$AIC - AIC_models$AIC[1]
AIC_models$weight <- exp(-0.5 * AIC_models$deltaAIC) %>% {./sum(.)}
AIC_models$`p value` <- sapply(list(m0, ms), \(x) anova(m0, x)$`Pr(>Chi)`[2])
anova(m0, ms)
## Analysis of Deviance Table
## 
## Model 1: DirichReg(formula = items ~ 1, data = dieta)
## Model 2: DirichReg(formula = items ~ Season, data = dieta)
## 
##         Deviance N. par Difference df  Pr(>Chi)    
## Model 1  -209.05      4                            
## Model 2  -266.07     16     57.019 12 7.841e-08 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
drop1(ms)
## CAVEAT: drop1() is still an experimental feature. If you plan to use this
##         function, please double-check results, e.g., by comparing two models
##         using anova().
## Single term deletions
## 
## Model:
## items ~ Season
##                          Df Deviance     AIC     LRT  Pr(>Chi)    
## <none>                       -266.07 -234.07                      
## Other_herbaceous: Season  3  -264.45 -238.45  1.6203 0.6547934    
## Fabaceae: Season          3  -263.43 -237.43  2.6442 0.4497996    
## Woody: Season             3  -254.94 -228.94 11.1288 0.0110493 *  
## Graminoids: Season        3  -248.92 -222.92 17.1467 0.0006593 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Model diagnostics
res <- residuals(ms, type = "standardized")
boxplot(res, main = "Residuals by Component (Przewalski)")

fitted_vals <- fitted(ms)
par(mfrow = c(1, ncol(fitted_vals)))
for (i in 1:ncol(fitted_vals)) {
  plot(fitted_vals[, i], res[, i], main = colnames(fitted_vals)[i],
       xlab = "Fitted", ylab = "Residuals")
  abline(h = 0, col = "red")
}

# Prepare beta regression data
items2 <- items |> unclass() |> as.data.frame() |> cbind(Season = dieta$Season)

# Beta regression for each food group

# graminoids
mb_Graminoids0 <- betareg(Graminoids ~ Season,
                          data = items2)
mb_Graminoids <- betareg(Graminoids ~ Season|Season,
                         data = items2)
lrtest(mb_Graminoids0, mb_Graminoids)
## Likelihood ratio test
## 
## Model 1: Graminoids ~ Season
## Model 2: Graminoids ~ Season | Season
##   #Df LogLik Df  Chisq Pr(>Chisq)
## 1   5 28.239                     
## 2   8 31.280  3 6.0823     0.1077
lrtest(update(mb_Graminoids0, ~1), mb_Graminoids0)  
## Likelihood ratio test
## 
## Model 1: Graminoids ~ 1
## Model 2: Graminoids ~ Season
##   #Df LogLik Df  Chisq Pr(>Chisq)    
## 1   2 15.355                         
## 2   5 28.239  3 25.768  1.066e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
em <- emmeans(mb_Graminoids0, ~ Season)
contrast(em, "pairwise")
##  contrast        estimate     SE  df z.ratio p.value
##  winter - spring  0.13109 0.0416 Inf   3.148  0.0089
##  winter - summer  0.27689 0.0398 Inf   6.962  <.0001
##  winter - autumn  0.14065 0.0480 Inf   2.931  0.0178
##  spring - summer  0.14580 0.0449 Inf   3.249  0.0064
##  spring - autumn  0.00955 0.0523 Inf   0.183  0.9978
##  summer - autumn -0.13625 0.0508 Inf  -2.682  0.0368
## 
## P value adjustment: tukey method for comparing a family of 4 estimates
#### fabaceae 
mb_Fabaceae0 <- betareg(Fabaceae ~ Season,
                        data = items2)
mb_Fabaceae <- betareg(Fabaceae ~ Season|Season,
                       data = items2)
lrtest(mb_Fabaceae0, mb_Fabaceae)
## Likelihood ratio test
## 
## Model 1: Fabaceae ~ Season
## Model 2: Fabaceae ~ Season | Season
##   #Df LogLik Df  Chisq Pr(>Chisq)
## 1   5 40.877                     
## 2   8 43.552  3 5.3519     0.1478
lrtest(update(mb_Fabaceae0, ~1), mb_Fabaceae0)  
## Likelihood ratio test
## 
## Model 1: Fabaceae ~ 1
## Model 2: Fabaceae ~ Season
##   #Df LogLik Df  Chisq Pr(>Chisq)   
## 1   2 33.645                        
## 2   5 40.877  3 14.464   0.002337 **
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
em <- emmeans(mb_Fabaceae0, ~ Season)
contrast(em, "pairwise")
##  contrast        estimate     SE  df z.ratio p.value
##  winter - spring  -0.0406 0.0234 Inf  -1.735  0.3052
##  winter - summer  -0.1097 0.0261 Inf  -4.210  0.0001
##  winter - autumn  -0.0756 0.0313 Inf  -2.412  0.0748
##  spring - summer  -0.0691 0.0301 Inf  -2.296  0.0989
##  spring - autumn  -0.0349 0.0347 Inf  -1.005  0.7464
##  summer - autumn   0.0341 0.0366 Inf   0.933  0.7869
## 
## P value adjustment: tukey method for comparing a family of 4 estimates
#### woody 
mb_Woody0 <- betareg(Woody ~ Season,
                     data = items2)
mb_Woody <- betareg(Woody ~ Season|Season,
                    data = items2)
lrtest(mb_Woody0, mb_Woody)
## Likelihood ratio test
## 
## Model 1: Woody ~ Season
## Model 2: Woody ~ Season | Season
##   #Df LogLik Df  Chisq Pr(>Chisq)
## 1   5 55.317                     
## 2   8 56.036  3 1.4374     0.6968
lrtest(update(mb_Woody0, ~1), mb_Woody0)
## Likelihood ratio test
## 
## Model 1: Woody ~ 1
## Model 2: Woody ~ Season
##   #Df LogLik Df Chisq Pr(>Chisq)  
## 1   2 51.385                      
## 2   5 55.317  3 7.863    0.04893 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
em <- emmeans(mb_Woody0, ~ Season)
contrast(em, "pairwise")
##  contrast        estimate     SE  df z.ratio p.value
##  winter - spring  0.03782 0.0143 Inf   2.644  0.0409
##  winter - summer  0.00228 0.0156 Inf   0.146  0.9989
##  winter - autumn  0.01721 0.0175 Inf   0.981  0.7602
##  spring - summer -0.03554 0.0136 Inf  -2.615  0.0442
##  spring - autumn -0.02061 0.0158 Inf  -1.304  0.5601
##  summer - autumn  0.01493 0.0170 Inf   0.880  0.8153
## 
## P value adjustment: tukey method for comparing a family of 4 estimates
#### other_herbaceous 
mb_Other_herbaceous0 <- betareg(Other_herbaceous ~ Season,
                                data = items2)
mb_Other_herbaceous <- betareg(Other_herbaceous ~ Season|Season,
                               data = items2)
lrtest(mb_Other_herbaceous0, mb_Other_herbaceous)
## Likelihood ratio test
## 
## Model 1: Other_herbaceous ~ Season
## Model 2: Other_herbaceous ~ Season | Season
##   #Df LogLik Df  Chisq Pr(>Chisq)  
## 1   5 32.622                       
## 2   8 38.128  3 11.011    0.01167 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
lrtest(update(mb_Other_herbaceous, ~1), mb_Other_herbaceous) 
## Likelihood ratio test
## 
## Model 1: Other_herbaceous ~ 1 | Season
## Model 2: Other_herbaceous ~ Season | Season
##   #Df LogLik Df  Chisq Pr(>Chisq)    
## 1   5 27.383                         
## 2   8 38.128  3 21.489  8.332e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
em <- emmeans(mb_Other_herbaceous, ~ Season)
contrast(em, "pairwise")
##  contrast        estimate     SE  df z.ratio p.value
##  winter - spring  -0.1103 0.0313 Inf  -3.522  0.0024
##  winter - summer  -0.1615 0.0393 Inf  -4.108  0.0002
##  winter - autumn  -0.0868 0.0298 Inf  -2.917  0.0186
##  spring - summer  -0.0512 0.0493 Inf  -1.038  0.7268
##  spring - autumn   0.0235 0.0421 Inf   0.557  0.9447
##  summer - autumn   0.0747 0.0484 Inf   1.544  0.4112
## 
## P value adjustment: tukey method for comparing a family of 4 estimates
# Diet composition plot
pdieta <- dieta %>% 
  dplyr::select(Graminoids:Other_herbaceous) %>%           # subconjunt amb dieta nom?s
  transmute(total = rowSums(.)) %>%         # calculem abund. total per individu
  bind_cols(dieta) %>%                         # ajuntem el total a dd
  mutate(across(Graminoids:Other_herbaceous, ~.x/total))

ladieta <- pivot_longer(pdieta, cols = Graminoids:Other_herbaceous,
                        names_to = "Species",
                        values_to = "p_i")
ladieta$Species <- factor(ladieta$Species, 
                          levels = c("Graminoids", 
                                     "Fabaceae", "Other_herbaceous", "Woody"),
                          labels = c("Poaceae", 
                                     "Fabaceae", "Other herbaceous", "Woody"))
ladieta$Season <- factor(ladieta$Season, 
                         levels = c("summer", "autumn", "winter", "spring"))

ggplot(ladieta, aes(Species, p_i)) +
  stat_summary(fun.data = mean_se, geom = "errorbar", width = 0.3) +
  stat_summary(fun = mean, geom = "col") +
  facet_wrap(~ Season, nrow = 1) +
  labs(title = "Diet Composition (Przewalski)", x = NULL, y = NULL) +
  theme(aspect.ratio = 1, plot.title = element_text(hjust = 0.5, size = 14),
        axis.text.x = element_text(angle = 45, hjust = 1))

# Section 2: Potokka Horses
# Load and prepare data
dieta <- read_excel("Potokka.xlsx")
dieta$Season <- factor(dieta$Season, levels = c("winter", "spring", "summer", "autumn"))

# Prepare compositional data for Dirichlet regression
items <- dieta %>% dplyr::select(Ampelodesmos:Other_herbaceous) %>% DR_data()
## Warning in DR_data(.): not all rows sum up to 1 => normalization forced
# Dirichlet Regression Models
m0 <- DirichReg(items ~ 1, data = dieta)
mm <- DirichReg(items ~  Season, data = dieta)

# AIC model comparison
models <- list(Null = m0, Season = mm)
AIC_models <- sapply(models, AIC) 
AIC_models <- as.data.frame(AIC_models)
names(AIC_models) <- "AIC"
rownames(AIC_models) <- names(models)
AIC_models$K <- sapply(models, \(m) m$npar)                
AIC_models$LL <- sapply(models, logLik)                    
AIC_models <- AIC_models[order(AIC_models$AIC), ] 
AIC_models$deltaAIC <- AIC_models$AIC - AIC_models$AIC[1]        
.tmp <- exp(-1/2*AIC_models$deltaAIC)                            
AIC_models$weight <- .tmp/sum(.tmp)                              
AIC_models <- AIC_models[, c("K", "AIC", "deltaAIC", "weight", "LL")]  
apply(AIC_models, 2, signif, 4)        
##         K    AIC deltaAIC    weight     LL
## Season 20 -192.2     0.00 1.000e+00 116.10
## Null    5 -115.3    76.96 1.944e-17  62.63
AIC_models$`p value` <- sapply(list(m0, mm),
                               \(x) anova(m0, x)$`Pr(>Chi)`[2])
anova(m0, mm)
## Analysis of Deviance Table
## 
## Model 1: DirichReg(formula = items ~ 1, data = dieta)
## Model 2: DirichReg(formula = items ~ Season, data = dieta)
## 
##         Deviance N. par Difference df  Pr(>Chi)    
## Model 1  -125.26      5                            
## Model 2  -232.22     20     106.96 15 6.171e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
drop1(mm)
## Single term deletions
## 
## Model:
## items ~ Season
##                          Df Deviance     AIC    LRT Pr(>Chi)  
## <none>                       -232.22 -192.22                  
## Other_graminoids: Season  3  -230.09 -196.09 2.1260  0.54667  
## Other_herbaceous: Season  3  -229.71 -195.71 2.5149  0.47260  
## Woody: Season             3  -228.30 -194.30 3.9242  0.26977  
## Brachypodium: Season      3  -226.24 -192.24 5.9864  0.11228  
## Ampelodesmos: Season      3  -224.00 -190.00 8.2225  0.04163 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Model diagnostics
res <- residuals(mm, type = "standardized")
boxplot(res, main = "Residuals by Component (Potokka)")

fitted_vals <- fitted(mm)
par(mfrow = c(1, ncol(fitted_vals)))
for (i in 1:ncol(fitted_vals)) {
  plot(fitted_vals[, i], res[, i], main = colnames(fitted_vals)[i],
       xlab = "Fitted", ylab = "Residuals")
  abline(h = 0, col = "red")
}

# Prepare beta regression data
items2 <- items |> unclass() |> as.data.frame() |> cbind(Season = dieta$Season)

# Run beta models

#### ampelodesmos
mb_Ampelodesmos0 <- betareg(Ampelodesmos ~ Season,
                            data = items2)
mb_Ampelodesmos <- betareg(Ampelodesmos ~ Season|Season,
                           data = items2)
lrtest(mb_Ampelodesmos0, mb_Ampelodesmos)
## Likelihood ratio test
## 
## Model 1: Ampelodesmos ~ Season
## Model 2: Ampelodesmos ~ Season | Season
##   #Df LogLik Df  Chisq Pr(>Chisq)
## 1   5 21.151                     
## 2   8 22.576  3 2.8507     0.4152
lrtest(update(mb_Ampelodesmos0, ~1), mb_Ampelodesmos0)  
## Likelihood ratio test
## 
## Model 1: Ampelodesmos ~ 1
## Model 2: Ampelodesmos ~ Season
##   #Df  LogLik Df  Chisq Pr(>Chisq)    
## 1   2  8.7051                         
## 2   5 21.1512  3 24.892  1.626e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
em <- emmeans(mb_Ampelodesmos0, ~ Season)
contrast(em, "pairwise")
##  contrast         estimate     SE  df z.ratio p.value
##  winter - spring -0.000691 0.0297 Inf  -0.023  1.0000
##  winter - summer -0.264157 0.0349 Inf  -7.566  <.0001
##  winter - autumn -0.187964 0.0342 Inf  -5.500  <.0001
##  spring - summer -0.263466 0.0349 Inf  -7.541  <.0001
##  spring - autumn -0.187273 0.0342 Inf  -5.476  <.0001
##  summer - autumn  0.076192 0.0388 Inf   1.966  0.2010
## 
## P value adjustment: tukey method for comparing a family of 4 estimates
#### brachypodium
mb_Brachypodium0 <- betareg(Brachypodium ~ Season,
                            data = items2)
mb_Brachypodium <- betareg(Brachypodium ~ Season|Season,
                           data = items2)
lrtest(mb_Brachypodium0, mb_Brachypodium)
## Likelihood ratio test
## 
## Model 1: Brachypodium ~ Season
## Model 2: Brachypodium ~ Season | Season
##   #Df LogLik Df  Chisq Pr(>Chisq)  
## 1   5 25.981                       
## 2   8 29.492  3 7.0222    0.07119 .
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
lrtest(update(mb_Brachypodium0, ~1), mb_Brachypodium0)  
## Likelihood ratio test
## 
## Model 1: Brachypodium ~ 1
## Model 2: Brachypodium ~ Season
##   #Df LogLik Df Chisq Pr(>Chisq)    
## 1   2 15.892                        
## 2   5 25.981  3 20.18  0.0001558 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
em <- emmeans(mb_Brachypodium0, ~ Season)
contrast(em, "pairwise")
##  contrast        estimate     SE  df z.ratio p.value
##  winter - spring  -0.0175 0.0200 Inf  -0.877  0.8169
##  winter - summer  -0.1330 0.0230 Inf  -5.794  <.0001
##  winter - autumn  -0.1199 0.0227 Inf  -5.283  <.0001
##  spring - summer  -0.1154 0.0235 Inf  -4.921  <.0001
##  spring - autumn  -0.1023 0.0232 Inf  -4.411  0.0001
##  summer - autumn   0.0131 0.0258 Inf   0.508  0.9572
## 
## P value adjustment: tukey method for comparing a family of 4 estimates
#### other_graminoids 
mb_Other_graminoids0 <- betareg(Other_graminoids ~ Season,
                                data = items2)
mb_Other_graminoids <- betareg(Other_graminoids ~ Season|Season,
                               data = items2)
lrtest(mb_Other_graminoids0, mb_Other_graminoids)
## Likelihood ratio test
## 
## Model 1: Other_graminoids ~ Season
## Model 2: Other_graminoids ~ Season | Season
##   #Df LogLik Df  Chisq Pr(>Chisq)  
## 1   5 34.291                       
## 2   8 37.719  3 6.8562    0.07662 .
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
lrtest(update(mb_Other_graminoids0, ~1), mb_Other_graminoids0)
## Likelihood ratio test
## 
## Model 1: Other_graminoids ~ 1
## Model 2: Other_graminoids ~ Season
##   #Df LogLik Df  Chisq Pr(>Chisq)
## 1   2 32.337                     
## 2   5 34.291  3 3.9069     0.2717
em <- emmeans(mb_Other_graminoids0, ~ Season)
contrast(em, "pairwise")
##  contrast         estimate     SE  df z.ratio p.value
##  winter - spring -0.014063 0.0109 Inf  -1.288  0.5704
##  winter - summer -0.020343 0.0111 Inf  -1.826  0.2612
##  winter - autumn -0.020747 0.0112 Inf  -1.860  0.2457
##  spring - summer -0.006280 0.0116 Inf  -0.539  0.9495
##  spring - autumn -0.006684 0.0117 Inf  -0.573  0.9401
##  summer - autumn -0.000404 0.0119 Inf  -0.034  1.0000
## 
## P value adjustment: tukey method for comparing a family of 4 estimates
#### woody 
mb_Woody0 <- betareg(Woody ~ Season,
                     data = items2)
mb_Woody <- betareg(Woody ~ Season|Season,
                    data = items2)
lrtest(mb_Woody0, mb_Woody)
## Likelihood ratio test
## 
## Model 1: Woody ~ Season
## Model 2: Woody ~ Season | Season
##   #Df LogLik Df  Chisq Pr(>Chisq)
## 1   5 21.655                     
## 2   8 22.202  3 1.0935     0.7786
lrtest(update(mb_Woody0, ~1), mb_Woody0) 
## Likelihood ratio test
## 
## Model 1: Woody ~ 1
## Model 2: Woody ~ Season
##   #Df  LogLik Df  Chisq Pr(>Chisq)    
## 1   2  4.0245                         
## 2   5 21.6550  3 35.261  1.073e-07 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
em <- emmeans(mb_Woody0, ~ Season)
contrast(em, "pairwise")
##  contrast        estimate     SE  df z.ratio p.value
##  winter - spring   0.0314 0.0366 Inf   0.859  0.8261
##  winter - summer   0.4076 0.0323 Inf  12.627  <.0001
##  winter - autumn   0.3541 0.0336 Inf  10.529  <.0001
##  spring - summer   0.3762 0.0324 Inf  11.597  <.0001
##  spring - autumn   0.3227 0.0338 Inf   9.552  <.0001
##  summer - autumn  -0.0534 0.0290 Inf  -1.840  0.2545
## 
## P value adjustment: tukey method for comparing a family of 4 estimates
#### other_herbaceous 
mb_Other_herbaceous0 <- betareg(Other_herbaceous ~ Season,
                                data = items2)
mb_Other_herbaceous <- betareg(Other_herbaceous ~ Season|Season,
                               data = items2)
lrtest(mb_Other_herbaceous0, mb_Other_herbaceous)
## Likelihood ratio test
## 
## Model 1: Other_herbaceous ~ Season
## Model 2: Other_herbaceous ~ Season | Season
##   #Df LogLik Df  Chisq Pr(>Chisq)
## 1   5 37.987                     
## 2   8 41.078  3 6.1828      0.103
lrtest(update(mb_Other_herbaceous, ~1), mb_Other_herbaceous)  
## Likelihood ratio test
## 
## Model 1: Other_herbaceous ~ 1 | Season
## Model 2: Other_herbaceous ~ Season | Season
##   #Df LogLik Df  Chisq Pr(>Chisq)   
## 1   5 33.175                        
## 2   8 41.078  3 15.806   0.001242 **
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
em <- emmeans(mb_Other_herbaceous, ~ Season)
contrast(em, "pairwise")
##  contrast        estimate      SE  df z.ratio p.value
##  winter - spring -0.00165 0.01071 Inf  -0.154  0.9987
##  winter - summer  0.00835 0.00982 Inf   0.850  0.8303
##  winter - autumn -0.02832 0.00941 Inf  -3.010  0.0139
##  spring - summer  0.01000 0.00671 Inf   1.489  0.4441
##  spring - autumn -0.02667 0.00610 Inf  -4.369  0.0001
##  summer - autumn -0.03667 0.00435 Inf  -8.428  <.0001
## 
## P value adjustment: tukey method for comparing a family of 4 estimates
# Diet composition plot
pdieta <- dieta %>% 
  dplyr::select(Ampelodesmos:Other_herbaceous) %>%           # subconjunt amb dieta nom?s
  transmute(total = rowSums(.)) %>%         # calculem abund. total per individu
  bind_cols(dieta) %>%                         # ajuntem el total a dd
  mutate(across(Ampelodesmos:Other_herbaceous, ~.x/total))
ladieta <- pivot_longer(pdieta, cols = Ampelodesmos:Other_herbaceous,
                        names_to = "Species",
                        values_to = "p_i")
ladieta$Species <- factor(ladieta$Species, 
                          levels = c("Ampelodesmos", "Brachypodium", 
                                     "Other_graminoids", "Other_herbaceous", "Woody"),
                          labels = c("Ampelodesmos", "Brachypodium",
                                     "Other poaceae", "Other herbaceous", "Woody"))
ladieta$Season <- factor(ladieta$Season, 
                         levels = c("summer", "autumn", "winter", "spring"))

ggplot(ladieta, aes(Species, p_i)) +
  stat_summary(fun.data = mean_se, geom = "errorbar", width = 0.3) +
  stat_summary(fun = mean, geom = "col") +
  facet_wrap(~ Season, nrow = 1) +
  labs(title = "Diet Composition (Potokka)", x = NULL, y = NULL) +
  theme(aspect.ratio = 1, axis.text.x = element_text(angle = 70, hjust = 1),
        plot.title = element_text(hjust = 0.5, size = 14))

############ Section 3: Common or Crossbred Horses 
# Load and format diet data
dieta <- read_excel("Crossbred.xlsx")
dieta$Period <- factor(dieta$Period, levels = c("start", "end"))

# Prepare compositional data using DR_data (zeros are imputed, proportions sum to 1)
items <- dieta %>% dplyr::select(Woody:Other_herbaceous) %>% DR_data() 
## Warning in DR_data(.): not all rows sum up to 1 => normalization forced
##   some entries are 0 or 1 => transformation forced
# Reshape data for plotting
ddpc <- dieta %>% 
  dplyr::select(Period) %>% 
  bind_cols(data.frame(unclass(items))) %>% 
  pivot_longer(cols = Woody:Other_herbaceous,
               values_to = "pc", 
               names_to = "item")

# Relabel items for plotting
ddpc$item <- factor(ddpc$item, 
                    levels = c("Brachypodium", "Other_graminoids", "Fabaceae", 
                               "Other_herbaceous", "Woody"),
                    labels = c("Brachypodium", "Other poaceae", "Fabaceae",
                               "Other herbaceous", "Woody"))

# Ensure correct period order
ddpc$Period <- factor(ddpc$Period, levels = c("start", "end"))
# Fit null and period models
m0 <- DirichReg(items ~ 1, data = dieta)
mm <- DirichReg(items ~ Period, data = dieta)

# AIC model comparison
models <- list(Null = m0, Period = mm)
AIC_models <- sapply(models, AIC) %>% as.data.frame()
names(AIC_models) <- "AIC"
rownames(AIC_models) <- names(models)
AIC_models$K <- sapply(models, \(m) m$npar)        
AIC_models$LL <- sapply(models, logLik)           
AIC_models <- AIC_models[order(AIC_models$AIC), ]
AIC_models$deltaAIC <- AIC_models$AIC - AIC_models$AIC[1]
.tmp <- exp(-0.5 * AIC_models$deltaAIC)
AIC_models$weight <- .tmp / sum(.tmp)              
AIC_models <- AIC_models[, c("K", "AIC", "deltaAIC", "weight", "LL")]
AIC_models$`p value` <- sapply(list(m0, mm),
                               \(x) anova(m0, x)$`Pr(>Chi)`[2])
print(AIC_models)
##         K       AIC deltaAIC       weight        LL      p value
## Period 10 -230.0997  0.00000 1.000000e+00 125.04983 1.000000e+00
## Null    5 -148.2435 81.85621 1.679383e-18  79.12173 2.736933e-18
drop1(mm)
## Single term deletions
## 
## Model:
## items ~ Period
##                          Df Deviance     AIC     LRT  Pr(>Chi)    
## <none>                       -250.10 -230.10                      
## Other_graminoids: Period  1  -249.80 -231.80  0.2967   0.58599    
## Brachypodium: Period      1  -249.69 -231.69  0.4088   0.52259    
## Fabaceae: Period          1  -237.42 -219.42 12.6779   0.00037 ***
## Other_herbaceous: Period  1  -228.16 -210.16 21.9421 2.810e-06 ***
## Woody: Period             1  -226.87 -208.87 23.2312 1.436e-06 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Standardized residuals
res <- residuals(mm, type = "standardized")

# Boxplot of residuals by component
boxplot(res, main = "Boxplot of Deviance Residuals by Component")

# Residuals vs fitted for each component
fitted_vals <- fitted(mm)
par(mfrow = c(1, ncol(fitted_vals)))
for (i in 1:ncol(fitted_vals)) {
  plot(fitted_vals[, i], res[, i],
       main = colnames(fitted_vals)[i],
       xlab = "Fitted", ylab = "Residuals")
  abline(h = 0, col = "red")
}

# Convert DR_data back to standard data frame
items2 <- items |> unclass() |> as.data.frame() |> cbind(Period = dieta$Period)
mb_Woody0 <- betareg(Woody ~ Period, data = items2)
mb_Woody <- betareg(Woody ~ Period | Period, data = items2)
lrtest(mb_Woody0, mb_Woody)  # constant dispersion model is preferred
## Likelihood ratio test
## 
## Model 1: Woody ~ Period
## Model 2: Woody ~ Period | Period
##   #Df LogLik Df  Chisq Pr(>Chisq)
## 1   3 18.515                     
## 2   4 19.076  1 1.1214     0.2896
lrtest(update(mb_Woody0, ~1), mb_Woody0)  # Period effect is significant
## Likelihood ratio test
## 
## Model 1: Woody ~ 1
## Model 2: Woody ~ Period
##   #Df  LogLik Df  Chisq Pr(>Chisq)    
## 1   2  6.3342                         
## 2   3 18.5149  1 24.362  7.985e-07 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
mb_Brachypodium0 <- betareg(Brachypodium ~ Period, data = items2)
mb_Brachypodium <- betareg(Brachypodium ~ Period | Period, data = items2)
lrtest(mb_Brachypodium0, mb_Brachypodium)  # constant dispersion model is preferred
## Likelihood ratio test
## 
## Model 1: Brachypodium ~ Period
## Model 2: Brachypodium ~ Period | Period
##   #Df LogLik Df  Chisq Pr(>Chisq)
## 1   3 21.480                     
## 2   4 22.585  1 2.2105     0.1371
lrtest(update(mb_Brachypodium0, ~1), mb_Brachypodium0)  # Period effect is significant
## Likelihood ratio test
## 
## Model 1: Brachypodium ~ 1
## Model 2: Brachypodium ~ Period
##   #Df  LogLik Df  Chisq Pr(>Chisq)    
## 1   2  6.4911                         
## 2   3 21.4797  1 29.977  4.371e-08 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
mb_Fabaceae0 <- betareg(Fabaceae ~ Period, data = items2)
mb_Fabaceae <- betareg(Fabaceae ~ Period | Period, data = items2)
lrtest(mb_Fabaceae0, mb_Fabaceae)  # variable dispersion is better
## Likelihood ratio test
## 
## Model 1: Fabaceae ~ Period
## Model 2: Fabaceae ~ Period | Period
##   #Df LogLik Df Chisq Pr(>Chisq)  
## 1   3 31.578                      
## 2   4 34.004  1 4.852    0.02761 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
lrtest(update(mb_Fabaceae, ~1), mb_Fabaceae)  # Period effect is NOT significant
## Likelihood ratio test
## 
## Model 1: Fabaceae ~ 1 | Period
## Model 2: Fabaceae ~ Period | Period
##   #Df LogLik Df  Chisq Pr(>Chisq)
## 1   3 33.293                     
## 2   4 34.004  1 1.4221     0.2331
mb_Other_graminoids0 <- betareg(Other_graminoids ~ Period, data = items2)
mb_Other_graminoids <- betareg(Other_graminoids ~ Period | Period, data = items2)
lrtest(mb_Other_graminoids0, mb_Other_graminoids)  # variable dispersion is better
## Likelihood ratio test
## 
## Model 1: Other_graminoids ~ Period
## Model 2: Other_graminoids ~ Period | Period
##   #Df LogLik Df  Chisq Pr(>Chisq)  
## 1   3 35.027                       
## 2   4 37.664  1 5.2751    0.02163 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
lrtest(update(mb_Other_graminoids, ~1), mb_Other_graminoids)  # Period effect is significant
## Likelihood ratio test
## 
## Model 1: Other_graminoids ~ 1 | Period
## Model 2: Other_graminoids ~ Period | Period
##   #Df LogLik Df  Chisq Pr(>Chisq)    
## 1   3 30.430                         
## 2   4 37.664  1 14.469  0.0001425 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
mb_Other_herbaceous0 <- betareg(Other_herbaceous ~ Period, data = items2)
mb_Other_herbaceous <- betareg(Other_herbaceous ~ Period | Period, data = items2)
lrtest(mb_Other_herbaceous0, mb_Other_herbaceous)  # constant dispersion is preferred
## Likelihood ratio test
## 
## Model 1: Other_herbaceous ~ Period
## Model 2: Other_herbaceous ~ Period | Period
##   #Df LogLik Df  Chisq Pr(>Chisq)
## 1   3 33.825                     
## 2   4 34.875  1 2.0986     0.1474
lrtest(update(mb_Other_herbaceous0, ~1), mb_Other_herbaceous0)  # Period effect is significant
## Likelihood ratio test
## 
## Model 1: Other_herbaceous ~ 1
## Model 2: Other_herbaceous ~ Period
##   #Df LogLik Df  Chisq Pr(>Chisq)    
## 1   2 27.337                         
## 2   3 33.825  1 12.976  0.0003154 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
ggplot(ddpc, aes(item, pc)) +
  stat_summary(fun.data = mean_se, geom = "errorbar", width = 0.3) +
  stat_summary(fun = mean, geom = "col") +
  facet_wrap(~ Period, nrow = 1) +
  labs(title = "Diet Composition by Period", x = NULL, y = NULL) +
  theme(aspect.ratio = 1,
        axis.text.x = element_text(angle = 70, hjust = 1),
        plot.title = element_text(hjust = 0.5, size = 14))