Partie 6 Analyse de variance

  • Mise en place : Télécharger le dossier exo6 et décompressez le sur votre ordinateur. Puis ouvrez le projet R exo6.Rproj dans Rstudio.

6.1 Préparation des données

6.1.1 Chargement du fichier

On charge un fichier statistique appelé tips.csv où les séparateurs sont des points-virgules et les décimales des points.

don<-read.table(file = "resources/data/tips/tips.csv",
                sep = ";",
                header = T)
head(don)
#>   IDEN TOTBILL  TIP SEX SMOKER DAY TIME SIZE
#> 1 R001   16.99 1.01   1      0   6    1    2
#> 2 R002   10.34 1.66   0      0   6    1    3
#> 3 R003   21.01 3.50   0      0   6    1    3
#> 4 R004   23.68 3.31   0      0   6    1    2
#> 5 R005   24.59 3.61   1      0   6    1    4
#> 6 R006   25.29 4.71   0      0   6    1    4

6.1.2 Contenu du fichier

Ce dossier contient les pourboires (tips en anglais, d’où le nom du fichier) d’un serveur dans un restaurant américain aux débuts des années 1990. Le restaurant était dans un centre commercial. Il y avait une zone fumeurs et une zone non fumeurs.Les données indiquent le prix du repas, le pourboire, le sexe de la personne qui a payé et donné le pourboire, si c’était dans la zone fumeurs ou non, le jour où le repas a été pris, si c’était en journée ou en soirée et enfin, le nombre de convives.

Sources : Ces données sont disponibles dans le package R nommé rggobi et sont décrites dans l’ouvrage de Cook et Swayne intitulé Interactive and Dynamic Graphics for Data Analysis. Elles font partie des données d’exemple du livre de Bryant et Smith dont la première édition est parue en 1995 dont le titre est Practical Data Analysis: Case Studies in Business Statistics.

6.1.3 Dictionaire des variables

  • IDEN : identifiant du repas
  • TOTBILL : prix du repas (en dollars des années 1990)
  • TIP : pourboire (en dollars des années 1990)
  • SEX : sexe de la personne qui a payé (0 = Homme, 1 = Femme)
  • SMOKER : la personne qui a payé est non-fumeur (O) ou fumeur (1)
  • DAY : jour de la semaine (1 = dimanche, 2 = lundi, 3 = mardi, …)
  • TIME : repas pris en journée (0) ou le soir (1)
  • SIZE : nombre de convives

6.1.4 Recodage des variables

Le type de plusieurs variables est incorrect. On transforme les codes numériques en facteur et on recode les niveaux en français :

don$IDEN<-as.character(don$IDEN)
don$SEX<-as.factor(don$SEX)
levels(don$SEX)<-c("Homme","Femme")
don$SMOKER<-as.factor(don$SMOKER)
levels(don$SMOKER)<-c("Non fumeur", "Fumeur")
don$DAY<-as.factor(don$DAY)
levels(don$DAY)<-c("Mercredi","Jeudi","Vendredi","Samedi")
don$TIME<-as.factor(don$TIME)
levels(don$TIME)<-c("Journée","Soirée")

6.1.5 Ajout d’une nouvelle variable

On crée la variable PCT qui est le rapport entre le pourboire (TIP) et le prix total (TOTBILL) du repas exprimé en pourcentage.

don$PCT<-100*don$TIP/don$TOTBILL

6.1.6 Résumé de l’ensemble du tableau

summary(don)
#>      IDEN              TOTBILL           TIP            SEX     
#>  Length:244         Min.   : 3.07   Min.   : 1.000   Homme:157  
#>  Class :character   1st Qu.:13.35   1st Qu.: 2.000   Femme: 87  
#>  Mode  :character   Median :17.80   Median : 2.900              
#>                     Mean   :19.79   Mean   : 2.998              
#>                     3rd Qu.:24.13   3rd Qu.: 3.562              
#>                     Max.   :50.81   Max.   :10.000              
#>         SMOKER          DAY          TIME          SIZE           PCT        
#>  Non fumeur:151   Mercredi:62   Journée: 68   Min.   :1.00   Min.   : 3.564  
#>  Fumeur    : 93   Jeudi   :19   Soirée :176   1st Qu.:2.00   1st Qu.:12.913  
#>                   Vendredi:87                 Median :2.00   Median :15.477  
#>                   Samedi  :76                 Mean   :2.57   Mean   :16.080  
#>                                               3rd Qu.:3.00   3rd Qu.:19.148  
#>                                               Max.   :6.00   Max.   :71.034

