Pour suivre cet atelier, nous recommandons:
Nous commencerons par les bases de comment spécifier et implémenter des GAMs en R:
Nous discuterons ensuite de la généralisation du modèle additif, incluant:
mgcv
pour modéliser les relations non linéaires,La régression linéaire est parmi les méthodes les plus performantes et plus utilisées. Elle nous permet de modéliser une variable réponse en fonction de facteurs prédictifs et d'une erreur résiduelle.
La régression linéaire est parmi les méthodes les plus performantes et plus utilisées. Elle nous permet de modéliser une variable réponse en fonction de facteurs prédictifs et d'une erreur résiduelle.
Comme on a vu dans l'Atelier 4: Modèles linéaires, le modèle linéaire fait quatre suppositions importantes:
La régression linéaire est parmi les méthodes les plus performantes et plus utilisées. Elle nous permet de modéliser une variable réponse en fonction de facteurs prédictifs et d'une erreur résiduelle.
Comme on a vu dans l'Atelier 4: Modèles linéaires, le modèle linéaire fait quatre suppositions importantes:
Modèle linéaire avec plusieurs prédicteurs:
yi=β0+β1x1,i+β2x2,i+β3x3,i+...+βkxk,i+ϵi
Un modèle linéaire peut parfois s'adapter à certains types de réponses non linéaires (par exemple x2), mais cette approche repose fortement sur des décisions qui peuvent être soit arbitraires, soit bien informées, et est beaucoup moins flexible que l'utilisation d'un modèle additif.
Les modèles linéaires fonctionnent très bien dans certains cas spécifiques où tous ces critères sont respectés:
En réalité, il est souvent impossible de respecter ces critères. Dans de nombreux cas, les modèles linéaires sont inappropriés:
Quel est le problème et comment le régler?
Un modèle linéaire essaye d'ajuster la meilleure droite qui passe au milieu des données, cela ne fonctionne donc pas pour tous les jeux de données.
En revanche, les GAM font cela en ajustant une fonction de lissage non-linéaire à travers les données, mais tout en contrôlant le degré de courbure de la ligne (plus d'informations suivront).
Utilisons un exemple pour démontrer la différence entre une régression linéaire et un modèle additif. Nous allons utiliser le jeu de données ISIT
.
isit <- read.csv("data/ISIT.csv")head(isit)
Ce jeu de donnée comporte des mesures de bioluminescence en relation à la profondeur (depth), la station de rechercher et la saison (Season).
Prenons que les données de la deuxième saison pour l'instant:
isit2 <- subset(isit, Season==2)
Commençons par essayer d'ajuster un modèle de régression linéaire à la relation entre Sources
et SampleDepth
.
linear_model <- gam(Sources ~ SampleDepth, data = isit2)summary(linear_model)...# # Parametric coefficients:# Estimate Std. Error t value Pr(>|t|) # (Intercept) 30.9021874 0.7963891 38.80 <2e-16 ***# SampleDepth -0.0083450 0.0003283 -25.42 <2e-16 ***# # # R-sq.(adj) = 0.588 Deviance explained = 58.9%# GCV = 60.19 Scale est. = 59.924 n = 453...
Le modèle linéaire explique une bonne partie de la variance de notre jeu de données ( Radj = 0.588), ce qui veut dire que notre modèle est super bon, non?
Nous pouvons utiliser la commande gam()
de la librairie mgcv
pour modéliser une régression par les moindres carrés. Nous verrons plus loin comment utiliser gam()
pour spécifier un terme lissé et non linéaire.
Voyons comment notre modèle cadre avec les données:
data_plot <- ggplot(data = isit2, aes(y = Sources, x = SampleDepth)) + geom_point() + geom_line(aes(y = fitted(linear_model)), colour = "red", size = 1.2) + theme_bw()data_plot
Les suppositions de la régression linéaire sont-elles satisfaites dans ce cas? Comme vous l'avez peut-être remarqué, nous ne respectons pas les conditions du modèle linéaire:
Sources
et SampleDepth
.Relation entre la variable réponse et le prédicteur
Une variable prédicteur: yi=β0+f(xi)+ϵ
Plusieurs variables prédicteurs: yi=β0+f1(x1,i)+f2(x2,i)+...+ϵ
Un des grands avantages d'utiliser un GAM est que la forme optimale de la non-linéarité, i.e. le degré de lissage de f(x) est contrôlée en utilisant une régression pénalisée qui est déterminée automatiquement est déterminée automatiquement selon la méthode d'ajustement (généralement le maximum de vraisemblance ou maximum likelihood).
Au sens strict, les équations concernent un GAM gaussien avec lien d'identité, qui est aussi appelé "modèle additif" (sans "généralisé").
Étant donné que la fonction de lissage f(xi) est non linéaire et locale, l'ampleur de l'effet de la variable explicative peut varier en fonction de la relation entre la variable et la réponse.
Autrement dit, contrairement à un coefficient fixe βxi, la fonction f
peut changer tout au long du gradient xi. Le degré de lissage de f
est contrôlée en utilisant une régression pénalisée qui est déterminée
automatiquement à l'aide d'une méthode de validation croisée
généralisée (GCV) de la librairie mgcv
.
Essayons de modéliser les données à l'aide d'une fonction de lissage s(x)
avec mgcv::gam()
gam_model <- gam(Sources ~ s(SampleDepth), data = isit2)
Essayons de modéliser les données à l'aide d'une fonction de lissage s(x)
avec mgcv::gam()
gam_model <- gam(Sources ~ s(SampleDepth), data = isit2)
...# Family: gaussian # Link function: identity # # Parametric coefficients:# Estimate Std. Error t value Pr(>|t|) # (Intercept) 12.8937 0.2471 52.17 <2e-16 ***# # Approximate significance of smooth terms:# edf Ref.df F p-value # s(SampleDepth) 8.908 8.998 214.1 <2e-16 ***# ---# Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1# # R-sq.(adj) = 0.81 Deviance explained = 81.4%# GCV = 28.287 Scale est. = 27.669 n = 453...
Nous pouvons essayer de construire un modèle plus approprié en ajustant les données avec un terme lissé (non-linéaire). Dans mgcv::gam()
, les termes lissés sont spécifiés par des expressions de la forme s(x)
, où x est la variable prédictive non linéaire que nous voulons lisser. Dans ce cas, nous voulons appliquer une fonction de lissage à SampleDepth
.
La variance expliquée par notre modèle a augmenté de plus de 20% ($R_{adj}$ = 0.81)!
Note: contrairement à un coefficient fixe β, la fonction de lissage peut changer tout au long du gradient x.
Lorsque nous comparons l'ajustement des modèles linéaire (rouge) et non linéaire (bleu), il est clair que ce dernier cadre mieux avec nos données
La librairie mgcv
comprend également une fonction plot
qui, par
défaut, nous permet de visualiser la non-linéarité du modèle.
plot(gam_model)
Comment tester si le modèle non linéaire offre une amélioration significative par rapport au modèle linéaire?
On peut utiliser gam()
et AIC()
pour comparer la performance d'un modèle linéaire contenant x
comme prédicteur linéaire à la performance d'un modèle non linéaire contenant s(x)
comme prédicteur lisse.
linear_model <- gam(Sources ~ SampleDepth, data = isit2)smooth_model <- gam(Sources ~ s(SampleDepth), data = isit2)AIC(linear_model, smooth_model)# df AIC# linear_model 3.00000 3143.720# smooth_model 10.90825 2801.451
Ici, l'AIC du GAM lissé est plus bas, ce qui indique que l'ajout d'une fonction de lissage améliore la performance du modèle. La linéarité n'est donc pas soutenue par nos données.
En d'autres termes, on demande si l'ajout d'une fonction lisse au modèle linéaire améliore l'ajustement du modèle à nos données.
Pour expliquer brièvement, le critère d'information d'Akaike (AIC) est une mesure comparative de la performance d'un modèle, où des valeurs plus basses indiquent qu'un modèle est "plus performant" par rapport aux autres modèles considérés.
Essayons maintenant de déterminer si les données enregistrées lors de la première saison doivent être modélisées par une régression linéaire ou par un modèle additif.
Répétons le test de comparaison avec gam()
et AIC()
en utilisant les données de la première saison seulement:
isit1 <- subset(isit, Season == 1)
Sources
et SampleDepth
.Nous n'avons pas encore discuté des degrés de liberté effectifs (EDF), mais ils sont un outil clé pour nous aider à interpréter l'ajustement d'un GAM. Gardez ce terme en tête. Plus sur ce sujet dans les prochaines sections!
1. Ajustez un modèle linéaire et un GAM à la relation entre Sources
et SampleDepth
.
linear_model_s1 <- gam(Sources ~ SampleDepth, data = isit1)smooth_model_s1 <- gam(Sources ~ s(SampleDepth), data = isit1)
2. Déterminez si l'hypothèse de linéarité est justifiée pour ces données.
Comme ci-dessus, la visualisation de la courbe du modèle sur notre ensemble de données est une excellente première étape pour déterminer si notre modèle est bien conçu.
ggplot(isit1, aes(x = SampleDepth, y = Sources)) + geom_point() + geom_line(colour = "red", size = 1.2, aes(y = fitted(linear_model_s1))) + geom_line(colour = "blue", size = 1.2, aes(y = fitted(smooth_model_s1))) + theme_bw()
2. Déterminez si l'hypothèse de linéarité est justifiée pour ces données.
Comme ci-dessus, la visualisation de la courbe du modèle sur notre ensemble de données est une excellente première étape pour déterminer si notre modèle est bien conçu.
On peut compléter cela par une comparaison quantitative des performances du modèle en utilisant AIC()
.
AIC(linear_model_s1, smooth_model_s1)# df AIC# linear_model_s1 3.000000 2324.905# smooth_model_s1 9.644938 2121.249
Le score AIC moins élevé indique que le modèle lissé est plus performant que le modèle linéaire, ce qui confirme que la linéarité n'est pas appropriée pour notre ensemble de données.
3. Quels sont les degrés de liberté effectifs du terme non-linéaire?
Pour obtenir les degrés de liberté effectifs, il suffit d'imprimer notre objet du modèle:
smooth_model_s1# # Family: gaussian # Link function: identity # # Formula:# Sources ~ s(SampleDepth)# # Estimated degrees of freedom:# 7.64 total = 8.64 # # GCV score: 32.13946
Les degrés de liberté effectifs (EDF) sont >> 1.
Gardez cela à l'esprit, car nous reviendrons bientôt sur les EDF!
Nous allons maintenant prendre quelques minutes pour regarder comment fonctionnent les GAMs. Commençons en considérant d'abord un modèle qui contient une fonction lisse f d'une covariable, x :
yi=f(xi)+ϵi
Pour estimer la fonction f, nous avons besoin de représenter l'équation ci-dessus de manière à ce qu'elle devienne un modèle linéaire. Cela peut être fait en définissant des fonctions de base, bj(x), dont est composée f :
f(x)=q∑j=1bj(x)×βj
Supposons que f est considérée comme un polynôme d'ordre 4, de sorte que l'espace des polynômes d'ordre 4 et moins contient f. Une base de cet espace serait alors :
b0(x)=1 ,b1(x)=x ,b2(x)=x2 ,b3(x)=x3 ,b4(x)=x4
Alors f(x) devient :
f(x)=β0+xβ1+x2β2+x3β3+x4β4
... et le modèle complet devient :
yi=β0+xiβ1+x2iβ2+x3iβ3+x4iβ4+ϵi
Chaque fonction de base est multipliée par un paramètre à valeur réelle, βj, et est ensuite additionnée pour donner la courbe finale f(x).
En faisant varier le coefficient βj, on peut faire varier la forme de f(x) pour produire une fonction polynomiale d'ordre 4 ou moins.
Un spline cubique est une courbe construite à partir de sections d'un polynôme cubique reliées entre elles de sorte qu'elles sont continues en valeur. Chaque section du spline a des coefficients différents.
Voici une représentation d'une fonction lisse utilisant une base de régression spline cubique de rang 5 avec des nœuds situés à incréments de 0.2:
Dans cet exemple, les nœuds sont espacés uniformément à travers la gamme des valeurs observées de x. Le choix du degré de finesse du modèle est pré-déterminé par le nombre de nœuds, qui était arbitraire.
Y a-t-il une meilleure façon de sélectionner les emplacements des nœuds?
Au lieu de contrôler le lissage (non linéarité) en modifiant le nombre de nœuds, nous gardons celui-ci fixé à une taille un peu plus grande que raisonnablement nécessaire et on contrôle le lissage du modèle en ajoutant une pénalité sur le niveau de courbure. Donc, plutôt que d'ajuster le modèle en minimisant (comme avec la méthode des moindres carrés) :
||y−XB||2
Le modèle peut être ajusté en minimisant:
||y−XB||2+λ∫10[f″
Quand \lambda tend vers ∞, le modèle devient linéaire.
Si \lambda est trop élevé, les données seront trop lissées et si elle est trop faible, les données ne seront pas assez lissées. Idéalement, il serait bon de choisir une valeur \lambda de sorte que le \hat{f} prédit est aussi proche que possible du f observé.
Un critère approprié pourrait être de choisir \lambda pour minimiser :
M = 1/n \times \sum_{i=1}^n (\hat{f_i} - f_i)^2
Étant donné que f est inconnue, M doit être estimé.
Les méthodes recommandées pour ce faire sont le maximum de vraisemblance (maximum likelihood, ML) ou l'estimation par maximum de vraisemblance restreint (restricted maximum likelihood, REML).
La validation croisée généralisée (GCV) est une autre possibilité.
Avec les GAMs, il est facile d'ajouter des termes non linéaires et linéaires dans un seul modèle, plusieurs termes non linéaires ou même des interactions non linéaires.
Dans cette section, nous allons utiliser les données de ISIT
de nouveau.
Nous allons essayer de modéliser la réponse Sources
avec les prédicteurs Season
and SampleDepth
simultanément.
Tout d'abord, nous devons convertir notre prédicteur qualitatif (Season
) en facteur:
head(isit)isit$Season <- as.factor(isit$Season)
Rappelez-vous de ce jeu de données présenté dans les sections précédentes? Le jeu de données ISIT est composé des niveaux de bioluminescence (Sources
) en fonction de la profondeur, des saisons et des différentes stations.
Commençons par un modèle de base comprenant un terme non linéaire (SampleDepth
) et un facteur qualitatif (Season
avec 2 niveaux).
basic_model <- gam(Sources ~ Season + s(SampleDepth), data = isit, method = "REML")basic_summary <- summary(basic_model)
Commençons par un modèle de base comprenant un terme non linéaire (SampleDepth
) et un facteur qualitatif (Season
avec 2 niveaux).
basic_model <- gam(Sources ~ Season + s(SampleDepth), data = isit, method = "REML")basic_summary <- summary(basic_model)
Le tableau p.table
donne des informations sur les termes linéaires:
basic_summary$p.table# Estimate Std. Error t value Pr(>|t|)# (Intercept) 7.253273 0.3612666 20.07734 1.430234e-72# Season2 6.156130 0.4825491 12.75752 5.525673e-34
Commençons par un modèle de base comprenant un terme non linéaire (SampleDepth
) et un facteur qualitatif (Season
avec 2 niveaux).
basic_model <- gam(Sources ~ Season + s(SampleDepth), data = isit, method = "REML")basic_summary <- summary(basic_model)
Le tableau p.table
donne des informations sur les termes linéaires:
basic_summary$p.table# Estimate Std. Error t value Pr(>|t|)# (Intercept) 7.253273 0.3612666 20.07734 1.430234e-72# Season2 6.156130 0.4825491 12.75752 5.525673e-34
Le tableau s.table
nous donne donne des informations sur le terme non linéaire:
basic_summary$s.table# edf Ref.df F p-value# s(SampleDepth) 8.706426 8.975172 184.3583 0
Que nous montrent ces graphiques sur la relation entre la bioluminescence, la profondeur de l'échantillon et les saisons?
par(mfrow = c(1,2))plot(basic_model, all.terms = TRUE)
La bioluminescence varie de manière non-linéaire sur le gradient SampleDepth
, avec des niveaux de bioluminescence les plus élevés à la surface, suivis d'un second maximum plus petit, juste au-dessus d'une profondeur de 1500, avec des niveaux décroissants à des profondeurs plus basses.
Il y a également une différence prononcée dans la bioluminescence entre les saisons, avec des niveaux élevés pendant la saison 2, par rapport à la saison 1.
basic_summary$s.table# edf Ref.df F p-value# s(SampleDepth) 8.706426 8.975172 184.3583 0
Les edf
indiqués dans le s.table
sont les degrés effectifs de liberté (EDF, en anglais "effective degrees of freedom") du terme lisse s(SampleDepth)
.
Plus le nombre de degrés de liberté est élevé, plus la courbe est complexe et ondulée.
Une valeur proche de 1 se rapproche d'un terme linéaire.
Une valeur elevée signifie que la courbe est plus ondulé, ou en d'autres termes, plus non-linéaire.
basic_summary$s.table# edf Ref.df F p-value# s(SampleDepth) 8.706426 8.975172 184.3583 0
Les edf
indiqués dans le s.table
sont les degrés effectifs de liberté (EDF, en anglais "effective degrees of freedom") du terme lisse s(SampleDepth)
.
Plus le nombre de degrés de liberté est élevé, plus la courbe est complexe et ondulée.
Une valeur proche de 1 se rapproche d'un terme linéaire.
Une valeur elevée signifie que la courbe est plus ondulé, ou en d'autres termes, plus non-linéaire.
Dans notre modèle de base, les EDF du terme non-linéaire
s(SampleDepth)
sont ~9, ce qui suggère une courbe fortement non-linéaire.
Les degrés de liberté effectifs nous donnent beaucoup d'informations sur la relation entre les prédicteurs du modèle et les variables de réponse.
Vous reconnaissez peut-être le terme "degrés de liberté" suite à des ateliers précédents sur les modèles linéaires, mais attention!
Les degrés de liberté effectifs d'un GAM sont estimés différemment des degrés de liberté d'une régression linéaire, et sont interprétés différemment.
Les degrés de liberté effectifs nous donnent beaucoup d'informations sur la relation entre les prédicteurs du modèle et les variables de réponse.
Vous reconnaissez peut-être le terme "degrés de liberté" suite à des ateliers précédents sur les modèles linéaires, mais attention!
Les degrés de liberté effectifs d'un GAM sont estimés différemment des degrés de liberté d'une régression linéaire, et sont interprétés différemment.
Dans la régression linéaire, les degrés de liberté du modèle sont équivalents au nombre de paramètres libres non redondants, p, dans le modèle (et les degrés de liberté résiduels sont égaux à n-p; où n est le nombre d'observations).
Les degrés de liberté effectifs nous donnent beaucoup d'informations sur la relation entre les prédicteurs du modèle et les variables de réponse.
Vous reconnaissez peut-être le terme "degrés de liberté" suite à des ateliers précédents sur les modèles linéaires, mais attention!
Les degrés de liberté effectifs d'un GAM sont estimés différemment des degrés de liberté d'une régression linéaire, et sont interprétés différemment.
Dans la régression linéaire, les degrés de liberté du modèle sont équivalents au nombre de paramètres libres non redondants, p, dans le modèle (et les degrés de liberté résiduels sont égaux à n-p; où n est le nombre d'observations).
Parce que le nombre de paramètres libres des fonctions de lissage est souvent difficile à définir, les EDF sont liés à \lambda, où l'effet de la pénalité est de réduire les degrés de liberté.
Revenons sur le concept de degrés de liberté effectifs (EDF). (Rappel: Défi 1)
La limite supérieure d'EDF est déterminée par les dimensions de base k de la fonction lisse (les EDF ne peuvent pas dépasser k-1)
En pratique, le choix exact de k est arbitraire, mais il devrait être suffisamment grand pour permettre une fonction lisse suffisamment complexe.
Nous discuterons du choix de k dans les sections qui suivent.
Nous pouvons ajouter un second terme, RelativeDepth
, mais en spécifiant une relation linéaire avec Sources
:
two_term_model <- gam(Sources ~ Season + s(SampleDepth) + RelativeDepth, data = isit, method = "REML")two_term_summary <- summary(two_term_model)
Nous pouvons ajouter un second terme, RelativeDepth
, mais en spécifiant une relation linéaire avec Sources
:
two_term_model <- gam(Sources ~ Season + s(SampleDepth) + RelativeDepth, data = isit, method = "REML")two_term_summary <- summary(two_term_model)
Informations sur les effets paramétriques (termes linéaires):
two_term_summary$p.table# Estimate Std. Error t value Pr(>|t|)# (Intercept) 9.808305503 0.6478741951 15.139213 1.446613e-45# Season2 6.041930627 0.4767977508 12.671894 1.380010e-33# RelativeDepth -0.001401908 0.0002968443 -4.722705 2.761048e-06
Informations sur les effets additifs (termes non linéaires):
two_term_summary$s.table# edf Ref.df F p-value# s(SampleDepth) 8.699146 8.97396 132.4801 0
L'estimation du coefficient de régression pour ce nouveau terme linéaire, RelativeDepth
, sera présenté dans le tableau p.table
. Rappelez-vous, le tableau p.table
montre des informations sur les effets paramétriques (termes linéaires).
Dans s.table
, nous trouverons encore une fois le terme non-linéaire, s(SampleDepth)
, et son paramètre de courbure (edf
). Rappelez-vous, le tableau s.table
montre des informations sur les effets additifs (termes non-linéaires).
par(mfrow = c(2,2))plot(two_term_model, all.terms = TRUE)
Si nous voulons vérifier que la relation entre Sources
et RelativeDepth
est non-linéaire, on peut modéliser RelativeDepth
avec une fonction non-linéaire.
two_smooth_model <- gam(Sources ~ Season + s(SampleDepth) + s(RelativeDepth), data = isit, method = "REML")two_smooth_summary <- summary(two_smooth_model)
Informations sur les effets paramétriques (termes linéaires) :
two_smooth_summary$p.table# Estimate Std. Error t value Pr(>|t|)# (Intercept) 7.937755 0.3452945 22.98836 1.888513e-89# Season2 4.963951 0.4782280 10.37988 1.029016e-23
Informations sur les effets additifs (termes non linéaires) :
two_smooth_summary$s.table# edf Ref.df F p-value# s(SampleDepth) 8.752103 8.973459 150.37263 0# s(RelativeDepth) 8.044197 8.749580 19.97476 0
Nous pouvons aussi vérifier que la relation entre Sources
et RelativeDepth
est non-linéaire.
par(mfrow = c(2,2))plot(two_smooth_model, all.terms = TRUE)
Pensez-vous que la performance de notre modèle est amélioré par l'ajout de ce nouveau terme non-linéaire, pour mieux représenter la relation entre la bioluminescence et la profondeur relative?
Comme précédemment, nous pouvons comparer nos modèles avec AIC pour tester si le terme non-linéaire améliore la performance de notre modèle:
AIC(basic_model, two_term_model, two_smooth_model)# df AIC# basic_model 11.83374 5208.713# two_term_model 12.82932 5188.780# two_smooth_model 20.46960 5056.841
On peut voir que two_smooth_model
a la plus petite valeur de AIC.
Comme précédemment, nous pouvons comparer nos modèles avec AIC pour tester si le terme non-linéaire améliore la performance de notre modèle:
AIC(basic_model, two_term_model, two_smooth_model)# df AIC# basic_model 11.83374 5208.713# two_term_model 12.82932 5188.780# two_smooth_model 20.46960 5056.841
On peut voir que two_smooth_model
a la plus petite valeur de AIC.
two_smooth_model# # Family: gaussian # Link function: identity # # Formula:# Sources ~ Season + s(SampleDepth) + s(RelativeDepth)# # Estimated degrees of freedom:# 8.75 8.04 total = 18.8 # # REML score: 2550.112
Le modèle le mieux ajusté comprend donc deux fonctions non-linéaires pour SampleDepth
et RelativeDepth
, et un terme linéaire pour Season
.
Pour notre deuxième défi, nous allons développer notre modèle en ajoutant des variables qui, selon nous, pourraient être des prédicteurs écologiquement significatifs pour expliquer la bioluminescence.
Créez deux nouveaux modèles: Ajoutez la variable Latitude
à two_smooth_model
, premièrement comme paramètre linéaire, et ensuite comme fonction non-linéaire.
Est-ce que Latitude
est un terme important à inclure dans le modèle? La Latitude
a-t-elle un effet linéaire ou non-linéaire?
Utilisez des graphiques, les tables des coefficients et la fonction
AIC()
pour répondre à ces questions.
1. Créez deux nouveaux modèles: Ajoutez la variable Latitude
à two_smooth_model
, premièrement comme paramètre linéaire, et ensuite comme fonction non-linéaire.
# Ajouter Latitude comme terme linéairethree_term_model <- gam(Sources ~ Season + s(SampleDepth) + s(RelativeDepth) + Latitude, data = isit, method = "REML")three_term_summary <- summary(three_term_model)
# Ajouter Latitude comme terme non-linéairethree_smooth_model <- gam(Sources ~ Season + s(SampleDepth) + s(RelativeDepth) + s(Latitude), data = isit, method = "REML")three_smooth_summary <- summary(three_smooth_model)
2. Est-ce que Latitude
est un terme important à inclure dans le modèle?
Commençons par visualiser les 4 effets qui sont maintenant inclus dans chaque modèle.
par(mfrow = c(2,2))plot(three_smooth_model, all.terms = TRUE)
par(mfrow = c(2,2))plot(three_smooth_model, all.terms = TRUE)
Nous devrions également examiner nos tableaux de coefficients. Qu'est-ce que les EDF nous disent à propos de l'ondulation, ou la non-linéarité, des effets de nos prédicteurs?
three_smooth_summary$s.table# edf Ref.df F p-value# s(SampleDepth) 8.766891 8.975682 68.950905 0# s(RelativeDepth) 8.007411 8.730625 17.639321 0# s(Latitude) 7.431116 8.296838 8.954349 0
Nous devrions également examiner nos tableaux de coefficients. Qu'est-ce que les EDF nous disent à propos de l'ondulation, ou la non-linéarité, des effets de nos prédicteurs?
three_smooth_summary$s.table# edf Ref.df F p-value# s(SampleDepth) 8.766891 8.975682 68.950905 0# s(RelativeDepth) 8.007411 8.730625 17.639321 0# s(Latitude) 7.431116 8.296838 8.954349 0
Les EDF sont tous élevés pour nos variables, y compris Latitude
.
Cela nous indique que Latitude
est assez ondulée, et qu'elle ne devrait probablement pas être incluse comme terme linéaire.
Avant de décider quel modèle est le "meilleur", nous devrions tester si l'effet Latitude
est plus approprié comme terme linéaire ou lisse, en utilisant AIC()
:
AIC(three_smooth_model, three_term_model)# df AIC# three_smooth_model 28.20032 4990.546# three_term_model 21.47683 5051.415
Avant de décider quel modèle est le "meilleur", nous devrions tester si l'effet Latitude
est plus approprié comme terme linéaire ou lisse, en utilisant AIC()
:
AIC(three_smooth_model, three_term_model)# df AIC# three_smooth_model 28.20032 4990.546# three_term_model 21.47683 5051.415
Notre modèle incluant la Latitude
comme terme non-linéaire a un score AIC inférieur, ce qui signifie qu'il est plus performant que notre modèle incluant la Latitude
comme terme linéaire.
Avant de décider quel modèle est le "meilleur", nous devrions tester si l'effet Latitude
est plus approprié comme terme linéaire ou lisse, en utilisant AIC()
:
AIC(three_smooth_model, three_term_model)# df AIC# three_smooth_model 28.20032 4990.546# three_term_model 21.47683 5051.415
Notre modèle incluant la Latitude
comme terme non-linéaire a un score AIC inférieur, ce qui signifie qu'il est plus performant que notre modèle incluant la Latitude
comme terme linéaire.
Mais, est-ce que l'ajout de Latitude
comme prédicteur non-linéaire améliore réellement notre "meilleur" modèle (two_smooth_model
)?
AIC(two_smooth_model, three_smooth_model)# df AIC# two_smooth_model 20.46960 5056.841# three_smooth_model 28.20032 4990.546
Notre three_smooth_model
a un score AIC inférieur à notre meilleur modèle précédent (two_smooth_model
), qui n'incluait pas Latitude
.
AIC(two_smooth_model, three_smooth_model)# df AIC# two_smooth_model 20.46960 5056.841# three_smooth_model 28.20032 4990.546
Notre three_smooth_model
a un score AIC inférieur à notre meilleur modèle précédent (two_smooth_model
), qui n'incluait pas Latitude
.
Ceci implique que Latitude
est en effet un prédicteur informatif non-linéaire de la bioluminescence.
Il y a deux façons de modéliser une interaction entre deux variables :
pour deux variables non-linéaires : s(x1, x2)
pour une variable non-linéaire et une variable linéaire (quantitative ou qualitative) : utiliser l'argument by
, s(x1, by = x2)
x2
est qualitative, vous avez un terme non linéaire qui varie entre les différents niveaux de x2
x2
est quantitative, l'effet linéaire de x2
varie avec x1
x2
est qualitative, le facteur doit être ajouté comme effet principal dans le modèleNous allons examiner l'effet de l'interaction en utilisant notre variable qualitative Season
et examiner si la non-linéarité de s(SampleDepth)
varie selon les différents niveaux de Season
.
factor_interact <- gam(Sources ~ Season + s(SampleDepth,by=Season) + s(RelativeDepth), data = isit, method = "REML")
summary(factor_interact)$s.table# edf Ref.df F p-value# s(SampleDepth):Season1 6.839386 7.552045 95.119422 0# s(SampleDepth):Season2 8.744574 8.966290 154.474325 0# s(RelativeDepth) 6.987223 8.055898 6.821074 0
par(mfrow = c(2),2))plot(factor_interact)
Les deux graphiques montrent l'effet d'interaction entre notre variable lisse SampleDepth
et chaque niveau de notre variable factorielle, Season
.
Une bonne question pour les participants: Voyez-vous une différence entre les deux courbes?
Les graphiques montrent quelques différences entre la forme des termes lisses entre les deux niveaux de Season
. La différence la plus notable est le pic dans le deuxième panneau, qui nous indique qu'il y a un effet de SampleDepth
entre 1000 et 2000 qui est important dans la saison 2, mais qui ne se produit pas dans la saison 1.
Ceci suggère que l'effet d'interaction pourrait être important à inclure dans notre modèle.
Nous pouvons également représenter l'effet d'interaction en 3D sur un seul graphique, en utilisant vis.gam()
.
vis.gam(factor_interact, theta = 120, n.grid = 50, lwd = .4)
Nous pouvons également représenter l'effet d'interaction en 3D sur un seul graphique, en utilisant vis.gam()
.
vis.gam(factor_interact, theta = 120, n.grid = 50, lwd = .4)
vis.gam(factor_interact, theta = 60, n.grid = 50, lwd = .4)
Nous pouvons modifier la rotation de ce graphique en utilisant l'argument theta
.
Lorsqu'on visualise les termes d'interaction, on observe des différences dans la forme du lissage de SampleDepth
entre les deux niveaux de Season
. Ceci suggère que l'effet d'interaction pourrait être important à inclure dans notre modèle.
Ces graphiques suggèrent que l'effet d'interaction pourrait être important à inclure dans notre modèle.
On peut faire une comparaison de modèles en utilisant l'AIC pour déterminer si le terme d'interaction améliore la performance de notre modèle.
AIC(two_smooth_model, factor_interact)# df AIC# two_smooth_model 20.46960 5056.841# factor_interact 26.99693 4878.631
L'AIC de notre modèle avec une interaction factorielle entre la variable non-linéair SampleDepth
et le Season
a un score AIC plus bas.
Ces graphiques suggèrent que l'effet d'interaction pourrait être important à inclure dans notre modèle.
On peut faire une comparaison de modèles en utilisant l'AIC pour déterminer si le terme d'interaction améliore la performance de notre modèle.
AIC(two_smooth_model, factor_interact)# df AIC# two_smooth_model 20.46960 5056.841# factor_interact 26.99693 4878.631
L'AIC de notre modèle avec une interaction factorielle entre la variable non-linéair SampleDepth
et le Season
a un score AIC plus bas.
Ensemble, l'AIC et les graphiques confirment que l'inclusion de cette interaction améliore la performance de notre modèle.
Finalement, nous regardons les interactions entre deux termes non linéaires, SampleDepth
et RelativeDepth
.
smooth_interact <- gam(Sources ~ Season + s(SampleDepth, RelativeDepth), data = isit, method = "REML")summary(smooth_interact)$s.table# edf Ref.df F p-value# s(SampleDepth,RelativeDepth) 27.12521 28.77 93.91722 0
Finalement, nous regardons les interactions entre deux termes non linéaires, SampleDepth
et RelativeDepth
.
smooth_interact <- gam(Sources ~ Season + s(SampleDepth, RelativeDepth), data = isit, method = "REML")summary(smooth_interact)$s.table# edf Ref.df F p-value# s(SampleDepth,RelativeDepth) 27.12521 28.77 93.91722 0
vis.gam(smooth_interact, view = c("SampleDepth", "RelativeDepth"), theta = 50, n.grid = 50, lwd = .4)
Les graphiques illustrent une interaction non linéaire, où Sources
est plus faible à des valeurs élevées de SampleDepth
et RelativeDepth
, mais augmente avec RelativeDepth
alors que SampleDepth
est faible.
Rappelez-vous, ce graphique peut être réorienté en changeant la valeur de l'argument theta
.
On peut changer la couleur du graphique 3D en utilisant l'argument color
. Essayez de spécifier color = "cm"
dans vis.gam()
ci-dessus, et consultez ?vis.gam
pour plus d'options de couleurs.
Ainsi, il semble y avoir un effet d'interaction entre ces termes non linéaires.
Est-ce que l'inclusion de l'interaction entre s(SampleDepth)
et s(RelativeDepth)
améliore notre modèle two_smooth_model
?
Ainsi, il semble y avoir un effet d'interaction entre ces termes non linéaires.
Est-ce que l'inclusion de l'interaction entre s(SampleDepth)
et s(RelativeDepth)
améliore notre modèle two_smooth_model
?
AIC(two_smooth_model, smooth_interact)# df AIC# two_smooth_model 20.46960 5056.841# smooth_interact 30.33625 4943.890
Le modèle avec l'intéraction entre s(SampleDepth)
et s(RelativeDepth)
a une plus petite valeur d'AIC.
L'inclusion de cette interaction améliore la performance de notre modèle, et donc notre capacité à comprendre les déterminants de la bioluminescence.
Le modèle additif de base peut être étendu de plusieurs façons :
family
(comme dans un GLM),Nous allons maintenant examiner ces aspects.
Jusqu'à présent, nous avons utilisé des modèles additifs simples (gaussiens), l'équivalent non linéaire d'un modèle linéaire.
Jusqu'à présent, nous avons utilisé des modèles additifs simples (gaussiens), l'équivalent non linéaire d'un modèle linéaire.
Mais que pouvons-nous faire si :
Jusqu'à présent, nous avons utilisé des modèles additifs simples (gaussiens), l'équivalent non linéaire d'un modèle linéaire.
Mais que pouvons-nous faire si :
Ces situations se produisent fréquemment !
Tout comme les modèles linéaires généralisés (GLM), nous pouvons formuler des modèles additifs généralisés pour répondre à ces problèmes.
Revenons au modèle d'interaction pour les données de bioluminescence :
smooth_interact <- gam(Sources ~ Season + s(SampleDepth, RelativeDepth), data = isit, method = "REML")summary(smooth_interact)$p.table# Estimate Std. Error t value Pr(>|t|)# (Intercept) 8.077356 0.4235432 19.070912 1.475953e-66# Season2 4.720806 0.6559436 7.196969 1.480113e-12summary(smooth_interact)$s.table# edf Ref.df F p-value# s(SampleDepth,RelativeDepth) 27.12521 28.77 93.91722 0
Comme pour un GLM, il est essentiel de vérifier si nous avons correctement spécifié le modèle, en particulier la distribution de la réponse.
Il faut vérifier:
k
.Comme pour un GLM, il est essentiel de vérifier si nous avons correctement spécifié le modèle, en particulier la distribution de la réponse.
Il faut vérifier:
k
.
Fonctions incluses dans mgcv
:
k.check()
effectue une vérification des dimensions de base.gam.check()
produit des tracés de résidus (et fournit également la sortie de k.check()
.Vous vous rappelez du paramètre de lissage \lambda qui restreint les ondulations de nos fonctions de lissage?
Cette ondulation est également contrôlé par la dimension de base k, qui définit le nombre de fonctions de base utilisées pour créer une fonction lisse.
Plus le nombre de fonctions de base utilisées pour construire une fonction lisse est élevé, plus la fonction lisse est "ondulée":
Dans les section précédents, nous avons discuté du rôle du paramètre de lissage \lambda pour contrôler les ondulations de nos fonctions de lissage. Cette ondulation est également contrôlé par la dimension de base k, qui définit le nombre de fonctions de base utilisées pour créer une fonction lisse.
Chaque fonction lisse dans un GAM est essentiellement la somme pondérée de nombreuses fonctions plus petites, appelées fonctions de base. Plus le nombre de fonctions de base utilisées pour construire une fonction lisse est élevé, plus la fonction lisse est "ondulée". Comme vous pouvez le voir ci-dessous, une fonction lisse avec une petite dimension de base de k sera moins ondulée qu'une fonction lisse avec une grande dimension de base de k.
La clé pour obtenir un bon ajustement du modèle consiste à équilibrer le compromis entre deux éléments:
Avons-nous optimisé le compromis entre le lissage ( \lambda ) et la flexibilité ( k ) dans notre modèle?
En d'autres mots, est-ce que le k
est assez grand?
k.check(smooth_interact)# k' edf k-index p-value# s(SampleDepth,RelativeDepth) 29 27.12521 0.9448883 0.0575
La clé pour obtenir un bon ajustement du modèle consiste à équilibrer le compromis entre deux éléments:
Avons-nous optimisé le compromis entre le lissage ( \lambda ) et la flexibilité ( k ) dans notre modèle?
En d'autres mots, est-ce que le k
est assez grand?
k.check(smooth_interact)# k' edf k-index p-value# s(SampleDepth,RelativeDepth) 29 27.12521 0.9448883 0.0575
Les EDF se rapprochent beaucoup de k
, donc la flexibilité du modèle est trop restreinte par le k
utilisé par défaut.
En d'autres mots, nous n'avons pas un compromis équilibré entre le lissage et l'ondulation du modèle.
Ici, on se demande essentiellement: Est-ce que notre module est assez flexible?
On n'a pas encore spécifié de valeur k dans notre modèle, mais gam()
définit un k par défaut en fonction du nombre de variables sur lequel la fonction lisse est construite.
Les EDF se rapprochent beaucoup de k
. Ceci signifie que la flexibilité du modèle est restreint par le k
utilisé par défaut, et que notre modèle pourrait mieux s'ajuster aux données si on permettait plus d'ondulations. En d'autres mots, nousn n'avons pas un compromis équilibré entre le lissage et l'ondulation du modèle.
Recommençons le modèle avec un k
plus élevé:
smooth_interact_k60 <- gam(Sources ~ Season + s(SampleDepth, RelativeDepth, k = 60), data = isit, method = "REML")
summary(smooth_interact_k60)$p.table# Estimate Std. Error t value Pr(>|t|)# (Intercept) 8.129512 0.4177659 19.459491 1.911267e-68# Season2 4.629964 0.6512205 7.109672 2.741865e-12summary(smooth_interact_k60)$s.table# edf Ref.df F p-value# s(SampleDepth,RelativeDepth) 46.03868 54.21371 55.19817 0
Recommençons le modèle avec un k
plus élevé:
smooth_interact_k60 <- gam(Sources ~ Season + s(SampleDepth, RelativeDepth, k = 60), data = isit, method = "REML")
summary(smooth_interact_k60)$p.table# Estimate Std. Error t value Pr(>|t|)# (Intercept) 8.129512 0.4177659 19.459491 1.911267e-68# Season2 4.629964 0.6512205 7.109672 2.741865e-12summary(smooth_interact_k60)$s.table# edf Ref.df F p-value# s(SampleDepth,RelativeDepth) 46.03868 54.21371 55.19817 0
Est-ce que k
est assez grand maintenant?
k.check(smooth_interact_k60)# k' edf k-index p-value# s(SampleDepth,RelativeDepth) 59 46.03868 1.048626 0.895
Recommençons le modèle avec un k
plus élevé:
smooth_interact_k60 <- gam(Sources ~ Season + s(SampleDepth, RelativeDepth, k = 60), data = isit, method = "REML")
summary(smooth_interact_k60)$p.table# Estimate Std. Error t value Pr(>|t|)# (Intercept) 8.129512 0.4177659 19.459491 1.911267e-68# Season2 4.629964 0.6512205 7.109672 2.741865e-12summary(smooth_interact_k60)$s.table# edf Ref.df F p-value# s(SampleDepth,RelativeDepth) 46.03868 54.21371 55.19817 0
Est-ce que k
est assez grand maintenant?
k.check(smooth_interact_k60)# k' edf k-index p-value# s(SampleDepth,RelativeDepth) 59 46.03868 1.048626 0.895
Les EDF sont beaucoup plus petits que k
. On peut remplacer notre modèle avec cette version plus flexible:
smooth_interact <- smooth_interact_k60
Les EDF sont beaucoup plus petits que k
, donc notre modèle s'adjuste mieux aux données avec plus d'ondulations. On peut donc remplacer notre modèle avec cette version plus flexible.
Comme pour tout modèle normal, nous devons vérifier certaines conditions avant de continuer.
On peut visualiser les résidus du modèle avec gam.check()
:
par(mfrow = c(2,2))gam.check(smooth_interact)
En plus des graphiques, gam.check()
fournit également la sortie de k.check()
.
Rappel: Nous pouvons évaluer la distribution des résidus du modèle pour vérifier ces conditions, tout comme nous le ferions pour un GLM (voir Atelier 6).
Hétéroscédasticité marquée et points extrêmes dans les résidus
Ces tracés sont un peu différents de ceux produits par plot
pour un modèle linéaire (par exemple, pas de tracé de levier).
Les participants devraient déjà être familiarisés avec les graphiques de résidus (ils sont expliqués plus en détail dans les Atelier 4 et Atelier 6.
La visualisation des résidus met quelques problèmes en évidence:
Pour notre modèle d'interaction, nous avons besoin d'une distribution de probabilité qui permet à la variance d'augmenter avec la moyenne.
Pour notre modèle d'interaction, nous avons besoin d'une distribution de probabilité qui permet à la variance d'augmenter avec la moyenne.
Une famille de distributions qui possède cette propriété et qui fonctionne bien dans un GAM est la famille Tweedie.
Une fonction de liaison commune pour les distributions Tweedie est le log.
Pour notre modèle d'interaction, nous avons besoin d'une distribution de probabilité qui permet à la variance d'augmenter avec la moyenne.
Une famille de distributions qui possède cette propriété et qui fonctionne bien dans un GAM est la famille Tweedie.
Une fonction de liaison commune pour les distributions Tweedie est le log.
Comme dans un GLM, nous pouvons utiliser l'argument family =
dans gam()
pour ajuster des modèles avec d'autres distributions (y compris des distributions telles que binomial
, poisson
, gamma
etc).
Pour en savoir plus sur les familles disponibles dans mgcv
:
?family.mgcv
smooth_interact_tw
avec la même formule que le modèle smooth_interact
mais avec une distribution de la famille Tweedie (au lieu de la distribution normale) et log
comme fonction de liaison. Pour ce faire, on peut utiliser family = tw(link = "log")
dans gam()
.k
et les tracés de résidus pour le nouveau modèle.smooth_interact_tw
avec smooth_interact
. Lequel est meilleur ?smooth_interact_tw
avec la même formule que le modèle smooth_interact
mais avec une distribution de la famille Tweedie (au lieu de la distribution normale) et log
comme fonction de liaison. Pour ce faire, on peut utiliser family = tw(link = "log")
dans gam()
.k
et les tracés de résidus pour le nouveau modèle.smooth_interact_tw
avec smooth_interact
. Lequel est meilleur ?Indice:
# Voici comment nous écririons le modèle pour spécifier la distribution normale :smooth_interact <- gam(Sources ~ Season + s(SampleDepth, RelativeDepth, k = 60), family = gaussian(link = "identity"), data = isit, method = "REML")
1. Premièrement, construisons un nouveau modèle avec une distribution Tweedie un lien log
.
smooth_interact_tw <- gam(Sources ~ Season + s(SampleDepth, RelativeDepth, k = 60), family = tw(link = "log"), data = isit, method = "REML")summary(smooth_interact_tw)$p.table# Estimate Std. Error t value Pr(>|t|)# (Intercept) 1.3126641 0.03400390 38.60333 8.446478e-180# Season2 0.5350529 0.04837342 11.06089 1.961733e-26summary(smooth_interact_tw)$s.table# edf Ref.df F p-value# s(SampleDepth,RelativeDepth) 43.23949 51.57139 116.9236 0
2. Vérifier le choix de k
et la visualisation des résidus pour le nouveau modèle.
Ensuite, on devrait vérifier le choix des dimensions de bases k
:
k.check(smooth_interact_tw)# k' edf k-index p-value# s(SampleDepth,RelativeDepth) 59 43.23949 1.015062 0.7825
On a un équilibre entre k et les EDF. Super!
Ensuite la visualisation des résidus, pour valider la distribution Tweedie:
par(mfrow=c(2,2))gam.check(smooth_interact_tw)
Les résidus semblent mieux distribués, mais il est évident que le modèle manque encore quelque chose. Il pourrait s'agir d'un effet spatial (longitude et latitude), ou d'un effet aléatoire (par exemple basé sur Station
).
3. Comparer smooth_interact_tw
avec smooth_interact
. Lequel est meilleur?
AIC(smooth_interact, smooth_interact_tw)# df AIC# smooth_interact 49.47221 4900.567# smooth_interact_tw 47.86913 3498.490
L'AIC nous permet de comparer des modèles qui sont basés sur des distributions différentes!
3. Comparer smooth_interact_tw
avec smooth_interact
. Lequel est meilleur?
AIC(smooth_interact, smooth_interact_tw)# df AIC# smooth_interact 49.47221 4900.567# smooth_interact_tw 47.86913 3498.490
L'AIC nous permet de comparer des modèles qui sont basés sur des distributions différentes!
Utiliser une distribution Tweedie au lieu d'une distribution Normale améliore beaucoup notre modèle!
Le score AIC pour smooth_interact_tw
est beaucoup plus petit que celui de smooth_interact
. Utiliser une distribution Tweedie au lieu d'une distribution Normale améliore beaucoup notre modèle!
Pour modéliser une surface lisse ou non-linéaire, nous pouvons construire des fonctions lisses de différentes manières:
s()
pour modéliser un terme lisse 1-dimensionnelle, ou pour modéliser une intéraction entre des variables mesurées sur la même échelle
te()
pour modéliser une surface d'interaction 2- ou n-dimensionnelle entre des variables qui ne sont pas sur la même échelle. Comprend les effets principaux.
ti()
pour modéliser une surface d'interaction 2- ou n-dimensionnelle qui ne comprend pas les effets principaux.
Les fonctions lisses ont beaucoup de paramètres qui pourraient changer leur comportement. Les paramètres les plus souvent utilisés sont les suivants :
k
dimensions de base
Les fonctions lisses ont beaucoup de paramètres qui pourraient changer leur comportement. Les paramètres les plus souvent utilisés sont les suivants :
bs
spécifie la fonction de base sous-jacente.
s()
on utilise tp
(thin plate regression spline) et pour te()
et ti()
on utilise la base cr
(cubic regression spline).d
spécifie quelles variables d'une intéraction se trouvent sur la même échelle lorsqu'on utilise te()
and ti()
.
te(Temps, largeur, hauteur, d=c(1,2))
, indique que la largeur
et la hauteur
sont sur la même échelle, mais que temps
ne l'est pas.Lorsque l'on modélise des données cycliques, on souhaite généralement que le prédicteur soit identique aux deux bouts des phases. Pour y parvenir, nous devons modifier la fonction de base.
Utilisons une série chronologique de données climatiques, divisées en mesures mensuelles, afin de déterminer s'il y a une tendance de température annuelle. Nous utiliserons la série temporelle de la température de Nottingham dans R
:
data(nottem)
# nombre d'années de données (20 ans)n_years <- length(nottem)/12# codage qualitatif pour les 12 mois de l'année,# pour chaque année échantillonnée (série de 1 à 12, répétée 20 fois)nottem_month <- rep(1:12, times = n_years)# une variable où l'année correspondant à chaque mois dans nottem_monthnottem_year <- rep(1920:(1920 + n_years - 1), each = 12)
Lorsque l'on modélise des données cycliques, on souhaite généralement que le prédicteur soit identique aux deux bouts des phases. Pour y parvenir, nous devons modifier la fonction de base.
Utilisons une série chronologique de données climatiques, divisées en mesures mensuelles, afin de déterminer s'il y a une tendance de température annuelle. Nous utiliserons la série temporelle de la température de Nottingham dans R
:
data(nottem)
# nombre d'années de données (20 ans)n_years <- length(nottem)/12# codage qualitatif pour les 12 mois de l'année,# pour chaque année échantillonnée (série de 1 à 12, répétée 20 fois)nottem_month <- rep(1:12, times = n_years)# une variable où l'année correspondant à chaque mois dans nottem_monthnottem_year <- rep(1920:(1920 + n_years - 1), each = 12)
# Visualiser la série temporelleqplot(x = nottem_month, y = nottem, colour = factor(nottem_year), geom = "line") + theme_bw()
Voir ?nottem
pour plus de détails sur le jeu de données.
Nous pouvons modéliser le changement cyclique de température à travers les mois et la tendance non-linéaire à travers les années, en utilisant une spline cubique, ou cc
pour modéliser les effets de mois ainsi qu'un terme non-linéaire pour la variable année.
year_gam <- gam(nottem ~ s(nottem_year) + s(nottem_month, bs = "cc"), method = "REML")
summary(year_gam)$s.table# edf Ref.df F p-value# s(nottem_year) 1.621375 2.011475 2.788093 0.06141004# s(nottem_month) 6.855132 8.000000 393.119285 0.00000000
plot(year_gam, page = 1, scale = 0)
Il y a une augmentation de 1 à 1.5 degrés au cours de la série, mais au cours d'une année, il y a une variation d'environ 20 degrés. Les données réelles varient autour de ces valeurs prédites et ceci représente donc la variance inexpliquée.
Ici, nous pouvons voir l'un des avantages très intéressants de l'utilisation des GAMs. Nous pouvons soit tracer la surface réponse (valeurs prédites) ou les termes (contribution de chaque covariable) tel qu'indiqué ci-haut. Vous pouvez imaginer ce dernier en tant qu'une illustration de la variation des coefficients de régression et comment leur contribution (ou taille de leur effet) varie au fil du temps. Dans le premier graphique, nous voyons que les contributions positives de la température sont survenues après 1930.
Lorsque les observations ne sont pas indépendantes, les GAMs peuvent être utilisés soit pour incorporer:
L'autocorrélation des résidus désigne le degré de corrélation entre les résidus (les différences entre les valeurs réelles et les valeurs prédites) d'un modèle de série temporelle.
En d'autres termes, s'il y a autocorrélation des résidus dans un modèle de série temporelle, cela signifie qu'il existe un modèle ou une relation entre les résidus à un moment donné et les résidus à d'autres moments.
L'autocorrélation des résidus désigne le degré de corrélation entre les résidus (les différences entre les valeurs réelles et les valeurs prédites) d'un modèle de série temporelle.
En d'autres termes, s'il y a autocorrélation des résidus dans un modèle de série temporelle, cela signifie qu'il existe un modèle ou une relation entre les résidus à un moment donné et les résidus à d'autres moments.
L'autocorrélation des résidus est généralement mesurée à l'aide des graphiques ACF (fonction d'autocorrélation) et pACF (fonction d'autocorrélation partielle), qui montrent la corrélation entre les résidus à différents retards.
Si les graphiques ACF ou pACF montrent des corrélations significatives à des retards non nuls, il y a des preuves d'autocorrélation des résidus et le modèle peut devoir être modifié ou amélioré pour mieux capturer les modèles sous-jacents dans les données.
Voyons comment cela fonctionne avec notre modèle year_gam
!
Pour commencer, nous allons jeter un coup d'œil à un modèle avec de l'autocorrélation temporelle dans les résidus.
Revenons au modèle de la température de Nottingham pour vérifier si les résidus sont corrélés en faisant appel à la fonction (partielle) d'autocorrélation.
par(mfrow = c(1,2))acf(resid(year_gam), lag.max = 36, main = "ACF")pacf(resid(year_gam), lag.max = 36, main = "pACF")
Souvenez vous que: acf
signifie autocorrelation function, et pacf
signifie partial autocorrelation function.
ACF évalue la corrélation croisée et pACF la corrélation partielle d'une série temporelle entre points à différents décalages (donc, la similarité entre observations progressivement décalés).
Les graphiques ACF et pACF sont donc utilisés pour identifier le temps nécessaire avant que les observations ne sont plus autocorrélées.
ACF évalue la corrélation croisée et pACF la corrélation partielle d'une série temporelle entre points à différents décalages (donc, la similarité entre observations progressivement décalés).
Les graphiques ACF et pACF sont donc utilisés pour identifier le temps nécessaire avant que les observations ne sont plus autocorrélées.
Un modèle AR de faible ordre semble nécessaire (donc, avec un ou deux intervalles de temps décalés).
La fonction d'autocorrelaton (ACF; première figure) évalue la corrélation croisée d'une série temporelle entre points à différents décalages (donc, la similarité entre observations progressivement décalés).
En contraste, la fonction partielle d'autocorrelation (PACF: deuxième figure) évalue la corrélation croisée d'une série temporelle entre points à différents décalages, après avoir contrôlé les valeurs de la série temporelle à tous les décalages plus courts.
Dans le graphique ACF, la région ombrée en bleu représente l'intervalle de confiance et les lignes rouges en pointillé représentent les limites de la signification statistique.
Ajoutons des structures d'autocorrelation au modèle de température de Nottingham:
Ajoutons des structures d'autocorrelation au modèle de température de Nottingham:
df <- data.frame(nottem, nottem_year, nottem_month)year_gam <- gamm(nottem ~ s(nottem_year) + s(nottem_month, bs = "cc"), data = df)year_gam_AR1 <- gamm(nottem ~ s(nottem_year) + s(nottem_month, bs = "cc"), correlation = corARMA(form = ~ 1|nottem_year, p = 1), data = df)year_gam_AR2 <- gamm(nottem ~ s(nottem_year) + s(nottem_month, bs = "cc"), correlation = corARMA(form = ~ 1|nottem_year, p = 2), data = df)
Quel modèle est mieux ajusté?
AIC(year_gam$lme, year_gam_AR1$lme, year_gam_AR2$lme)# df AIC# year_gam$lme 5 1109.908# year_gam_AR1$lme 6 1101.218# year_gam_AR2$lme 7 1101.598
Le modèle avec la structure AR(1) donne un meilleur ajustement comparé au premier modèle (year_gam
), il y a très peu d'amélioration en passant au AR(2)
.
Il est donc préférable d'inclure uniquement la structure AR(1)
dans notre modèle.
Comme nous l'avons vu dans la section précédente, bs
spécifie la fonction de base sous-jacente. Pour les facteurs aléatoires (origine et pente linéaire), nous utilisons bs = "re"
et pour les pentes aléatoires non linéaires, nous utilisons bs = "fs"
.
Comme nous l'avons vu dans la section précédente, bs
spécifie la fonction de base sous-jacente. Pour les facteurs aléatoires (origine et pente linéaire), nous utilisons bs = "re"
et pour les pentes aléatoires non linéaires, nous utilisons bs = "fs"
.
Trois types d'effets aléatoires différents sont possibles lors de l'utilisation des GAMMs (où fac
variable qualitative utilisée pour l'effet aléatoire; x0
effet quantitatif fixe) :
s(fac, bs = "re")
Comme nous l'avons vu dans la section précédente, bs
spécifie la fonction de base sous-jacente. Pour les facteurs aléatoires (origine et pente linéaire), nous utilisons bs = "re"
et pour les pentes aléatoires non linéaires, nous utilisons bs = "fs"
.
Trois types d'effets aléatoires différents sont possibles lors de l'utilisation des GAMMs (où fac
variable qualitative utilisée pour l'effet aléatoire; x0
effet quantitatif fixe) :
interceptes aléatoires ajustent la hauteur des termes du modèle avec une valeur constante de pente : s(fac, bs = "re")
pentes aléatoires ajustent la pente d'une variable explicative numérique : s(fac, x0, bs = "re")
Comme nous l'avons vu dans la section précédente, bs
spécifie la fonction de base sous-jacente. Pour les facteurs aléatoires (origine et pente linéaire), nous utilisons bs = "re"
et pour les pentes aléatoires non linéaires, nous utilisons bs = "fs"
.
Trois types d'effets aléatoires différents sont possibles lors de l'utilisation des GAMMs (où fac
variable qualitative utilisée pour l'effet aléatoire; x0
effet quantitatif fixe) :
interceptes aléatoires ajustent la hauteur des termes du modèle avec une valeur constante de pente : s(fac, bs = "re")
pentes aléatoires ajustent la pente d'une variable explicative numérique : s(fac, x0, bs = "re")
surfaces lisses aléatoires ajustent la tendance d'une prédiction numérique de façon non linéaire: s(x0, fac, bs = "fs", m = 1)
, où l'argument m = 1 met une plus grande pénalité au lissage qui s'éloigne de 0, ce qui entraîne un retrait vers la moyenne.
Nous allons utiliser gamSim()
pour simuler un ensemble de données, cette fois-ci avec un effet aléatoire. Ensuite, nous construirons un modèle avec un intercepte aléatoire en utilisant fac
comme facteur aléatoire.
# Simuler des donnéesgam_data2 <- gamSim(eg = 6)head(gam_data2)
# 4 term additive + random effectGu & Wahba 4 term additive model
Nous allons utiliser gamSim()
pour simuler un ensemble de données, cette fois-ci avec un effet aléatoire. Ensuite, nous construirons un modèle avec un intercepte aléatoire en utilisant fac
comme facteur aléatoire.
# Simuler des donnéesgam_data2 <- gamSim(eg = 6)head(gam_data2)
# 4 term additive + random effectGu & Wahba 4 term additive model
# Rouler un modèle avec intercepte aléatoiregamm_intercept <- gam(y ~ s(x0) + s(fac, bs = "re"), data = gam_data2, method = "REML")
# Voir la sortie du modèlesummary(gamm_intercept)$s.table# edf Ref.df F p-value# s(x0) 2.999782 3.736749 3.608906 0.008655953# s(fac) 2.977044 3.000000 129.697933 0.000000000
plot(gamm_intercept, select = 2)
Nous allons premièrement tracer l'effet combiné de x0
(sans les niveaux de l'effet aléatoire) et ensuite une courbe pour les 4 niveaux de fac
:
par(mfrow = c(1,2), cex = 1.1)# Visualiser les effets combinés de x0 (sans effets aléatoires)plot_smooth(gamm_intercept, view = "x0", rm.ranef = TRUE, main = "intercept + s(x1)")# Visualiser chaque niveau de l'effet aléatoireplot_smooth(gamm_intercept, view = "x0", rm.ranef = FALSE, cond = list(fac="1"), main = "... + s(fac)", col = 'orange', ylim = c(0,25))plot_smooth(gamm_intercept, view = "x0", rm.ranef = FALSE, cond = list(fac = "2"), add = TRUE, col = 'red')plot_smooth(gamm_intercept, view="x0", rm.ranef = FALSE, cond = list(fac = "3"), add = TRUE, col = 'purple')plot_smooth(gamm_intercept, view="x0", rm.ranef = FALSE, cond = list(fac = "4"), add = TRUE, col = 'turquoise')
fac1 fac2 fac3 fac4
Ensuite, spécifions un modèle avec une pente aléatoire:
gamm_slope <- gam(y ~ s(x0) + s(x0, fac, bs = "re"), data = gam_data2, method = "REML")
summary(gamm_slope)$s.table# edf Ref.df F p-value# s(x0) 2.942915 3.667881 3.73027 0.008300806# s(x0,fac) 2.966452 3.000000 88.09058 0.000000000
par(mfrow = c(1,2), cex = 1.1)# Visualiser les effets combinés de x0 (sans effets aléatoires)plot_smooth(gamm_slope, view = "x0", rm.ranef = TRUE, main = "intercept + s(x1)")# Visualiser chaque niveau de l'effet aléatoireplot_smooth(gamm_slope, view = "x0", rm.ranef = FALSE, cond = list(fac="1"), main = "... + s(fac, x0)", col = 'orange', ylim = c(0,25))plot_smooth(gamm_slope, view = "x0", rm.ranef = FALSE, cond = list(fac = "2"), add = TRUE, col = 'red')plot_smooth(gamm_slope, view="x0", rm.ranef = FALSE, cond = list(fac = "3"), add = TRUE, col = 'purple')plot_smooth(gamm_slope, view="x0", rm.ranef = FALSE, cond = list(fac = "4"), add = TRUE, col = 'turquoise')
On peut aussi inclure un intercept et une pente aléatoire.
gamm_int_slope <- gam(y ~ s(x0) + s(fac, bs = "re") + s(fac, x0, bs = "re"), data = gam_data2, method = "REML")summary(gamm_int_slope)$s.table# edf Ref.df F p-value# s(x0) 3.006867 3.744708 3.593945 0.008802081# s(fac) 2.940108 3.000000 381.418397 0.000000000# s(fac,x0) 1.388805 3.000000 109.266270 0.113010130
par(mfrow = c(1,2), cex = 1.1)# Visualiser les effets combinés de x0 (sans effets aléatoires)plot_smooth(gamm_int_slope, view = "x0", rm.ranef = TRUE, main = "intercept + s(x1)")# Visualiser chaque niveau de l'effet aléatoireplot_smooth(gamm_int_slope, view = "x0", rm.ranef = FALSE, cond = list(fac="1"), main = "... + s(fac) + s(fac, x0)", col = 'orange', ylim = c(0,25))plot_smooth(gamm_int_slope, view = "x0", rm.ranef = FALSE, cond = list(fac = "2"), add = TRUE, col = 'red')plot_smooth(gamm_int_slope, view="x0", rm.ranef = FALSE, cond = list(fac = "3"), add = TRUE, col = 'purple')plot_smooth(gamm_int_slope, view="x0", rm.ranef = FALSE, cond = list(fac = "4"), add = TRUE, col = 'turquoise')
Notez que la pente aléatoire est statique dans ce cas :
plot(gamm_int_slope, select = 3)
select = 3 parce que la pente aléatoire est sur la troisième ligne de notre tableau sommaire.
Finalement, spécifions un modèle avec une surface lisse aléatoire.
gamm_smooth <- gam(y ~ s(x0) + s(x0, fac, bs = "fs", m = 1), data = gam_data2, method = "REML")
summary(gamm_smooth)$s.table# edf Ref.df F p-value# s(x0) 2.973666 3.69337 3.415788 0.01190229# s(x0,fac) 3.984247 35.00000 11.185386 0.00000000
plot(gamm_smooth, select=1)
select = 1 parce que la surface lisse aléatoire est sur la première ligne de notre tableau sommaire.
par(mfrow = c(1,2), cex = 1.1)# Visualiser les effets combinés de x0 (sans effets aléatoires)plot_smooth(gamm_smooth, view = "x0", rm.ranef = TRUE, main = "intercept + s(x1)")# Visualiser chaque niveau de l'effet aléatoireplot_smooth(gamm_smooth, view = "x0", rm.ranef = FALSE, cond = list(fac="1"), main = "... + s(fac) + s(fac, x0)", col = 'orange', ylim = c(0,25))plot_smooth(gamm_smooth, view = "x0", rm.ranef = FALSE, cond = list(fac = "2"), add = TRUE, col = 'red')plot_smooth(gamm_smooth, view="x0", rm.ranef = FALSE, cond = list(fac = "3"), add = TRUE, col = 'purple')plot_smooth(gamm_smooth, view="x0", rm.ranef = FALSE, cond = list(fac = "4"), add = TRUE, col = 'turquoise')
Ici, si la pente aléatoire varie selon x0
, nous aurions des courbes variables pour chaque niveau.
Tous les GAMMs de cette section peuvent être comparé avec AIC()
pour trouver le modèle le mieux ajusté:
AIC(gamm_intercept, gamm_slope, gamm_int_slope, gamm_smooth)# df AIC# gamm_intercept 8.623101 2200.672# gamm_slope 8.450850 2269.562# gamm_int_slope 10.840655 2201.538# gamm_smooth 10.558836 2202.343
Le meilleur modèle de ces trois modèles serait donc le GAMM avec un intercept aléatoire.
Cet atelier présente une brève introduction aux concepts de base et aux librairies populaires pour vous aider à estimer, évaluer et visualiser les GAMs dans R, mais il y a beaucoup plus à explorer!
mgcv
).gratia
de Gavin Simpson for GAM visualisation in ggplot2
.Enfin, les pages d'aide, disponibles via ?gam
dans R sont une excellente ressource.
Un bref aperçu de l'utilisation des GAMs lorsque la variable réponse ne suit pas une distribution normale ou que les données sont des abondances ou proportions (par exemple, distribution Gamma, binomiale, Poisson, binomiale négative).
Nous allons utiliser un exemple de données où une répartition binomiale sera nécessaire; la variable réponse représente le nombre de succès (l'événement a eu lieu) en fonction des défaillances au cours d'une expérience.
gam_data3 <- read.csv("data/other_dist.csv")str(gam_data3)# 'data.frame': 514 obs. of 4 variables:# $ prop : num 1 1 1 1 0 1 1 1 1 1 ...# $ total: int 4 20 20 18 18 18 20 20 20 20 ...# $ x1 : int 550 650 750 850 950 650 750 850 950 550 ...# $ fac : chr "f1" "f1" "f1" "f1" ...
plot(range(gam_data3$x1), c(0,1), type = "n", main = "Probabilités de succès dans le temps", ylab = "Probabilité", xlab = "x1 (temps)")abline(h = 0.5)avg <- aggregate(prop ~ x1, data=gam_data3, mean)lines(avg$x1, avg$prop, col = "orange", lwd = 2)
Nous allons tester si cette tendance est linéaire ou non avec un GAM logistique (nous utilisons une famille de distributions binomiales parce que nous avons des données de proportion).
prop_model <- gam(prop ~ s(x1), data = gam_data3, weights = total, family = "binomial", method = "REML")prop_summary <- summary(prop_model)
Nous allons tester si cette tendance est linéaire ou non avec un GAM logistique (nous utilisons une famille de distributions binomiales parce que nous avons des données de proportion).
prop_model <- gam(prop ~ s(x1), data = gam_data3, weights = total, family = "binomial", method = "REML")prop_summary <- summary(prop_model)
Qu'est ce que représente l'intercepte dans ce modèle?
prop_summary$p.table# Estimate Std. Error z value Pr(>|z|)# (Intercept) 1.174024 0.02709868 43.32402 0
Nous allons tester si cette tendance est linéaire ou non avec un GAM logistique (nous utilisons une famille de distributions binomiales parce que nous avons des données de proportion).
prop_model <- gam(prop ~ s(x1), data = gam_data3, weights = total, family = "binomial", method = "REML")prop_summary <- summary(prop_model)
Qu'est ce que représente l'intercepte dans ce modèle?
prop_summary$p.table# Estimate Std. Error z value Pr(>|z|)# (Intercept) 1.174024 0.02709868 43.32402 0
Qu'est ce que le terme de lissage indique?
prop_summary$s.table# edf Ref.df Chi.sq p-value# s(x1) 4.750198 5.791279 799.8463 0
# Estimate Std. Error z value Pr(>|z|)# (Intercept) 1.174024 0.02709868 43.32402 0
Que représente l'intercepte dans ce modèle?
Rappel le modèle utilise le nombre de succès vs échecs pour calculer le logit, qui est la logarithme du rapport entre les succès et échecs :
# Estimate Std. Error z value Pr(>|z|)# (Intercept) 1.174024 0.02709868 43.32402 0
Que représente l'intercepte dans ce modèle?
Rappel le modèle utilise le nombre de succès vs échecs pour calculer le logit, qui est la logarithme du rapport entre les succès et échecs :
Ici, l'estimé est positif ce qui signifie, qu'en moyenne, il y a plus de succès que d'échecs.
# edf Ref.df Chi.sq p-value# s(x1) 4.750198 5.791279 799.8463 0
Qu'est ce que le terme de lissage indique?
Cela représente comment le ratio de succès vs échecs change sur l'échelle de x1.
# edf Ref.df Chi.sq p-value# s(x1) 4.750198 5.791279 799.8463 0
Qu'est ce que le terme de lissage indique?
Cela représente comment le ratio de succès vs échecs change sur l'échelle de x1.
Puisque les EDF > 1, la proportion des succès augmente plus rapidement avec x1
plot(prop_model)
Il y a différente façon de représenter cette relation graphiquement :
plot()
, vous obtenez les effets partiels.itsadug::plot_smooth()
, vous obtenez les effets additionnés.Que nous disent ces graphes sur les succès et échecs?
Contribution / effets partiels
La valeur logit augmente, donc les succès augmentent et les échecs diminuent.
Valeurs ajustées, effets additionnés, intercepte inclu
Quantités égales de succès et d'échecs jusqu'à x1 = 400.
Enfin, pour nous aider à interpréter les résultats, nous pouvons re-transformer l'effet sur une échelle de proportions avec la fonction itsadug::plot_smooth()
:
plot_smooth(prop_model, view = "x1", main = "", transform = plogis, ylim = c(0,1), print.summary = F)abline(h = 0.5, v = diff$start, col = 'red', lty = 2)
Comme précédemment, la proportion de succès augmente au-dessus de 0.5 à x1 = 400.
Keyboard shortcuts
↑, ←, Pg Up, k | Go to previous slide |
↓, →, Pg Dn, Space, j | Go to next slide |
Home | Go to first slide |
End | Go to last slide |
Number + Return | Go to specific slide |
b / m / f | Toggle blackout / mirrored / fullscreen mode |
c | Clone slideshow |
p | Toggle presenter mode |
t | Restart the presentation timer |
?, h | Toggle this help |
Esc | Back to slideshow |