Comparaison de moyennes ou sinon médianes ou rangs avec R

Que faire lorsqu'on a un ou plusieurs échantillons qui ne se prêtent pas nécessairement à une comparaison de moyennes ?

L'essentiel de cette page

La démarche à suivre est un joli labyrinthe.

Comment comparer deux moyennes ? Comment comparer plusieurs moyennes (> 2) ?

Quelle démarche suivre pas. Voici une page (en construction) qui a pour ambition de donner cette démarche.

Remarque : j'ai aussi développé une fonction m.test() qui vous réalise l'ensemble des tests les plus appropriées et vous donne les résultats de l'analyse pas à pas.

0- Je souhaite comparer des échantillons appariés

Lorsqu'on suit toujours les mêmes individus, on parle d'échantillon apparié. Chaque échantillon est une mesure ou une notation de ces individus, mais on suit l'évolution de chacun sans les comparer en vrac.

Exemple : suivre l'évolution des notes de biologie des mêmes étudiants d'une classe.

Dans cette approche, il n'est pas nécessaire de vérifier la normalité ou la variance des échantillons.

On fera un test de Student pour données appariées :

t.test(paired=TRUE) # Pour comparer deux échantillons

pairwise.t.test(paired=TRUE) # Pour comparer plus de 2 échantillons

1- Je souhaite comparer 1 échantillon à une moyenne ou une médiane

Comparer un échantillon à une valeur moyenne attendue nécessite d'abord de contrôler sa normalité.

Exemple : comparer la largeur des sépales d'iris versicolor à la moyenne de 2.69

shapiro.test(iris$Sepal.Width[iris$Species=="versicolor"]) # échantillon normal

t.test(iris$Sepal.Width[iris$Species=="versicolor"],mu=2.69)

Exemple : comparer la largeur des sépales d'iris versicolor à la médiane de 2.69

shapiro.test(iris$Petal.Width[iris$Species=="versicolor"])# échantillon non normal

wilcox.test(iris$Petal.Width[iris$Species=="versicolor"],mu=2.69)

2- Je souhaite comparer seulement 2 échantillons

Parfois, nous n'avons que 2 échantillons à comparer, ou alors nous avons plusieurs échantillons à comparer à un seul échantillon témoin, ce qui revient à comparer chaque échantillon à ce témoin avec une logique de comparaison 2 à 2.

Voici la démarche :

2.1- Je contrôle la normalité des échantillons

Le test de Shapiro permet de vérifier que un ou plusieurs échantillons suivent la loi normale.

Un échantillon est considéré comme normale si la p-value reste supérieure à 0.05.

shapiro.test()

Je peux appliquer ce test à un échantillon (un ensemble de valeurs) ou le faire automatiquement sur tous mes échantillons grâce à la fonction by().

Exemple d'application : contrôler le respect de la loi normale pour les iris "versicolor" au niveau de la largeur des sépales  :

data(iris)

shapiro.test(iris$Sepal.Width[iris$Species=="versicolor"]) # Loi normale respectée

2.2- Je contrôle l'égalité de la variance des échantillons

A) Si les échantillons suivent la loi normale

La fonction var.test() va me permettre de voir si les échantillons ont la même variance ou pas grâce au test de Fisher-Snedecor.

On considère les variances comme équivalentes si la p-value est supérieure à 0.05.

var.test()

Exemple d'application : vérifier que la largeur des sépales des iris versicolor et setosa sont égales :

data(iris) var.test(iris$Sepal.Width[iris$Species=="versicolor"],iris$Sepal.Width[iris$Species=="setosa"]) # Variances équivalentes

Les variances étant équivalentes, je vais pouvoir me diriger vers une comparaison de ces 2 échantillons normaux : cf. 2.3- point A.

B) Si les échantillons ne suivent pas la loi normale

2.3- Je réalise un test de comparaison des échantillons

A) Échantillons normaux, variances égales

t.test(var.equal=T)

B) Échantillons normaux, variances non égales

t.test(var.equal=F)

C) Échantillons non-normaux, mais grands

t.test(var.equal=F)

D) Échantillons non-normaux, besoin d'un test robuste

wilcox.test()

Aller plus loin sur le test de Wilcoxon et comment estimer la différence entre deux échantillons lorsque l'on ne peut plus calculer la différence entre les moyennes : estimateur de Hodges-Lehmann. Page dédiée au test de Wilcoxon.

3- Je souhaite comparer plus de deux échantillons

Prenons l'exemple de ce diagramme en violon.

Il nous permet de voir que tous les échantillons n'ont pas une distribution normale (forme des "violons" en "double-gauss") ni la même variance (hauteur des "violons"). Selon, ces cas (normalité absente ou non, variances différentes), on ne pourra pas appliquer les mêmes tests statistiques.

library(vioplot)

data(iris)

vioplot(iris$Sepal.Width~iris$Species, col=c(4:6))

cf. page pour faire un diagramme en violon.


3.1- Je contrôle la normalité des échantillons

Le test de Shapiro permet de vérifier que un ou plusieurs échantillons suivent la loi normale.

Un échantillon est considéré comme normale si la p-value reste supérieure à 0.05.

shapiro.test()

Exemple sur les données iris : On voit ici des variables où chaque espèce suit la loi normale... et d'autres non.

data(iris) ; colames(iris)

by(iris$Sepal.Length,iris$Species,shapiro.test) # Normalité

by(iris$Sepal.Width,iris$Species,shapiro.test)  # Normalité