6.2 Rappels sur la régression

6.2.1 La distribution de PCT est-elle normale ?

hist(don$PCT, breaks = 10,col="lightyellow",probability = TRUE)
lines(density(don$PCT,bw=3),col="red",lwd=1)

La distribution semble normale . Mais est-ce l’avis du test de Shapiro ?

shapiro.test(don$PCT)
#> 
#>  Shapiro-Wilk normality test
#> 
#> data:  don$PCT
#> W = 0.79943, p-value < 2.2e-16

Que nous apprend la boxplot ?

boxplot(don$PCT, col="lightyellow",horizontal = T)

La distribution devient presque parfaitement gaussienne si on retire les 4 valeurs exceptionnelles !

don2<-don[don$PCT<30,]
shapiro.test(don2$PCT)
#> 
#>  Shapiro-Wilk normality test
#> 
#> data:  don2$PCT
#> W = 0.99435, p-value = 0.5066
hist(don2$PCT, breaks = 10,col="lightyellow",probability = TRUE)
lines(density(don2$PCT,bw=3),col="red",lwd=1)

6.2.2 Y-a-t-il une relation entre le prix du repas et le pourboire ?

On fait le graphique …

plot(don2$TOTBILL,don2$TIP)

Puis on teste le coefficient de Pearson et celui de Sperman

cor.test(don2$TIP,don2$TOTBILL)
#> 
#>  Pearson's product-moment correlation
#> 
#> data:  don2$TIP and don2$TOTBILL
#> t = 14.906, df = 239, p-value < 2.2e-16
#> alternative hypothesis: true correlation is not equal to 0
#> 95 percent confidence interval:
#>  0.6223204 0.7543075
#> sample estimates:
#>       cor 
#> 0.6941023

cor.test(don2$TIP,don2$TOTBILL, method="spearman")
#> Warning in cor.test.default(don2$TIP, don2$TOTBILL, method = "spearman"):
#> Cannot compute exact p-value with ties
#> 
#>  Spearman's rank correlation rho
#> 
#> data:  don2$TIP and don2$TOTBILL
#> S = 688482, p-value < 2.2e-16
#> alternative hypothesis: true rho is not equal to 0
#> sample estimates:
#>       rho 
#> 0.7048791

6.2.3 Modèle de régression

On calcule le modèle de régression

mareg<-lm(don2$TIP~don2$TOTBILL)
plot(don2$TOTBILL,don2$TIP, xlab="Repas ($)",ylab = "Pourboire ($)",pch=19,cex=0.5)
abline(mareg,col="red",lwd=1)

6.3 Test d’égalité des moyennes

6.3.1 Hypothèses

On considère une variable Y quantitative continue définie sur une population de réféence P et une variable X qualitative à deux modalités divisant P en deux sous population P1 et P2.

Soit par exemple la variable Y = PCT et la variable X = SEX. On peut se demander si les femmes sont plus généreuses que les hommes, les hommes sont plus généreux que les femmes, les hommes sont différents des femmes, etc…


Y<-don2$PCT
nomY <-"Pourboire relatif (%)"

X<-don2$SEX
nomX <- "Sexe du client"

#X<-don2$SMOKER
#nomX<- "Tabagisme"

#X<-don2$TIME
#nomX<- "Moment de la journée"

6.3.2 Visualisations

Le plus simple est d’utiliser boxplot() en version de base …


boxplot(Y~X)

… ou améliorée


boxplot(Y~X,horizontal=T, xlab = nomY, ylab=nomX, col="gray80")

On peut aussi utiliser le package beanplot() en version simple …

library(beanplot)
beanplot(Y~X)

… ou améliorée :

library(beanplot)
beanplot(Y~X,horizontal=T, xlab = nomY, ylab=nomX,col = "gray80")

6.3.3 Paramètres principaux

On détermine la moyenne et l’écart-type de chaque échantillon avec la fonction tapply() couplée avec les fonctions mean(), sd() ou summary()

tapply(Y,X, mean)
#>    Homme    Femme 
#> 15.41076 16.16741
tapply(Y,X,sd)
#>    Homme    Femme 
#> 4.732686 4.329426
tapply(Y,X, summary)
#> $Homme
#>    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#>   3.564  12.136  15.325  15.411  18.622  29.199 
#> 
#> $Femme
#>    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#>   5.643  13.999  15.522  16.167  19.284  27.952

