Test de Newman-Keuls

Différence significatives entre moyennes

Test de Newman-Keuls, tests de Student en séries, Comparaisons post-hoc

Si j'ai plusieurs échantillons dont je souhaite comparer les moyennes, plusieurs approches sont possibles.

1- D'abord analyser la variance

L'analyse de la variance se fait avec les fonctions anova() ou aov(). Elle va permettre de voir, si des différences significatives ressortent.

Il faudra alors chercher quelles moyennes semblent se distinguer des autres. On va donc réaliser une comparaison post-hoc, un test qui se décide donc a posteriori et en fonction de l'analyse de la variance : méfiance donc.

INCONVÉNIENT : l'analyse de la variance peut passer à côté de différences réelles si les différences ne concernent qu'un nombre réduit de moyennes.

ATTENTION : une ANOVA doit être aussi validée (ce qu'on oublie souvent de faire par différents tests) : SKEWNESS (symétrie des courbes de densité), KURTOSIS (applatissement de la courbe de densité) et LEVENE (Démontrer que les variances des échantillons sont égales de façon robuste).

Remarque : il faudrait creuser les différences entre anova() et aov() : le 2ème semble pouvoir utiliser lm() de façon interne et peut donc s'en passer.

# Un jeu de données qui décrit de voitures

data(mtcars)

head(mtcars)

mtcars$carb[mtcars$carb>=4] <- 4


# Poyenne conso en fonction du nombre de carburateurs

result <- by(mtcars$mpg,mtcars$carb,mean)

linear_model <- lm(mtcars$mpg~mtcars$carb)

model <- anova(linear_model) ; model

On voit ici les "***" qui montre qu'il a bien une belle différence entre certaines de nos moyennes.

Analysis of Variance Table


Response: mtcars$mpg

            Df Sum Sq Mean Sq F value    Pr(>F)    

mtcars$carb  1 462.81  462.81  20.934 7.706e-05 ***

Residuals   30 663.24   22.11                      

---

Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

# Affichage du diagramme en barres

barplot(result,col="orange",lwd=2,main="Consommation en miles/gallon en fonction\ndu nombre de carburateurs",

names.arg =c(1:3,"4 ou plus"))

Reste à voir combien il y a de catégories de moyennes. Les voiture à 1 carburateur sont elles significativement différentes de celles à 2 carburateurs ?

2- Faire des tests de Student en série ?

C'est une approche brute de décoffrage : on va croiser tous les échantillons pour comparer leurs moyennes 2 à 2. On va ainsi identifier qui est différent de qui et pouvoir définir des catégories de moyennes.

AVANTAGE : C'est très fin. On pourra voir des différences qui n'auront pas été vues lors de l'ANOVA.

INCONVÉNIENT : On risque de voir comme significatives des différences du fait du hasard. En effet, sur un grand nombre d'échantillons, le hasard finira bien par nous sortir un échantillon qui contraste avec un autre. cf. ce lien externe qui revient sur ce problème.

DÉMARCHE : Il faut d'abord vérifier que les échantillons respectent la loi normal. S'ils suivent la loi normale, on pourra faire des tests de Student, sinon, il faudra faire des tests de Wilcoxon (comparaison des médianes, très robuste).

Remarque : Student, test paramétrique vs Wilcoxon, non paramétrique (pas d'hypothèse initiale de répartition).

2.1- Avec une boucle, Student 2 à 2 (déconseillé)


######################

#  Tests croisés et systématique

######################

# Shapiro : si p-value < 0.05 => Loi non normale

by(mtcars$mpg,mtcars$carb,length)

by(mtcars$mpg,mtcars$carb,shapiro.test)

# Séries de tests : Wilcoxon si non normale, Student si loi normale suivi pour échantillons

modalités <- sort(unique(mtcars$carb))

for (i in 1:(length(modalités)-1)) {

  for (j in (i+1):length(modalités)) {

  temp0 <- mtcars$mpg[mtcars$carb == modalités[i]]

  temp1 <- mtcars$mpg[mtcars$carb == modalités[j]]

  #Choisir le test (ici Student) en changeant le #.

  pval <- t.test(temp0,temp1)$p.value

  #pval <- wilcox.test(temp0,temp1)$p.value

  if (pval < 0.05) {

   cat("Différence signif entre ",modalités[i]," et ",modalités[j],"avec pval : ",pval,"\n")

  }

 }

}

bp <- barplot(result,

     col="orange",lwd=2,

     main="Consommation en miles/gallon en fonction\ndu nombre de carburateurs",

     names.arg =c(1:3,"4 ou plus"),

     ylim=c(0,30))



text(bp, result+2, c("a","a","b","b"))

Indiquer les catégories par des lettres. 

Revenir sur cette formation simple (PAGE DE FORMATION + EXEMPLE COMPLET).

2.2- Avec une fonction de systématisation (pairwise.t.test)

Il vaut mieux utiliser la fonction pairwise.t.test() (ou son pendant en wicoxon pairwise.wilcox.test()).

C'est plus simple et on tient compte de la tous les échantillons (ajustement de la p-value) pour éviter les différences faussement significatives dues au hasard.

data(mtcars)

mtcars$carb[mtcars$carb>=4] <- 4

pairwise.t.test(mtcars$mpg,mtcars$carb)-> mon_resultat : mon_resultat

Et voilà! tous les tests de Student ont été fait en une ligne (on peut changer aussi la méthode d'ajustement de la p-value en jouant sur les arguments de la fonction pariwise.t.test().

3- Appliquer un test de Newman-Keuls

Une possibilité est d'appliquer un test de Newman-Keuls qui permettra de définir les catégories de barres.

AVANTAGE : ce test (réputé plus puissant que le test des étendues de Tukey qui présente l'avantage de permettre de calculer la plus petite différence significative entre les échantillons (exemple ici))  tient compte de tous les échantillons pour éviter les différences faussement significatives. C'est un test robuste.

install.packages("agricolae") ; library(agricolae) # librairie nécessaire pour avoir la fonction.

model <- aov(mpg~carb,data=mtcars) ; model


SNK.test(model,"carb")

print(SNK.test(model,"carb", group=TRUE))

On voit bien ici que les 2 catégories a et b trouvés en faisant un long algorithme de Student en série donnent la même chose ici avec Newman-Keuls.

       mpg groups

1 25.34286      a

2 22.40000      a

3 16.30000      b

4 16.05000      b