Document complémentaire au module 4 du cours SDD II de 2025-2026. Distribué sous licence CC BY-NC-SA 4.0.
Veuillez vous référer au cours en ligne pour les explications et les interprétations de cette analyse.
Installer un environnement R adéquat pour reproduire cette analyse.
# Configuration de R en dialecte SciViews::R pour la modélisation
SciViews::R("model", lang = "fr")
# Importation et préparation des données
dune <- sbind_cols(
read("dune", package = "vegan") |> sselect(Lolipere),
read("dune.env", package = "vegan") |> sselect(A1, Moisture, Management)
) %>.%
smutate(., Management = case_when(
Management == "NM" ~ "conservation",
.default = "culture") |> factor())
skimr::skim(dune)| Name | dune |
| Number of rows | 20 |
| Number of columns | 4 |
| _______________________ | |
| Column type frequency: | |
| factor | 2 |
| numeric | 2 |
| ________________________ | |
| Group variables | None |
Variable type: factor
| skim_variable | n_missing | complete_rate | ordered | n_unique | top_counts |
|---|---|---|---|---|---|
| Moisture | 0 | 1 | TRUE | 4 | 1: 7, 5: 7, 2: 4, 4: 2 |
| Management | 0 | 1 | FALSE | 2 | cul: 14, con: 6 |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| Lolipere | 0 | 1 | 2.90 | 2.83 | 0.0 | 0.0 | 2.0 | 6.00 | 7.0 | ▇▃▁▂▆ |
| A1 | 0 | 1 | 4.85 | 2.18 | 2.8 | 3.5 | 4.2 | 5.73 | 11.5 | ▇▂▁▁▁ |
# Abondance de L. perenne
chart(data = dune, ~ Lolipere) +
geom_bar() +
labs(x = "Abondance [nbr de plants/quadrat]",
y = "Nombre de sites")# Table de contingence humidité du sol versus mode de gestion des dunes
table(Humidité = dune$Moisture, Gestion = dune$Management) |>
tabularise()Humidité | Gestion | |||
|---|---|---|---|---|
conservation | culture | Total | ||
1 | Count | 1 (5.0%) | 6 (30.0%) | 7 (35.0%) |
Mar. pct (1) | 16.7% ; 14.3% | 42.9% ; 85.7% | ||
2 | Count | 1 (5.0%) | 3 (15.0%) | 4 (20.0%) |
Mar. pct | 16.7% ; 25.0% | 21.4% ; 75.0% | ||
4 | Count | 0 (0.0%) | 2 (10.0%) | 2 (10.0%) |
Mar. pct | 0.0% ; 0.0% | 14.3% ; 100.0% | ||
5 | Count | 4 (20.0%) | 3 (15.0%) | 7 (35.0%) |
Mar. pct | 66.7% ; 57.1% | 21.4% ; 42.9% | ||
Total | Count | 6 (30.0%) | 14 (70.0%) | 20 (100.0%) |
(1) Columns and rows percentages | ||||
# Abondance de L. perenne en fonction de l'épaisseur de la couche A1 du sol
chart(data = dune, Lolipere ~ A1) +
geom_point() +
labs(x = "Épaisseur de la couche A1 [cm]",
y = "Abondance [nbr de plants/quadrat]")# GLM de famille poisson
dune_glm <- glm(data = dune, Lolipere ~ A1, family = poisson)
summary_(dune_glm) |> tabularise()
| ||||
|---|---|---|---|---|
Terme | Valeur estimée | Ecart type | Valeur de z | Valeur de p |
| 3.569 | 0.591 | 6.04 | 1.53·10-09 |
| -0.607 | 0.154 | -3.94 | 8.11·10-05 |
0 <= '***' < 0.001 < '**' < 0.01 < '*' < 0.05 | ||||
(Paramètre de dispersion pour une Poisson family: 1) | ||||
# Même modèle, mais en GLM quasi-poisson
dune_glm_quasi <- glm(data = dune, Lolipere ~ A1, family = quasipoisson)
summary_(dune_glm_quasi) |> tabularise()
| ||||
|---|---|---|---|---|
Terme | Valeur estimée | Ecart type | Valeur de t | Valeur de p |
| 3.569 | 0.771 | 4.63 | 0.000209 |
| -0.607 | 0.201 | -3.02 | 0.007367 |
0 <= '***' < 0.001 < '**' < 0.01 < '*' < 0.05 | ||||
(Paramètre de dispersion pour une Quasi-Poisson family: 1.704) | ||||
# Modèle GLM poisson plus complet (avec plus de variables indépendantes)
dune_glm2 <- glm(data = dune, Lolipere ~ A1 + Management + Moisture,
family = poisson)
summary_(dune_glm2) |> tabularise()
| ||||
|---|---|---|---|---|
Terme | Valeur estimée | Ecart type | Valeur de z | Valeur de p |
| 0.454 | 1.002 | 0.453 | 0.6508 |
| -0.344 | 0.159 | -2.167 | 0.0302 |
| 1.921 | 0.734 | 2.616 | 0.0089 |
| -1.066 | 0.431 | -2.475 | 0.0133 |
| 0.153 | 0.460 | 0.333 | 0.7394 |
| 0.732 | 0.517 | 1.416 | 0.1567 |
0 <= '***' < 0.001 < '**' < 0.01 < '*' < 0.05 | ||||
(Paramètre de dispersion pour une Poisson family: 1) | ||||
# Comparaison des deux modèles imbriqués par test Chi-carré
anova(dune_glm, dune_glm2, test = "Chisq") |> tabularise()Modèle | Ddl des résidus | Déviance résiduelle | Ddl | Déviance | Valeur de p | |
|---|---|---|---|---|---|---|
Lolipere ~ A1 | 18 | 41.4 | ||||
Lolipere ~ A1 + Management + Moisture | 14 | 14.2 | 4 | 27.3 | 1.75·10-05 | *** |
0 <= '***' < 0.001 < '**' < 0.01 < '*' < 0.05 | ||||||
# Exemple de prédictions en utilisant un modèle GLM
new_sites <- dtbl_rows(
~A1, ~Moisture, ~Management,
3, 1, "conservation",
3, 1, "culture",
5, 2, "conservation",
5, 2, "culture"
) %>.%
mutate(., Moisture = ordered(Moisture, levels = c(1, 2, 4, 5)),
Management = factor(Management))
# Probabilité d'abondance de L. perenne en ces sites
new_sites$pred <- predict(dune_glm2,
newdata = new_sites, type = "response")
new_sites## # A tibble: 4 × 4
## A1 Moisture Management pred
## <dbl> <ord> <fct> <dbl>
## 1 3 1 conservation 1.05
## 2 3 1 culture 7.18
## 3 5 2 conservation 0.543
## 4 5 2 culture 3.71
# Graphique des observations avec distinction par gestion et humidité
chart(data = dune, Lolipere ~ A1 %size=% Moisture %col=% Management) +
geom_point(alpha = 0.7) +
labs(x = "Épaisseur de la couche A1 [cm]",
y = "Abondance [nbr de plants/quadrat]")# Préparation des données de maturation d'ovocytes par dose d'hypoxanthine
ovo <- dtbl_rows(
~hypo, ~mat, ~tot,
4, 0, 32,
3, 3, 23,
2, 12, 24,
1, 24, 32,
0.5, 26, 29,
0.25, 28, 30,
0, 35, 35
) %>.%
mutate(., prop = mat/tot)
# Graphique général
chart(data = ovo, prop ~ hypo) +
geom_point() +
labs(x = "Hypoxanthine [µM]",
y = "Fraction d'ovocytes matures")# GLM binomiale avec proportions ; notez bien l'utilisation de weights=... ici !
ovo_glm <- glm(data = ovo, prop ~ hypo,
family = binomial, weights = ovo$tot)
summary_(ovo_glm) |> tabularise()Modèle linéaire généralisé | ||||
|---|---|---|---|---|
| ||||
Terme | Valeur estimée | Ecart type | Valeur de z | Valeur de p |
| 3.27 | 0.407 | 8.03 | 9.54·10-16 |
| -1.78 | 0.228 | -7.83 | 4.80·10-15 |
0 <= '***' < 0.001 < '**' < 0.01 < '*' < 0.05 | ||||
(Paramètre de dispersion pour une Binomial family: 1) | ||||
# Autre formulation de GLM binomiale ne nécessitant pas d'indiquer weights=...
ovo_glm_bis <- glm(data = ovo, cbind(mat, tot) ~ hypo,
family = binomial)
summary_(ovo_glm) |> tabularise()
| ||||
|---|---|---|---|---|
Terme | Valeur estimée | Ecart type | Valeur de z | Valeur de p |
| 3.27 | 0.407 | 8.03 | 9.54·10-16 |
| -1.78 | 0.228 | -7.83 | 4.80·10-15 |
0 <= '***' < 0.001 < '**' < 0.01 < '*' < 0.05 | ||||
(Paramètre de dispersion pour une Binomial family: 1) | ||||
# Graphique de notre modèle GLM binomiale avec proportions
chart(data = ovo, prop ~ hypo) +
geom_point() +
stat_smooth(method = "glm", method.args = list(family = binomial),
formula = y ~ x, se = FALSE) +
labs(x = "Hypoxanthine [µM]",
y = "Fraction d'ovocytes matures")# Préparation des données sur les acariens
mite <- sbind_cols(
read("mite", package = "vegan") |> sselect(Oribatl1),
read("mite.env", package = "vegan") |> sselect(WatrCont, Topo)
) %>.%
smutate(., Oribatl1 = case_when(
Oribatl1 == 0 ~ "absent",
.default = "present") |> factor())
skimr::skim(mite)| Name | mite |
| Number of rows | 70 |
| Number of columns | 3 |
| _______________________ | |
| Column type frequency: | |
| factor | 2 |
| numeric | 1 |
| ________________________ | |
| Group variables | None |
Variable type: factor
| skim_variable | n_missing | complete_rate | ordered | n_unique | top_counts |
|---|---|---|---|---|---|
| Oribatl1 | 0 | 1 | FALSE | 2 | abs: 40, pre: 30 |
| Topo | 0 | 1 | FALSE | 2 | Bla: 44, Hum: 26 |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| WatrCont | 0 | 1 | 410.64 | 142.36 | 134.13 | 314.13 | 398.47 | 492.82 | 826.96 | ▃▇▆▂▁ |
# Graphique des données par rapport au contenu en eau et à la topographie
chart(data = mite, Oribatl1 ~ WatrCont | Topo) +
geom_point(alpha = 0.5) +
labs(x = "Teneur en eau [g/L]", y = "Larves d'acariens")# Modèle GLM binomial à partir de données binaires
mite_glm <- glm(data = mite, Oribatl1 ~ WatrCont * Topo,
family = binomial)
summary_(mite_glm) |> tabularise()Modèle linéaire généralisé | ||||
|---|---|---|---|---|
| ||||
Terme | Valeur estimée | Ecart type | Valeur de z | Valeur de p |
| 3.2198 | 1.63171 | 1.9733 | 0.0485 |
| -0.0104 | 0.00406 | -2.5542 | 0.0106 |
| -0.0652 | 2.36999 | -0.0275 | 0.9781 |
| 0.0042 | 0.00609 | 0.6897 | 0.4904 |
0 <= '***' < 0.001 < '**' < 0.01 < '*' < 0.05 | ||||
(Paramètre de dispersion pour une Binomial family: 1) | ||||
# Modèle GLM binomial simplifié sans Topo
mite_glm2 <- glm(data = mite, Oribatl1 ~ WatrCont,
family = binomial)
summary_(mite_glm2) |> tabularise()
| ||||
|---|---|---|---|---|
Terme | Valeur estimée | Ecart type | Valeur de z | Valeur de p |
| 3.7513 | 1.10988 | 3.38 | 0.000725 |
| -0.0102 | 0.00277 | -3.67 | 0.000241 |
0 <= '***' < 0.001 < '**' < 0.01 < '*' < 0.05 | ||||
(Paramètre de dispersion pour une Binomial family: 1) | ||||
# Comparaison des deux modèles imbriqués par test Chi-carré
anova(mite_glm, mite_glm2, test = "Chisq")## Analysis of Deviance Table
##
## Model 1: Oribatl1 ~ WatrCont * Topo
## Model 2: Oribatl1 ~ WatrCont
## Resid. Df Resid. Dev Df Deviance Pr(>Chi)
## 1 66 67.694
## 2 68 74.596 -2 -6.9019 0.03172 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Modèle GLM binomial avec Topo, mais sans interactions
mite_glm3 <- glm(data = mite, Oribatl1 ~ WatrCont + Topo,
family = binomial)
summary_(mite_glm3) |> tabularise()
| ||||
|---|---|---|---|---|
Terme | Valeur estimée | Ecart type | Valeur de z | Valeur de p |
| 2.56361 | 1.22983 | 2.08 | 0.03711 |
| -0.00869 | 0.00295 | -2.94 | 0.00324 |
| 1.52715 | 0.61449 | 2.49 | 0.01295 |
0 <= '***' < 0.001 < '**' < 0.01 < '*' < 0.05 | ||||
(Paramètre de dispersion pour une Binomial family: 1) | ||||
# Comparaison du dernier modèle avec le modèle complet par test Chi-carré
anova(mite_glm, mite_glm3, test = "Chisq")## Analysis of Deviance Table
##
## Model 1: Oribatl1 ~ WatrCont * Topo
## Model 2: Oribatl1 ~ WatrCont + Topo
## Resid. Df Resid. Dev Df Deviance Pr(>Chi)
## 1 66 67.694
## 2 67 68.169 -1 -0.47444 0.491
# Exemple d'utilisation du modèle GLM binomial pour des prédictions
new_soils <- dtbl_rows(
~WatrCont, ~Topo,
150, "Blanket",
500, "Blanket",
800, "Blanket",
200, "Hummock",
400, "Hummock"
)
# Probabilité de larves d'acariens pour ces sols
new_soils$P <- predict(mite_glm3,
newdata = new_soils, type = "response")
new_soils## # A tibble: 5 × 3
## WatrCont Topo P
## <dbl> <chr> <dbl>
## 1 150 Blanket 0.779
## 2 500 Blanket 0.144
## 3 800 Blanket 0.0122
## 4 200 Hummock 0.913
## 5 400 Hummock 0.649
# Transformer la variable présence/absence en 0/1 avant de faire le graphique
mutate(mite, Ori = as.numeric(Oribatl1 == "present")) %>.%
chart(data = ., Ori ~ WatrCont %col=% Topo) +
geom_point(alpha = 0.5) +
stat_smooth(
method = "glm",
method.args = list(family = binomial),
formula = y ~ x,
se = TRUE) +
labs(x = "Teneur en eau [g/L]", y = "Probabilité de présence")# Données sur la mobilité des spermatozoïdes en fonction de la dose d'éthanol
spe <- dtbl_rows(
~donor, ~conc, ~mobile, ~total,
1, 0.0, 236, 301,
1, 0.1, 238, 301,
1, 0.5, 115, 154,
1, 1.0, 105, 196,
1, 2.0, 182, 269,
2, 0.0, 92, 150,
2, 0.1, 60, 111,
2, 0.5, 63, 131,
2, 1.0, 46, 95,
2, 2.0, 50, 125,
3, 0.0, 100, 123,
3, 0.1, 91, 117,
3, 0.5, 132, 162,
3, 1.0, 145, 187,
3, 2.0, 52, 92,
4, 0.0, 83, 113,
4, 0.1, 104, 123,
4, 0.5, 65, 87,
4, 1.0, 93, 136,
4, 2.0, 78, 117,
5, 0.0, 127, 152,
5, 0.1, 82, 114,
5, 0.5, 55, 84,
5, 1.0, 80, 103,
5, 2.0, 98, 120,
6, 0.0, 62, 77,
6, 0.1, 65, 79,
6, 0.5, 63, 72,
6, 1.0, 57, 67,
6, 2.0, 39, 66,
7, 0.0, 91, 116,
7, 0.1, 51, 71,
7, 0.5, 70, 87,
7, 1.0, 53, 72,
7, 2.0, 59, 82,
8, 0.0, 121, 137,
8, 0.1, 80, 98,
8, 0.5, 100, 122,
8, 1.0, 126, 157,
8, 2.0, 98, 122
)
# Réencodage de ces données
spe <- smutate(spe, mob_frac = mobile / total, donor = as.factor(donor), conc = as.numeric(conc))
head(spe)## # A tibble: 6 × 5
## donor conc mobile total mob_frac
## <fct> <dbl> <dbl> <dbl> <dbl>
## 1 1 0 236 301 0.784
## 2 1 0.1 238 301 0.791
## 3 1 0.5 115 154 0.747
## 4 1 1 105 196 0.536
## 5 1 2 182 269 0.677
## 6 2 0 92 150 0.613
# Modèle GLLM binomial mixte complet (attention : tabularise() pas utilisable)
spe_m1 <- lme4::glmer(data = spe, cbind(mobile, total - mobile) ~ conc + (conc | donor),
family = binomial(link = "logit"))
summary_(spe_m1)## Generalized linear mixed model fit by maximum likelihood (Laplace Approximation) ['glmerMod']
## Family: binomial ( logit )
## Formula: cbind(mobile, total - mobile) ~ conc + (conc | donor)
## Data: spe
##
## AIC BIC logLik -2*log(L) df.resid
## 320.3 328.7 -155.1 310.3 35
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -4.9916 -0.7375 0.0028 0.9353 1.8933
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## donor (Intercept) 0.16977 0.4120
## conc 0.02106 0.1451 -0.02
## Number of obs: 40, groups: donor, 8
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 1.26479 0.15390 8.219 < 2e-16 ***
## conc -0.29582 0.06886 -4.296 1.74e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr)
## conc -0.163
# Graphique du modèle GLMM complet
chart(data = spe, mob_frac ~ conc %col=% donor) +
geom_point() +
geom_line(f_aes(fitted(spe_m1) ~ conc %col=% donor)) +
labs(x = "Ethanol [%]",
y = "Mobilité des spermatozoïdes [%]",
col = "Donneur")# Modèle GLMM binomial simplifié
spe_m2 <- lme4::glmer(data = spe,
cbind(mobile, total - mobile) ~ conc + (1 | donor),
family = binomial(link = "logit"))
anova(spe_m1, spe_m2)## Data: spe
## Models:
## spe_m2: cbind(mobile, total - mobile) ~ conc + (1 | donor)
## spe_m1: cbind(mobile, total - mobile) ~ conc + (conc | donor)
## npar AIC BIC logLik -2*log(L) Chisq Df Pr(>Chisq)
## spe_m2 3 319.58 324.65 -156.79 313.58
## spe_m1 5 320.28 328.72 -155.14 310.28 3.302 2 0.1919
## Generalized linear mixed model fit by maximum likelihood (Laplace Approximation) ['glmerMod']
## Family: binomial ( logit )
## Formula: cbind(mobile, total - mobile) ~ conc + (1 | donor)
## Data: spe
##
## AIC BIC logLik -2*log(L) df.resid
## 319.6 324.6 -156.8 313.6 37
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -5.0521 -0.5711 0.0252 0.9661 2.8884
##
## Random effects:
## Groups Name Variance Std.Dev.
## donor (Intercept) 0.1794 0.4236
## Number of obs: 40, groups: donor, 8
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 1.26983 0.15723 8.076 6.69e-16 ***
## conc -0.30297 0.04266 -7.103 1.22e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr)
## conc -0.209
# Graphique du modèle GLMM simplifié
chart(data = spe, mob_frac ~ conc %col=% donor) +
geom_point() +
geom_line(f_aes(fitted(spe_m2) ~ conc %col=% donor)) +
labs(x = "Ethanol [%]",
y = "Mobilité des spermatozoïdes [%]",
col = "Donneur")## Computing profile confidence intervals ...
## 2.5 % 97.5 %
## .sig01 0.2695168 0.7719890
## (Intercept) 0.9261419 1.6176274
## conc -0.3865530 -0.2192498
# Vérification de la singularité et test d'autres optimiseurs pour notre GLMM
lme4::isSingular(spe_m2)## [1] FALSE
## bobyqa : [OK]
## Nelder_Mead : [OK]
## nlminbwrap : [OK]
## optimx.L-BFGS-B : [OK]
## nloptwrap.NLOPT_LN_NELDERMEAD : [OK]
## nloptwrap.NLOPT_LN_BOBYQA : [OK]
## original model:
## cbind(mobile, total - mobile) ~ conc + (1 | donor)
## data: spe
## optimizers (6): bobyqa, Nelder_Mead, nlminbwrap, optimx.L-BFGS-B, nloptwrap.NLOPT_LN_NELDERME...
## differences in negative log-likelihoods:
## max= 1.36e-07 ; std dev= 5.5e-08
# Analyse des résidus de Pearson de notre GLMM simplifiée
chart(data = spe,
resid(spe_m2, type = "pearson") ~ fitted(spe_m2) %col=% donor) +
geom_point() +
geom_hline(yintercept = 0) +
labs(x = "Valeurs ajustées", y = "Résidus de Pearson")# Graphique de vérification de l'homoscédasticité des résidus de Pearson
chart(data = spe, sqrt(abs(resid(spe_m2, type = "pearson"))) ~ fitted(spe_m2) %col=% donor) +
geom_point() +
geom_hline(yintercept = 0) +
labs(x = "Valeurs ajustées", y = "|Résidus de Pearson|^.5")# Analyse des résidus de Pearson en fonction d'effet fixe (ici conc)
chart(data = spe, resid(spe_m2, type = "pearson") ~ conc %col=% donor) +
geom_point() +
geom_hline(yintercept = 0) +
labs(x = " Ethanol [%]", y = "Résidus de Pearson")# Graphique quantitle-quantile des résidus de Pearson -> PAS NÉCESSAIRE !
chart(data = spe, aes(sample = resid(spe_m2, type = "pearson"))) +
geom_qq() +
geom_qq_line()# Fonction de lien utilisée pour notre GLMM
logit <- make.link("logit")
# Transforme quelques valeurs de Y (comprises entre 0 et 1, proportions)
y <- c(0.8, 0.85, 0.9, 0.95)
(y_logit <- logit$linkfun(y))## [1] 1.386294 1.734601 2.197225 2.944439
## [1] 0.80 0.85 0.90 0.95
## [1] TRUE
## $donor
## (Intercept) conc
## 1 1.1559378 -0.3029708
## 2 0.2880608 -0.3029708
## 3 1.3821835 -0.3029708
## 4 1.2533090 -0.3029708
## 5 1.4292835 -0.3029708
## 6 1.5288128 -0.3029708
## 7 1.3454443 -0.3029708
## 8 1.7588595 -0.3029708
##
## attr(,"class")
## [1] "coef.mer"
## (Intercept) conc
## 1.2698292 -0.3029708
# Prédiction à partir de quelques valeurs de concentration
intercept <- spe_m2_fixef[1]
slope <- spe_m2_fixef[2]
conc <- c(0, 0.25, 0.5, 1, 2)
slope * conc + intercept## [1] 1.2698292 1.1940865 1.1183438 0.9668584 0.6638876
# Il faut appliquer la transformation inverse pour les fractions de mobilité
(mobi <- logit$linkinv(slope * conc + intercept))## [1] 0.7807135 0.7674711 0.7536814 0.7244929 0.6601331
## [1] 0.05622064