6.3.4 Test d’égalité des moyennes

Si la distribution est gaussienne on utilise le test de Student :

t.test(Y~X)
#> 
#>  Welch Two Sample t-test
#> 
#> data:  Y by X
#> t = -1.254, df = 186.21, p-value = 0.2114
#> alternative hypothesis: true difference in means between group Homme and group Femme is not equal to 0
#> 95 percent confidence interval:
#>  -1.9470273  0.4337437
#> sample estimates:
#> mean in group Homme mean in group Femme 
#>            15.41076            16.16741

Si ce n’est pas le cas et s’il y a des valeurs exceptionnelles on préfèrera le test de Wilcoxon basé sur les rangs des valeurs (comme le coefficient de corrélation de Spearman)

wilcox.test(Y~X)
#> 
#>  Wilcoxon rank sum test with continuity correction
#> 
#> data:  Y by X
#> W = 5953, p-value = 0.1908
#> alternative hypothesis: true location shift is not equal to 0

Lorsque les deux tests divergent dans leur conclusions, il y a certainement un problème de violation de l’hypothèse gaussienne. Dans ce cas, il faut sans doute transformer Y ou retirer des valeurs exceptionnelles (Cf.cours sur la corrélation et la régression)

6.4 Analyse de variance

6.4.1 Hypothèses

On considère une variable Y quantitative continue définie sur une population de réféence P et une variable X qualitative à k modalités divisant P en k sous population P1…Pk.

Soit par exemple la variable Y = PCT et la variable X = DAY. On peut se demander si la générosité des pourboires varie en fonction des jours de la semaine (mercredi, jeudi, vendredi ou samedi). On fera toutefois attention au fait que l’échantillon n’est pas très équilibré

table(don2$DAY)
#> 
#> Mercredi    Jeudi Vendredi   Samedi 
#>       62       19       86       74

6.4.2 Calcul des paramètres principaux

On va calculer les paramètres principaux de chacune des quatre sous population à l’aide de la superfonction tapply() dont la syntaxe est la suivante

tapply(variable à analyser, variable de partition , function)

La fonction tapply() s’applique sur les tableaux (data.frame). Il y a des fonctions équvalentes pour les listes, les matrices, etc…

moy<-tapply(X = don2$PCT, INDEX = don2$DAY, FUN = mean)
moy
#> Mercredi    Jeudi Vendredi   Samedi 
#> 16.12756 16.99130 15.11450 15.61781
ect<-tapply(don2$PCT, don2$DAY, sd)
ect
#> Mercredi    Jeudi Vendredi   Samedi 
#> 3.865182 4.766531 4.803544 4.858665
100*ect/moy
#> Mercredi    Jeudi Vendredi   Samedi 
#> 23.96631 28.05277 31.78104 31.10976
tapply(don2$PCT, don2$DAY, summary)
#> $Mercredi
#>    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#>   7.296  13.821  15.385  16.128  19.269  26.631 
#> 
#> $Jeudi
#>    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#>   10.36   13.37   15.56   16.99   19.66   26.35 
#> 
#> $Vendredi
#>    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#>   3.564  12.373  15.099  15.114  18.767  29.199 
#> 
#> $Samedi
#>    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#>   5.945  11.737  15.965  15.618  18.494  28.054

6.4.3 Visualisation

On utilise comme précédemment boxplot() :

boxplot(don2$PCT~don2$DAY, col="gray80")

Ou bien beanplot() :

library(beanplot)
beanplot(don2$PCT~don2$DAY,col = "gray80")

6.4.4 Modélisation simple

La solution la plus simple est d’utiliser la fonction lm() que l’on a déjà vu pour la régression.

monmodel<-lm(don2$PCT~don2$DAY)
summary(monmodel)
#> 
#> Call:
#> lm(formula = don2$PCT ~ don2$DAY)
#> 
#> Residuals:
#>      Min       1Q   Median       3Q      Max 
#> -11.5507  -2.7549  -0.1519   3.2335  14.0845 
#> 
#> Coefficients:
#>                  Estimate Std. Error t value Pr(>|t|)    
#> (Intercept)       16.1276     0.5836  27.634   <2e-16 ***
#> don2$DAYJeudi      0.8637     1.2050   0.717    0.474    
#> don2$DAYVendredi  -1.0131     0.7656  -1.323    0.187    
#> don2$DAYSamedi    -0.5097     0.7912  -0.644    0.520    
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 4.595 on 237 degrees of freedom
#> Multiple R-squared:  0.01435,    Adjusted R-squared:  0.001876 
#> F-statistic:  1.15 on 3 and 237 DF,  p-value: 0.3295

