Script : 49_question_GLMM # Installation
Chargement des packages, fonctions et des données
library(lme4)
library(aspe)
library(tidyverse)
library(aspe)
library(sjstats)
library(gt)
library(glmmTMB)
library(RVAideMemoire)
# library(lmerTest) # remplace lme4 automatiquement
library(ggh4x)
library(mgcv) # modele GAMMs
library(gratia)
library(patchwork)
library(lme4)
library(car) # fonction Anova()
library(gstat)#semi_variogramme
library(DHARMa) # Ajusting of the model
library(ggplotify)
library(ggpubr)
load(file = "../processed_data/selection_especes.rda")
load(file = "../processed_data/selection_pop_ope.rda")
load(file = "../processed_data/donnees_densite_eff_abs.rda")
load(file = "../processed_data/assemblage_tab_par_ope.rda")
source(file = "../R/zip_glmm_calcul_modele.R")
source(file = "../R/zip_glmm_application_modele.R")
source(file = "../R/gamm_calcul_modele.R")
source(file = "../R/gamm_application_modele.R")
source(file = "../R/adequate_data_for_model.R")
rdata_tables <- misc_nom_dernier_fichier(
repertoire = "../../../../Liste_rouge_BFC/raw_data",
pattern = "^tables")
load(rdata_tables) # Chargement des données
L’objectif principal de l’étude est d’évaluer les tendances démographiques des espèces de poissons d’eau douce à l’échelle de la région Bourgogne Franche-comté. Des séries chronologiques longues enregistrant plus d’une dizaine d’années ou 3 générations (critère A UICN) de données seront utilisées (sur un total disponible d’une vingtaine d’années). Ce travail s’inscrit dans la perspective de la création de la Liste rouge régionale des poissons d’eau douce de Bourgogne Franche-Comté et compte une trentaine d’espèces à évaluer.
L’OFB a mis en place depuis 1990 des réseaux de suivi temporel de l’état des milieux aquatiques à partir des peuplements de poissons. Les échantillonnages sont réalisés tous les ans ou tout les deux ans en fonction des réseaux pluriannuels des stations identiques selon deux protocoles distincts : - pêche par points (partielle) - pêche complète
L’ensemble des données sont stocké dans la base de données aspe de l’OFB.
Les tendances temporelles seront estimées par une analyse statistique de Modèles Additifs Généralisé Mixtes (GAMMs), de Modèles Linéaires Généralisé Mixtes (GLMM) ou de Zero-Inflated GLMM (ZIGLMM) ou Hurdle GLMM (HGLMM) en fonction de l’ajustement des modèles aux données.
Pour répondre à la question initiale, les modèles vont se construire à partir des variables suivantes :
La variable réponse : valeur, effectif des poissons variable quantitative discrète bornée
Les variables explicatives :
les co-variables :
annee, variable quantitative discrète bornée
ope_surface_calculee, la surface pêchée variable quantitative continue bornée
les facteurs :
pro_libelle, les protocoles utilisés (2 modalitées) variable qualitative nominal
sta_id, les stations d’échantillonages (163 modalitées) variable qualitative nominal
# preparer la table pour jointure
ope_selection <- ope_selection %>%
dplyr::select(ope_id, pop_id, sta_id)
# Ajout des coordonnées pour jointure avec df pour future analyse autocorrelation spatiale
coord_sta_id <- point_prelevement %>%
filter(pop_id %in% pop_serie_tempo) %>%
rename(x = pop_coordonnees_x, y = pop_coordonnees_y) %>%
select(pop_id, x, y) %>%
mutate(pop_id = as.factor(pop_id))
# prepéarer la table pour jointure
esp_ope_selection_join <- esp_ope_selection %>%
select(ope_id, ope_surface_calculee) %>%
distinct(ope_id, .keep_all = TRUE)
ope_effectif_glmm_abs <- ope_effectif_absences %>%
mef_ajouter_type_protocole() %>%
left_join(ope_selection, by = "ope_id") %>%
inner_join(esp_ope_selection_join, by = "ope_id") %>%
mutate(
valeur = as.numeric(valeur) ,
annee = as.numeric(annee),
ope_surface_calculee = as.numeric(ope_surface_calculee),
pro_libelle = as.factor(pro_libelle),
pop_id = as.factor(pop_id),
sta_id = as.factor(sta_id),
stade = as.factor(stade)
) %>%
left_join(coord_sta_id, by = "pop_id") %>%
mutate(x = as.numeric(x),
y = as.numeric(y))%>%
rename(espece = esp_code_alternatif)
truite_data_abs <- ope_effectif_glmm_abs %>%
filter(espece == "TRF")
head(truite_data_abs)
## # A tibble: 6 × 12
## ope_id espece indicateur valeur stade pro_libelle annee pop_id sta_id
## <int> <chr> <chr> <dbl> <fct> <fct> <dbl> <fct> <fct>
## 1 11207 TRF effectif_total 0 ind Pêche complète … 2014 67123 18684
## 2 11280 TRF effectif_total 2 ind Pêche complète … 2016 67123 18684
## 3 11903 TRF effectif_total 105 ind Pêche complète … 2016 81644 24171
## 4 11904 TRF effectif_total 182 ind Pêche complète … 2014 81644 24171
## 5 11905 TRF effectif_total 125 ind Pêche complète … 2012 81644 24171
## 6 11906 TRF effectif_total 160 ind Pêche complète … 2010 81644 24171
## # ℹ 3 more variables: ope_surface_calculee <dbl>, x <dbl>, y <dbl>
stats_esp <- ope_effectif_glmm_abs %>%
group_by(espece) %>%
summarise(
pct_zero = mean(valeur == 0) * 100,
pct_un = mean(valeur == 1) * 100,
pct_zero1 = mean(valeur <= 1) * 100,
n = n(),
.groups = "drop"
) %>%
mutate(
label = paste0(
"n=", n,
" 0:", round(pct_zero), "%",
" 1:", round(pct_un), "%"))
histogram_esp <- ggplot(data = ope_effectif_glmm_abs, aes(x = valeur)) +
facet_wrap2(
~ espece,
ncol = 3,
scales = "free",
axes = "all",
trim_blank = TRUE
) +
geom_histogram(bins = 30, fill = "steelblue4", color = "white", linewidth = 0.2) +
geom_vline(xintercept = 0, color = "firebrick", linetype = "dashed", linewidth = 0.5) +
geom_vline(xintercept = 1, color = "darkorange", linetype = "dotted", linewidth = 0.5) +
geom_label(
data = stats_esp,
mapping = aes(x = Inf, y = Inf, label = label),
hjust = 1.05, vjust = 3.5,
size = 4, fontface = "bold",
fill = "white", color = "steelblue4", label.size = 0.5
) +
scale_x_continuous() +
scale_y_continuous() +
labs(
x = "Effectif",
y = "Fréquence",
title = "Distribution des effectifs par espèce avec ajout des absences",
) +
theme_minimal(base_size = 11) +
theme(
strip.background = element_rect(fill = "grey88", color = NA),
strip.text = element_text(face = "bold", size = 9),
panel.background = element_rect(fill = "grey97", color = NA),
panel.grid.major = element_line(color = "grey90"),
panel.grid.minor = element_blank(),
plot.caption = element_text(size = 8, color = "grey50")
)
histogram_esp
# preparer la table pour jointure
ope_selection <- ope_selection %>%
dplyr::select(ope_id, pop_id, sta_id)
# Ajout des coordonnées pour jointure avec df pour future analyse autocorrelation spatiale
coord_sta_id <- point_prelevement %>%
filter(pop_id %in% pop_serie_tempo) %>%
rename(x = pop_coordonnees_x, y = pop_coordonnees_y) %>%
select(pop_id, x, y) %>%
mutate(pop_id = as.factor(pop_id))
# prepéarer la table pour jointure
esp_ope_selection_join <- esp_ope_selection %>%
select(ope_id, ope_surface_calculee) %>%
distinct(ope_id, .keep_all = TRUE)
ope_effectif_glmm_sans_abs <- ope_effectif %>%
mef_ajouter_type_protocole() %>%
left_join(ope_selection, by = "ope_id") %>%
inner_join(esp_ope_selection_join, by = "ope_id") %>%
mutate(
valeur = as.numeric(valeur) ,
annee = as.numeric(annee),
ope_surface_calculee = as.numeric(ope_surface_calculee),
pro_libelle = as.factor(pro_libelle),
pop_id = as.factor(pop_id),
sta_id = as.factor(sta_id),
stade = as.factor(stade)
) %>%
left_join(coord_sta_id, by = "pop_id") %>%
mutate(x = as.numeric(x),
y = as.numeric(y))%>%
rename(espece = esp_code_alternatif) %>%
filter(stade == "ind") # Filtrer les stades, ici les indetermines
truite_data_sans_abs <- ope_effectif_glmm_sans_abs %>%
filter(espece == "TRF")
head(truite_data_sans_abs)
## # A tibble: 6 × 12
## ope_id espece indicateur valeur stade pro_libelle annee pop_id sta_id
## <int> <chr> <chr> <dbl> <fct> <fct> <dbl> <fct> <fct>
## 1 11280 TRF effectif_total 2 ind Pêche complète … 2016 67123 18684
## 2 11903 TRF effectif_total 105 ind Pêche complète … 2016 81644 24171
## 3 11904 TRF effectif_total 182 ind Pêche complète … 2014 81644 24171
## 4 11905 TRF effectif_total 125 ind Pêche complète … 2012 81644 24171
## 5 11906 TRF effectif_total 160 ind Pêche complète … 2010 81644 24171
## 6 11907 TRF effectif_total 167 ind Pêche complète … 2008 81644 24171
## # ℹ 3 more variables: ope_surface_calculee <dbl>, x <dbl>, y <dbl>
stats_esp_sans_abs <- ope_effectif_glmm_sans_abs %>%
group_by(espece) %>%
summarise(
pct_zero = mean(valeur == 0) * 100,
pct_un = mean(valeur == 1) * 100,
pct_zero1 = mean(valeur <= 1) * 100,
n = n(),
.groups = "drop"
) %>%
mutate(
label = paste0(
"n=", n,
" 0:", round(pct_zero), "%",
" 1:", round(pct_un), "%"))
histogram_esp_sans_abs <- ggplot(data = ope_effectif_glmm_sans_abs, aes(x = valeur)) +
facet_wrap2(
~ espece,
ncol = 3,
scales = "free",
axes = "all",
trim_blank = TRUE
) +
geom_histogram(bins = 30, fill = "steelblue4", color = "white", linewidth = 0.2) +
geom_vline(xintercept = 0, color = "firebrick", linetype = "dashed", linewidth = 0.5) +
geom_vline(xintercept = 1, color = "darkorange", linetype = "dotted", linewidth = 0.5) +
geom_label(
data = stats_esp_sans_abs,
mapping = aes(x = Inf, y = Inf, label = label),
hjust = 1.05, vjust = 3.5,
size = 4, fontface = "bold",
fill = "white", color = "steelblue4", label.size = 0.5
) +
scale_x_continuous() +
scale_y_continuous() +
labs(
x = "Effectif",
y = "Fréquence",
title = "Distribution des effectifs par espèce sans ajout des absences",
) +
theme_minimal(base_size = 11) +
theme(
strip.background = element_rect(fill = "grey88", color = NA),
strip.text = element_text(face = "bold", size = 9),
panel.background = element_rect(fill = "grey97", color = NA),
panel.grid.major = element_line(color = "grey90"),
panel.grid.minor = element_blank(),
plot.caption = element_text(size = 8, color = "grey50")
)
histogram_esp_sans_abs
mod_zi_1.0 <- glmmTMB(
valeur ~ annee + offset(log(ope_surface_calculee)) +pro_libelle + (1 |
sta_id) ,
data = truite_data_abs,
family = poisson(link = "log"),
ziformula = ~ 1
)
mod_zi_1.1 <- glmmTMB(
valeur ~ annee + offset(log(ope_surface_calculee)) + pro_libelle + (1 | sta_id) ,
family = nbinom2(link = "log"),
data = truite_data_abs,
ziformula = ~ 1
)
mod_zi_1.2 <- glmmTMB(
valeur ~ annee + offset(log(ope_surface_calculee)) + pro_libelle + (1 | sta_id) ,
family = truncated_poisson(link = "log"),
data = truite_data_abs,
ziformula = ~ 1
)
mod_zi_1.3 <- glmmTMB(
valeur ~ annee + offset(log(ope_surface_calculee)) + pro_libelle + (1 | sta_id) ,
family = truncated_nbinom2(link = "log"),
data = truite_data_abs,
ziformula = ~ 1
)
On selectionne à l’aide du critère AIC le meilleur modèle c’est à dire le modèle avec le plus petit AIC.
AIC(mod_zi_1.0, mod_zi_1.1, mod_zi_1.2, mod_zi_1.3)
## df AIC
## mod_zi_1.0 5 13700.722
## mod_zi_1.1 6 7000.222
## mod_zi_1.2 5 15234.411
## mod_zi_1.3 6 8597.858
res_mod_zi_1.0 <- as.ggplot(~ plotresid(mod_zi_1.0))
res_mod_zi_1.1 <- as.ggplot(~ plotresid(mod_zi_1.1))
res_mod_zi_1.2 <- as.ggplot(~ plotresid(mod_zi_1.2))
res_mod_zi_1.3 <- as.ggplot(~ plotresid(mod_zi_1.3))
ggarrange(
res_mod_zi_1.0,
res_mod_zi_1.1,
res_mod_zi_1.2,
res_mod_zi_1.3,
ncol = 2,
nrow = 2,
labels = c("poisson", "nbinom2", "truncated_poisson", "truncated_nbinom2"),
font.label = list(
size = 13,
color = "darkred",
face = "bold",
family = NULL
),
hjust = -0.1,
vjust = 1.6,
align = c("none", "h", "v", "hv")
)
sim_res_mod_zi_1.0 <- as.ggplot(~ plotResiduals(simulateResiduals(fittedModel = mod_zi_1.0, n = 1000), quantreg = T))
sim_res_mod_zi_1.1 <- as.ggplot(~ plotResiduals(simulateResiduals(fittedModel = mod_zi_1.1, n = 1000), quantreg = T))
sim_res_mod_zi_1.2 <- as.ggplot(~ plotResiduals(simulateResiduals(fittedModel = mod_zi_1.2, n = 1000), quantreg = T))
sim_res_mod_zi_1.3 <- as.ggplot(~ plotResiduals(simulateResiduals(fittedModel = mod_zi_1.3, n = 1000), quantreg = T))
ggarrange(
sim_res_mod_zi_1.0,
sim_res_mod_zi_1.1,
sim_res_mod_zi_1.2,
sim_res_mod_zi_1.3,
ncol = 2,
nrow = 2,
labels = c("poisson", "nbinom2", "truncated_poisson", "truncated_nbinom2"),
font.label = list(
size = 13,
color = "darkred",
face = "bold",
family = NULL
),
hjust = -0.1,
vjust = 1.6,
align = c("none", "h", "v", "hv")
)
summary(mod_zi_1.1)
## Family: nbinom2 ( log )
## Formula:
## valeur ~ annee + offset(log(ope_surface_calculee)) + pro_libelle +
## (1 | sta_id)
## Zero inflation: ~1
## Data: truite_data_abs
##
## AIC BIC logLik -2*log(L) df.resid
## 7000.2 7033.1 -3494.1 6988.2 1754
##
## Random effects:
##
## Conditional model:
## Groups Name Variance Std.Dev.
## sta_id (Intercept) 15.44 3.929
## Number of obs: 1760, groups: sta_id, 163
##
## Dispersion parameter for nbinom2 family (): 2.84
##
## Conditional model:
## Estimate Std. Error
## (Intercept) 43.815919 10.189538
## annee -0.024354 0.005042
## pro_libellePêche partielle par points (grand milieu) -4.516801 0.774709
## z value Pr(>|z|)
## (Intercept) 4.30 1.71e-05 ***
## annee -4.83 1.36e-06 ***
## pro_libellePêche partielle par points (grand milieu) -5.83 5.53e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Zero-inflation model:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -20.48 1725.09 -0.012 0.991
Anova(mod_zi_1.3)
## Analysis of Deviance Table (Type II Wald chisquare tests)
##
## Response: valeur
## Chisq Df Pr(>Chisq)
## annee 12.198 1 0.0004784 ***
## pro_libelle 8.348 1 0.0038610 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
mod_zi_1.0 <- glmmTMB(
valeur ~ annee + offset(log(ope_surface_calculee)) +pro_libelle + (1 |
sta_id) ,
data = truite_data_sans_abs,
family = poisson(link = "log"),
ziformula = ~ 0
)
mod_zi_1.1 <- glmmTMB(
valeur ~ annee + offset(log(ope_surface_calculee)) + pro_libelle + (1 | sta_id) ,
family = nbinom2(link = "log"),
data = truite_data_sans_abs,
ziformula = ~ 0
)
mod_zi_1.2 <- glmmTMB(
valeur ~ annee + offset(log(ope_surface_calculee)) + pro_libelle + (1 | sta_id) ,
family = truncated_poisson(link = "log"),
data = truite_data_sans_abs,
ziformula = ~ 0
)
mod_zi_1.3 <- glmmTMB(
valeur ~ annee + offset(log(ope_surface_calculee)) + pro_libelle + (1 | sta_id) ,
family = truncated_nbinom2(link = "log"),
data = truite_data_sans_abs,
ziformula = ~ 0
)
On selectionne à l’aide du critère AIC le meilleur modèle c’est à dire le modèle avec le plus petit AIC.
AIC(mod_zi_1.0, mod_zi_1.1, mod_zi_1.2, mod_zi_1.3)
## df AIC
## mod_zi_1.0 4 12867.592
## mod_zi_1.1 5 6263.330
## mod_zi_1.2 4 12804.003
## mod_zi_1.3 5 6167.449
res_mod_zi_1.0 <- as.ggplot(~ plotresid(mod_zi_1.0))
res_mod_zi_1.1 <- as.ggplot(~ plotresid(mod_zi_1.1))
res_mod_zi_1.2 <- as.ggplot(~ plotresid(mod_zi_1.2))
res_mod_zi_1.3 <- as.ggplot(~ plotresid(mod_zi_1.3))
ggarrange(
res_mod_zi_1.0,
res_mod_zi_1.1,
res_mod_zi_1.2,
res_mod_zi_1.3,
ncol = 2,
nrow = 2,
labels = c("poisson", "nbinom2", "truncated_poisson", "truncated_nbinom2"),
font.label = list(
size = 13,
color = "darkred",
face = "bold",
family = NULL
),
hjust = -0.1,
vjust = 1.6,
align = c("none", "h", "v", "hv")
)
sim_res_mod_zi_1.0 <- as.ggplot(~ plotResiduals(simulateResiduals(fittedModel = mod_zi_1.0, n = 1000), quantreg = T))
sim_res_mod_zi_1.1 <- as.ggplot(~ plotResiduals(simulateResiduals(fittedModel = mod_zi_1.1, n = 1000), quantreg = T))
sim_res_mod_zi_1.2 <- as.ggplot(~ plotResiduals(simulateResiduals(fittedModel = mod_zi_1.2, n = 1000), quantreg = T))
sim_res_mod_zi_1.3 <- as.ggplot(~ plotResiduals(simulateResiduals(fittedModel = mod_zi_1.3, n = 1000), quantreg = T))
ggarrange(
sim_res_mod_zi_1.0,
sim_res_mod_zi_1.1,
sim_res_mod_zi_1.2,
sim_res_mod_zi_1.3,
ncol = 2,
nrow = 2,
labels = c("poisson", "nbinom2", "truncated_poisson", "truncated_nbinom2"),
font.label = list(
size = 13,
color = "darkred",
face = "bold",
family = NULL
),
hjust = -0.1,
vjust = 1.6,
align = c("none", "h", "v", "hv")
)
summary(mod_zi_1.3)
## Family: truncated_nbinom2 ( log )
## Formula:
## valeur ~ annee + offset(log(ope_surface_calculee)) + pro_libelle +
## (1 | sta_id)
## Data: truite_data_sans_abs
##
## AIC BIC logLik -2*log(L) df.resid
## 6167.4 6190.9 -3078.7 6157.4 804
##
## Random effects:
##
## Conditional model:
## Groups Name Variance Std.Dev.
## sta_id (Intercept) 3.49 1.868
## Number of obs: 809, groups: sta_id, 100
##
## Dispersion parameter for truncated_nbinom2 family (): 3.11
##
## Conditional model:
## Estimate Std. Error
## (Intercept) 28.511894 9.307772
## annee -0.016121 0.004616
## pro_libellePêche partielle par points (grand milieu) -1.130207 0.391173
## z value Pr(>|z|)
## (Intercept) 3.063 0.002190 **
## annee -3.493 0.000478 ***
## pro_libellePêche partielle par points (grand milieu) -2.889 0.003861 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Anova(mod_zi_1.3)
## Analysis of Deviance Table (Type II Wald chisquare tests)
##
## Response: valeur
## Chisq Df Pr(>Chisq)
## annee 12.1980 1 0.0004784 ***
## pro_libelle 8.3479 1 0.0038613 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1