by(iris$Petal.Length,iris$Species,shapiro.test) # Non-normalité

by(iris$Petal.Width,iris$Species,shapiro.test)  # Non-normalité

Si je veux voir si Sepal.Length change d'une espèce à l'autre d'iris, je vais aller voir le point A du 3.2.

Si je veux voir si Sepal.Width change d'une espèce à l'autre d'iris, je vais aller voir le point B du 3.2.

3.2- Je contrôle la variance et la structure de mes échantillons

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 (Aplatissement 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.

A) Si les échantillons suivent la loi normale

Je vérifie que les variances de mes échantillons sont égales avec bartlett.test().

Ce test peu robuste (Levene ou Brown-Forsyth le sont plus) permet de comparer les variances des échantillons.

Les échantillons sont considérés comme ayant des variances équivalentes si la p-value > 0.05.

bartlett.test()

Si le test de Bartlett renvoie une p-value inférieur à 0.05 (les variances des échantillons ne sont pas égales), il faut faire un test de Welch, sinon, on peut partir vers une anova classique avec la fonction aov().

Exemple sur les données iris : 

Je sais que les espèces d'iris suivent la loi normale pour les variables Sepal.Length et Sepal.Width. (cf. 3.1. Je contrôle la normalité des échantillons).

Je vais don pouvoir contrôler leurs variances :

data(iris) ; colames(iris)

bartlett.test(iris$Sepal.Length~iris$Species) # Variances différentes

bartlett.test(iris$Sepal.Width~iris$Species)  # Même variance

Si je veux voir comparer les valeurs Sepal.Length des différentes espèces d'iris, je vais aller voir le point A du 3.3.

Si je veux voir comparer les valeurs Sepal.Width des différentes espèces d'iris, je vais aller voir le point B du 3.3.

B) Si les échantillons ne suivent pas la loi normale

Rubrique en cours de préparation. Désolé pour l'inconvénient.

Vous êtes étudiants de l'IUT de Périgueux et vous avez besoin de cette rubrique : contactez-moi.

3.3- Je réalise le test de comparaison des mes échantillons le plus adapté

A) Échantillons normaux, variances non égales

# Option 1 - test de Welch

oneway.test(varequal=FALSE)


# Option 2 - anova sur données hétéroscédastiques

library(fda.usc)

fanova.hetero()

Remarque : fanova se nourrit de dataframes et les classes doivent être impérativement au format factor !

pairwise.t.test(var.equal=F)

Pour identifier les catégories d'échantillon à la suite d'un pairwise.t.test(), il faudra suivre la démarche de ce lien.

Exemple sur les données iris : 

Je sais que les espèces d'iris suivent la loi normale pour les variables Sepal.Length (cf. 3.1. Je contrôle la normalité des échantillons). Je sais en revanche que ces espèces n'ont pas la même variance (cf. 3.2. point A).

Je vais don pouvoir comparer les espèces pour Sepal.Length :

data(iris) ; colames(iris)


# Avec fanova.hetero

library(fda.usc)

fanova.hetero(object= iris ,Sepal.Length~Species)


# Avec pairwise.t.test()

pairwise.t.test(iris$Sepal.Length,iris$Species,var.equal=F)

Je connais maintenant la significativité des différences entre les espèces d'iris. Je vais pouvoir ensuite découper l'ensemble en catégories a, b et c. cf. Identifier les classes de moyennes.

B) Échantillons normaux, variances égales

On peut appliquer la méthode pairwise pour appliquer le test de Student 2 à 2 en tenant compte de l'ensemble des échantillons pour éviter les faux-positifs liés au fait que l'on multiplie les tests.

pairwise.t.test() fait donc une correction des p-values.

pairwise.t.test(var.equal=T)

Pour identifier les catégories d'échantillon à la suite d'un pairwise.t.test(), il faudra suivre la démarche de ce lien.

Cela dit, on préférera le test de Newman-Keuls, plus robuste et aboutit (ci-dessous).

Le test de Newman-Keuls (SNK.test() dans la librairie agricolae) permet de comparer tous les échantillons normaux de variances égales (ou non normaux si échantillons gros) et de donner les catégories de moyennes directement (quels échantillons sont équivalents, lesquels sont différents).

Il a aussi l'avantage d'être plus fiable que le test des étendues de Tukey.

library(agricolae)

SNK.test()

Exemple de mise en oeuvre d'un test de Newman-Keuls.

Je sais que les espèces d'iris ont la même variance et suivent la loi normale pour la largeur de Sépale.

Je vais donc faire une comparaison :

#install.packages("agricolae")

library(agricolae) # librairie nécessaire pour avoir la fonction.

model <- aov(Sepal.Width~Species,data=iris) ; model

SNK.test(model,"Species")

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

SNK.test a l'avantage de donner directement les groupes (les classes de moyennes) : pratique pour la construction d'un diagramme en barre !

C) Échantillons non normaux, allures permettant une comparaison simple

SNK.test()

Si vos échantillons n'ont pas la bonne taille, on pouvait anticiper ce problème.

Inversement, on peut connaître la capacité de résolution d'un échantillon.

cf. La page : Déterminer la taille de son échantillon pour une expérience

D) Échantillons non normaux, allures ne permettant une comparaison

kruskal.test()

pairwise.wilcox.test()

Pour identifier les catégories d'échantillon à la suite d'un wilcox.t.test(), il faudra suivre la démarche de ce lien.