On peut ensuite appliquer une analyse de variance avec anova() sur le modèle pour mesurer la variance totale et la variance résiduelle ainsi que la significativité de la relation.

anova(monmodel)
#> Analysis of Variance Table
#> 
#> Response: don2$PCT
#>            Df Sum Sq Mean Sq F value Pr(>F)
#> don2$DAY    3   72.9  24.293  1.1503 0.3295
#> Residuals 237 5004.9  21.117

Et on peut effectuer quelques diagnostics sur les résidus :

par(mfrow = c(2,2))
plot(monmodel,c(1,2,3,4))

6.4.5 Modélisation avancée

D’un point de vue statistique, l’analyse de variance à un facteur fait appel à des modèles et des hhypothèses plus sophistiqués que le modèle de base présenté ici et comporte de nombreux tests. On se reportera donc ave profit aux trois cours en lignes de Claire Della Vedova pour une approche plus poussée

https://statistique-et-logiciel-r.com/anova-a-un-facteur-partie-1/

https://statistique-et-logiciel-r.com/anova-a-un-facteur-partie-2-la-pratique/

https://statistique-et-logiciel-r.com/anova-a-un-facteur-quand-les-hypotheses-ne-sont-pas-satisfaites/

6.5 Annexe : les variables hybrides

Le nombre de convives (SIZE) n’est ni une variable quantitative continue, ni une variable qualitative de type catégorielle. On peut donc l’appréhender de deux points de vue différents sur le plan statistique

  • variable quantitative discrète : ce qui permet d’utiliser un modèle de régression linéaire.

  • variable qualitative ordinale : ce qui permet d’utiliser un modèle d’analyse de variance.

6.5.1 SIZE = quantitative discrète

hist(don$SIZE, breaks=6, col="gray80")

modreg<-lm(don2$PCT~don2$SIZE)
summary(modreg)
#> 
#> Call:
#> lm(formula = don2$PCT ~ don2$SIZE)
#> 
#> Residuals:
#>      Min       1Q   Median       3Q      Max 
#> -12.4591  -2.9738  -0.2625   3.4693  13.2193 
#> 
#> Coefficients:
#>             Estimate Std. Error t value Pr(>|t|)    
#> (Intercept)  17.2116     0.8545  20.143   <2e-16 ***
#> don2$SIZE    -0.5944     0.3108  -1.913    0.057 .  
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 4.574 on 239 degrees of freedom
#> Multiple R-squared:  0.01507,    Adjusted R-squared:  0.01095 
#> F-statistic: 3.658 on 1 and 239 DF,  p-value: 0.057
plot(don2$SIZE,don2$PCT, col="blue", pch=19, cex=0.7)
abline(modreg, col="red")

6.5.2 SIZE = qualitative ordinale

On recode les catégories trop rares …

don2$SIZE2<-as.factor(don2$SIZE)
levels(don2$SIZE2)<-c("1-2","1-2","3+","3+","3+","3+")
summary(don2$SIZE2)
#> 1-2  3+ 
#> 157  84
plot(don2$SIZE2)

tapply(don2$PCT, don2$SIZE2, mean)
#>      1-2       3+ 
#> 16.09466 14.89818
tapply(don2$PCT, don2$SIZE2, sd)
#>      1-2       3+ 
#> 4.626275 4.472961
beanplot(don2$PCT~don2$SIZE2)

modvar<-lm(don2$PCT~don2$SIZE2)
summary(modvar)
#> 
#> Call:
#> lm(formula = don2$PCT ~ don2$SIZE2)
#> 
#> Residuals:
#>      Min       1Q   Median       3Q      Max 
#> -12.5308  -2.7696  -0.3176   3.4082  13.1553 
#> 
#> Coefficients:
#>              Estimate Std. Error t value Pr(>|t|)    
#> (Intercept)   16.0947     0.3650  44.093   <2e-16 ***
#> don2$SIZE23+  -1.1965     0.6183  -1.935   0.0541 .  
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 4.574 on 239 degrees of freedom
#> Multiple R-squared:  0.01543,    Adjusted R-squared:  0.01131 
#> F-statistic: 3.745 on 1 and 239 DF,  p-value: 0.05414