TP 2 : Modèle linéaire et ANOVA à 1 facteur Charlotte Baey 21 octobre 2016 Exercice 1 - théorème de Cochran et ANOVA à un facteur Dans cet exercice, on se propose d étudier le jeu de données sur les fleurs de trois variétés d iris, introduit par Fisher en 1936. La longueur et la largeur des sépales et des pétales ont été relevées sur 150 plantes, provenant de 3 espèces d iris différentes. Dans la suite de l exercice, on suppose que l on dispose d un échantillon gaussien. 1. Charger et décrire le jeu de données iris. # question 1 library(datasets) summary(iris) Sepal.Length Sepal.Width Petal.Length Petal.Width Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300 Median :5.800 Median :3.000 Median :4.350 Median :1.300 Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800 Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500 Species setosa :50 versicolor:50 virginica :50 2. Tester pour chaque espèce l hypothèse H 0 : µ s = 5 vs. H 1 : µ s 5 où µ s est la moyenne de la longueur des sépales (variable Sepal.Length) pour l espèce s, au niveau 5%. # question 2 # on extrait d'abord les longueurs de sépales pour chaque espèces setosa <- iris$sepal.length[iris$species == "setosa"] versicolor <- iris$sepal.length[iris$species == "versicolor"] virginica <- iris$sepal.length[iris$species == "virginica"] # puis on calcule la statistique de test pour chaque espèce stattest_setosa <- sqrt(length(setosa)) * (mean(setosa) - 5)/sd(setosa) stattest_versicolor <- sqrt(length(versicolor)) * (mean(versicolor) - 5)/sd(versicolor) stattest_virginica <- sqrt(length(virginica)) * (mean(virginica) - 5)/sd(virginica) # et enfin on calcule la région de rejet # ici on a la même taille d'échantillon pour chaque espèce, donc la même loi sous H0 : # une loi de Student à n-1=49 degrés de liberté 1
seuil_rejet <- qt(0.975, df = 49) # test bilatéral if(abs(stattest_setosa) > seuil_rejet){print("rejet")}else{print("non rejet")} if(abs(stattest_versicolor) > seuil_rejet){print("rejet")}else{print("non rejet")} if(abs(stattest_virginica) > seuil_rejet){print("rejet")}else{print("non rejet")} [1] "Non rejet" [1] "Rejet" [1] "Rejet" # Remarque : le test de Student est implémenté dans la fonction t.test # exemple pour le cas de l'espèce setosa : t.test(x = setosa, mu = 5) One Sample t-test data: setosa t = 0.12036, df = 49, p-value = 0.9047 alternative hypothesis: true mean is not equal to 5 95 percent confidence interval: 4.905824 5.106176 sample estimates: mean of x 5.006 # on retrouve la même statistique de test. Par défaut, l'alternative est bilatérale, # et la fonction t.test renvoie 2 fois la probabilité pour qu'une loi de Student à # n-1 degrés de libertés soit supérieure à la valeur de la statistique de test (pvalue <- 2*(1-pt(statTest_setosa,length(setosa)-1))) [1] 0.9046885 # ce qui est équivalent à (pvalue <- 2*pt(statTest_setosa,length(setosa)-1,lower.tail = FALSE)) [1] 0.9046885 3. Tester pour chaque espèce l hypothèse H 0 : σ 2 s = 0.3 vs. H 1 : σ 2 s 0.3 où σ 2 s est la variance de la longueur des sépales (variable Sepal.Length) pour l espèce s, au niveau 5%. # question 3 # statistiques de test pour chaque espèce stattest_setosa <- length(setosa) * var(setosa) / 0.3 stattest_versicolor <- length(versicolor) * var(versicolor) / 0.3 stattest_virginica <- length(virginica) * var(virginica) / 0.3 # et enfin on calcule la région de rejet # ici on a la même taille d'échantillon pour chaque espèce, donc la même loi sous H0 : # une loi du chi-deux à n-1=49 degrés de liberté 2
# On veut un test bilatéral, donc notre région de rejet est divisée en deux parties, # une région située à gauche et une région située à droite seuil_rejet_u <- qchisq(0.975, df = 49) # test bilatéral seuil_rejet_l <- qchisq(0.025, df = 49) # test bilatéral if(stattest_setosa > seuil_rejet_u stattest_setosa < seuil_rejet_l){ print("rejet")}else{print("non rejet")} if(stattest_versicolor > seuil_rejet_u stattest_versicolor < seuil_rejet_l){ print("rejet")}else{print("non rejet")} if(stattest_virginica > seuil_rejet_u stattest_virginica < seuil_rejet_l){ print("rejet")}else{print("non rejet")} [1] "Rejet" [1] "Non rejet" [1] "Non rejet" Les régions de rejet pour le cas unilatéral (en bleu) ou bilatéral (en rouge) sont représentées sur le graphe suivant : Régions de rejet pour le test de comparaison de moyennes 0.00 0.01 0.02 0.03 0.04 Densité de la loi du chi deux à 49 ddl Région de rejet bilatérale Région de rejet unilatérale 0 50 100 150 4. Tester au niveau 5% (test bilatéral) l égalité des variances de la largeur des sépales (variable Sepal.Width) entre les espèces setosa et versicolor d une part, et versicolor et virginica d autre part. # on récupère les vecteurs correspondants setosa <- iris$sepal.width[iris$species == "setosa"] versicolor <- iris$sepal.width[iris$species == "versicolor"] virginica <- iris$sepal.width[iris$species == "virginica"] # on calcule les statistiques de test stattest1 <- var(setosa)/var(versicolor) stattest2 <- var(virginica)/var(versicolor) # seuils de rejet (même loi sous H0 pour les deux tests) # la loi de la statistique de test sous H0 est une loi de Fisher # de degrés de liberté n1-1 et n2-1, où n1 est la taille de 3
# l'échantillon 1 et n2 celle de l'échantillon 2 seuil_rejet_u <- qf(0.975, df1 = length(setosa)-1, df2 = length(versicolor)-1) seuil_rejet_l <- qf(0.025, df1 = length(setosa)-1, df2 = length(versicolor)-1) if(stattest1 > seuil_rejet_u stattest1 < seuil_rejet_l){ print("rejet")}else{print("non rejet")} if(stattest2 > seuil_rejet_u stattest2 < seuil_rejet_l){ print("rejet")}else{print("non rejet")} [1] "Non rejet" [1] "Non rejet" # Remarque : le test de comparaison de variances est implémenté dans la fonction # var.test # Exemple pour la comparaison entre setosa et versicolor var.test(setosa,versicolor) F test to compare two variances data: setosa and versicolor F = 1.4592, num df = 49, denom df = 49, p-value = 0.1895 alternative hypothesis: true ratio of variances is not equal to 1 95 percent confidence interval: 0.828080 2.571444 sample estimates: ratio of variances 1.459233 # On retrouve la statistique de test calculée précédemment, les degrés de liberté # de la loi de Fisher, et la p-value du test. Comme pour le test de Student, par défaut # la fonction var.test réalise un test bilatéral, et la p-value est également égale à 2*(1-pf(statTest1,length(setosa)-1,length(versicolor)-1)) [1] 0.1894885 5. Tester au niveau 5% l égalité des moyennes de la largeur des sépales (variable Sepal.Width) entre les espèces setosa et versicolor d une part, et versicolor et virginica d autre part. Donner la p-valeur du test. n1 <- length(setosa) n2 <- length(versicolor) sigma <- ((n1-1)*var(setosa) + (n2-1)*var(versicolor)) / (n1+n2-2) (stattest1 <- sqrt(n1*n2/(n1+n2)) * (mean(setosa)-mean(versicolor)) / sqrt(sigma)) (pvalue1=2*(1-pt(abs(stattest1),n1+n2-2))) [1] 9.454976 [1] 1.776357e-15 4
n3 <- length(virginica) sigma <- ((n3-1)*var(virginica) + (n2-1)*var(versicolor)) / (n1+n2-2) (stattest2 <- sqrt(n3*n2/(n3+n2)) * (mean(virginica)-mean(versicolor)) / sqrt(sigma)) (pvalue2=2*(1-pt(abs(stattest2),n3+n2-2))) [1] 3.205761 [1] 0.0018191 # On peut également utiliser la fonction t.test t.test(setosa,versicolor) Welch Two Sample t-test data: setosa and versicolor t = 9.455, df = 94.698, p-value = 2.484e-15 alternative hypothesis: true difference in means is not equal to 0 95 percent confidence interval: 0.5198348 0.7961652 sample estimates: mean of x mean of y 3.428 2.770 # la statistique de test est la même, mais le nombre de degrés de liberté est différent # de celui présenté dans votre cours. Cette version du test est plus adaptée aux cas où les # deux échantillons ont des variances différentes. 6. On souhaite maintenant comparer la largeur des sépales des trois espèces simultanément. i) Ecrire le modèle correspondant, et l implémenter sous R. ii) Comparer ce modèle au modèle vide avec la fonction anova. Décrire le tableau obtenu. Que représente la colonne F-value? Comment est elle calculée à partir des colonnes précédentes? iii) Conclure sur l effet de l espèce sur la largeur des sépales. # question i) # on cherche à comparer la largeur des sépales dans les trois espèces # simultanément. Pour ce faire, on utilise una ANOVA à 1 facteur. # Dans un premier temps, on décrit le modèle permettant d'étudier un lien # entre largeur des sépales et l'espèce # La fonction lm permet de définir un modèle linéaire, c'est-à-dire une relation # linéaire entre une variable réponse et une ou plusieurs variables explicative m1 <- lm(sepal.width ~ Species, data=iris) # on étudie Sepal.Width en fonction de Species summary(m1) # on affiche les résultats Call: lm(formula = Sepal.Width ~ Species, data = iris) Residuals: Min 1Q Median 3Q Max 5
-1.128-0.228 0.026 0.226 0.972 Coefficients: Estimate Std. Error t value Pr(> t ) (Intercept) 3.42800 0.04804 71.359 < 2e-16 *** Speciesversicolor -0.65800 0.06794-9.685 < 2e-16 *** Speciesvirginica -0.45400 0.06794-6.683 4.54e-10 *** --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 Residual standard error: 0.3397 on 147 degrees of freedom Multiple R-squared: 0.4008, Adjusted R-squared: 0.3926 F-statistic: 49.16 on 2 and 147 DF, p-value: < 2.2e-16 # la fonction calcule la moyenne de Sepal.Width dans chaque groupe, et on obtient # en sortie 3 lignes: # - Intercept correspond à la moyenne dans un des trois groupes, pris comme référence # (ici, c'est le groupe qui apparaît en premier dans le jeu de données qui a été choisi) # - Speciesversicolor correspond à la différence de moyenne entre le groupe setosa et # le groupe versicolor # - Speciesvirginica correspond à la différence de moyenne entre le groupe setosa et # le groupe virginica # On a donc : mean(setosa) # 3.428, comme sur la ligne intercept [1] 3.428 mean(versicolor) # 3.428-0.658 [1] 2.77 3.428-0.658 [1] 2.77 mean(virginica) [1] 2.974 3.428-0.454 [1] 2.974 # question ii) # Dans cette question on considère le modèle "vide", c'est-à-dire celui où # il n'y a pas d'effet de l'espèce, et donc où la variable Sepal.Width ne varie # pas avec Species # Pour dire à la fonction lm que Sepal.Width ne varie pas en fonction de l'espèce, # on utilise la formule "Sepal.Width ~ 1". Ici le 1 symbolise la constante du modèle m0 <- lm(sepal.width ~ 1, data=iris) summary(m0) 6
Call: lm(formula = Sepal.Width ~ 1, data = iris) Residuals: Min 1Q Median 3Q Max -1.05733-0.25733-0.05733 0.24267 1.34267 Coefficients: Estimate Std. Error t value Pr(> t ) (Intercept) 3.05733 0.03559 85.91 <2e-16 *** --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 Residual standard error: 0.4359 on 149 degrees of freedom # on obtient ici une seule ligne en sortie, car on n'a pas distingué selon l'espèce # la valeur obtenue est la moyenne globale dans toute la population mean(iris$sepal.width) # moyenne toutes espèces confondues [1] 3.057333 # Pour tester l'hypothèse selon laquelle les moyennes des trois groupes sont égales, # on utilise la fonction anova, qui va comparer les deux modèles précédents anova(m0,m1) Analysis of Variance Table Model 1: Sepal.Width ~ 1 Model 2: Sepal.Width ~ Species Res.Df RSS Df Sum of Sq F Pr(>F) 1 149 28.307 2 147 16.962 2 11.345 49.16 < 2.2e-16 *** --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 La colonne Res.Df donne le nombre de degrés de liberté pour la somme des carrés résiduelle de chaque modèle. La colonne RSS donne la somme des carrés résiduelle ( Residual Sum of Squares - RSS) pour chaque modèle. Plus précisément, si on note y ij l observation de l individu i dans le groupe j, le modèle m1 s écrit : et la somme des carrés résiduelle pour ce modèle est y ij = µ j + ε ij ε ij N (0, σ 2 ) 3 j=1 i=1 n (y ij µ j ) 2. Dans votre cours, c est ce que l on appelle aussi SRC(m1) (comparaison de deux modèles). Pour le modèle m0, il s écrit : y ij = µ + ε ij ε ij N (0, σ 2 ). et la somme des carrés résiduelle pour ce modèle est n (y ij µ) 2. i,j 7
Dans votre cours, c est ce que l on appelle aussi SRC(m0). # on vérifie les sommes de carrés (sum((setosa - mean(setosa))^2) + sum((versicolor - mean(versicolor))^2) + sum((virginica - mean(virginica))^2)) [1] 16.962 (sum((iris$sepal.width-mean(iris$sepal.width))^2)) # RSS pour modèle m0 [1] 28.30693 La colonne Df donne la différence entre les degrés de liberté sous le modèle de la ligne 2 (m) et le modèle de la ligne 1 (m0). Il s agit du nombre de groupes moins 1. La colonne Sum of Sq contient la somme des carrés dûs au modèle, et correspond à la formule suivante : n j=1 3 (µ µ j ) 2 où n est la taille de chaque groupe. On a aussi (voir cours) la relation suivante : Sum of Sq = SRC(m0) - SRC(m1) mu<-mean(iris$sepal.width) mu1 <- mean(setosa) mu2 <- mean(versicolor) mu3 <- mean(virginica) 50*((mu-mu1)^2+(mu-mu2)^2+(mu-mu3)^2) [1] 11.34493 28.307-16.962 [1] 11.345 Enfin, la colonne F correspond à la statistique de test, selon la formule : F = (Sum of Sq)/(Df) / (SRC(m1)/(Res.Df(m1)), ici on a donc F qui vaut bien : (11.345/2) / (16.962/147) [1] 49.16033 Exercice 2 : modèle linéaire Dans cet exercice, on cherche à modéliser la hauteur des arbres d une plantation d eucalyptus en fonction de leur diamètre à 1m30 du sol. On dispose pour cela d un jeu de données constitué de n = 1429 arbres, pour lesquels on a relevé le diamètre du tronc à 1m30 du sol et la hauteur totale. 1. Importer les données depuis le fichier eucalyptus.txt 8
2. Décrire le jeu de données, identifier les variables explicative et à expliquer, et écrire le modèle linéaire gaussien correspondant. 3. Tracer le graphe de la hauteur d un arbre en fonction du diamètre de son tronc. 4. Calculer les estimateurs du maximum de vraisemblance pour les paramètres du modèle, à l aide de la fonction lm de R. 5. Quels tests sont effectués par la fonction lm? 6. Tester l absence de lien entre la circonférence et la hauteur, contre une alternative bilatérale, au niveau 5%, à l aide d un test de Fisher. Utiliser la fonction anova, et retrouver les résultats manuellement en calculant les sommes de carrés. # question 1 d <- read.table("eucalyptus.txt", header=true) summary(d) id ht circ Min. : 1.0 Min. :11.25 Min. :26.00 1st Qu.: 449.0 1st Qu.:19.75 1st Qu.:42.00 Median : 893.0 Median :21.75 Median :48.00 Mean : 883.2 Mean :21.21 Mean :47.35 3rd Qu.:1318.0 3rd Qu.:23.00 3rd Qu.:54.00 Max. :1737.0 Max. :27.75 Max. :77.00 # question 3 plot(d$ht ~ d$circ, pch=20, xlab="circonférence à 1m30", ylab="hauteur", main="hauteur en fonction de la circonférence") Hauteur en fonction de la circonférence Hauteur 15 20 25 # question 4 modele1 <- lm(ht ~ circ, data=d) summary(modele1) 30 40 50 60 70 Circonférence à 1m30 9
Call: lm(formula = ht ~ circ, data = d) Residuals: Min 1Q Median 3Q Max -4.7659-0.7802 0.0557 0.8271 3.6913 Coefficients: Estimate Std. Error t value Pr(> t ) (Intercept) 9.037476 0.179802 50.26 <2e-16 *** circ 0.257138 0.003738 68.79 <2e-16 *** --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 Residual standard error: 1.199 on 1427 degrees of freedom Multiple R-squared: 0.7683, Adjusted R-squared: 0.7682 F-statistic: 4732 on 1 and 1427 DF, p-value: < 2.2e-16 # question 6 modele0 <- lm(ht ~ 1, data=d) anova(modele0,modele1) Analysis of Variance Table Model 1: ht ~ 1 Model 2: ht ~ circ Res.Df RSS Df Sum of Sq F Pr(>F) 1 1428 8857.4 2 1427 2052.1 1 6805.3 4732.4 < 2.2e-16 *** --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 # Remarque : dans le cas d'une variable continue, le test de Fisher est déjà # proposé par la fonction lm. C'est la ligne F-statistic que l'on obtient avec # summary(modele1) # on calcule les sommes de carrés dans le modèle sous H1 et sous H0 modele0 <- lm(ht ~ 1, data=d) (scr0 <- sum(modele0$residuals^2)) [1] 8857.416 (scr1 <- sum(modele1$residuals^2)) [1] 2052.084 (stattestfisher <- ((scr0-scr1)/(2-1)) / (scr1/(1429-2))) [1] 4732.364 10
(seuil_rejet_l <- qf(0.025,1,1427)) [1] 0.0009824136 (seuil_rejet_u <- qf(0.975,1,1427)) [1] 5.034506 11