Les tests post hoc sous R

en langage R

L'essentiel de cette page

Il existe plusieurs tests post-hoc : Tukey, Student paire à paire avec ajustement de la valeurs p, Wilcoxon sur les rangs paire à paire avec ajustement de la valeurs p, lincon() de {WRS2} pour effectuer des comparaisons multiples après une anova non paramétriques ou encore medpb() de {WRS2} pour effectuer des comparaisons multiples après une anova non paramétriques

Les tests post-hoc se divisent entre deux objectifs : être puissant ou être conservateur.

Une comparaison entre les tests les plus classiques confirme bien que Newan-Keuls est puissant (plus d'erreur de type1) et que Tukey ou Scheffé sont conservateurs (plus d'erreur de type 2). En additionnant les erreurs (type 1 et type 2) en fonctions de différents échantillons testés (plus ou moins variables), on voit que le test de Newman-Keuls fait globalement moins d'erreur.

Une remarque intéressante, un bootstrap sur moyenne avec la fonction pairwise.boot(mu="mean") de {KefiR} donne de meilleurs résultats par simple boostrap que l'ensemble des tests (type 1 et 2 cumulé). Il est puissant,  et s'il se trompe plus sur les données qui varient peu (faible écart-type), il s'en sort mieux dans les conditions où les données varient beaucoup.

Ces graphiques sont à titre d'exemple.

Cette modélisation a été faite à partir de la simulation de 4 échantillons normaux de 18 individus chacun dont seul le 4ème avait une moyenne différente.

Dunn n'a pas été comparé.

paramétrique

Très conservateur. Comparaison de tous les groupes deux à deux- faible nombre de groupes

scheffe.test()

paramétrique

conservateur, mais moins que Scheffé (risque d’erreur de type I plus élevé)), comparaison des moyennes paires par paires en maintenant le risque global alpha d'erreurs de type 1 - grand nombre de groupes

HSD.test() de {agricolae}

paramétrique

Puissant, comparaison des moyennes paires par paires en les triant pour réduire au maximum le nombre de comparaison.

SNK.test() de {agricolae}

Test t par paires

(ex : test de Bonfererroni)

paramétrique

plus ou moins conservateur selon l'ajustement de la valeur p (Bonferonni est conservateur, erreur de type 2 élevé)

pairwise.t.test(p.adjust.method="bonferroni")

Wilcoxon par paires

non-paramétrique

robuste, comparaison sur les rangs, plus ou moins conservateur selon l'ajustement de la valeur p

wilcox.t.test()

Dunn

non-paramétrique

comparaison sur les rangs, plutôt conservateur selon l'ajustement de la valeur p, utilisé généralement après un test de Kruskal-Wallis.

dunn_result <- dunnTest(data ~ group, method="bonferroni") de {FSA}

Médianes par paires

non-paramétrique

robuste, comparaison sur les médiane avec bootstrap percentile (estimation de 2,5% percentile et 97,5% percentile)

medpb() de {WRS2}

Moyennes rognées

non-paramétrique

robuste, comparaison sur les moyennes avec données extrêmes rognées (% global tr)

lincon() de {WRS2}

Dunnett

paramétrique

permet de comparer tous les échantillons à un contrôle

DunnettTest() de {DescTools}

non-paramétrique

permet de comparer sur les rangs tous les échantillons paire à paire en situation à deux facteurs

posthoc.kruskal.nemenyi.test() de {PMCMRplus}

non-paramétrique

permet de comparer sur les rangs tous les échantillons paire à paire en situation à deux facteurs

posthoc.conover.test() de {PMCMRplus}

Bootstrap

non-paramétrique

permet de comparer sur les rangs tous les échantillons paire à paire en situation à deux sur la moyenne, la médiane, la moyenne mobile

pairwise.boot() de {KefiR} 

Waller-Ducan

paramétrique

approche bayésienne, permet une meilleur maîtrise des erreurs de type 1 que Newman-Keuls

waller.test() {agricolae}

data$interaction <- interaction(Lycée,Sexe)

model <- aov(Note~interaction,data=data)

library(agricolae)

print(SNK.test(model,"interaction"))

HSD.test(model, "interaction", group = TRUE)$groups

library(multcomp)

m <- lm(Note~interaction, data = data)

r <- glht(m, linfct = mcp(interaction = "Tukey"))

summary(r)

mult<- summary(glht(m, linfct = mcp(interaction = "Tukey")), test = adjusted("holm"))

mult

cld(mult)

library(DescTools)

DunnettTest(Note ~ Lycée, data = data,control="B")

On ajoutera que d'autres tests sont à creuser : LSD (faible nombre de groupes), Dunnett (comparaison à un contrôle), Duncan (comme Scheffé : sur un petit nombre de groupes aux variances pouvant être différentes - travaille en revanche sur les étendus). Source : IWV93009.pdf (univ-irem.fr) 

D'autres, enfin, après avoir travaillé sur les moyennes marginales avec emmeans() de {emmeans}, préféreront utiliser la fonction emmeans_test() de {rstatix} pour établir des comparaison paire à paire.

emmeans_test(data,Note~interaction, p.adjust.method = "bonferroni")

# ou encore

pairs(emmeans(model,"Lycée"))

pwpm(emmeans(model,"Lycée"))

resultat <- emmeans(model,~Lycée+Sexe, adjust = "bonferroni")


pwpp(resultat, method = "pairwise")

Cette figure permet de comparer rapidement les moyennes (en y) et de voir si les différences (représentées par un trait) entre deux moyennes sont significatives.

model <- aov(Note~Lycée+Sexe,data=data)

resultat <- emmeans(model,~Lycée+Sexe, adjust = "bonferroni")


# Création d'une matrice de moyennes estimées pour chaque combinaison de 'Lycée' et 'Sexe'

matrice <- xtabs(emmean ~ Lycée + Sexe, data = resultat)


# Création de matrices pour les limites inférieures et supérieures des intervalles de confiance

matriceIC_l <- xtabs(lower.CL~ Lycée + Sexe, data = resultat)

matriceIC_u <- xtabs(upper.CL~ Lycée + Sexe, data = resultat)


# Création d'un diagramme à barres avec les moyennes estimées

barplot(matrice,beside=T,col=rainbow(4))


# Chargement de la bibliothèque 'gplots'

library(gplots)


# Création d'un diagramme à barres avec les intervalles de confiance

mybar <- barplot2(matrice,beside=T,col=rainbow(4),

plot.ci=T,ci.l=matriceIC_l,ci.u=matriceIC_u,ylim=c(0,20))


# Ajout d'une grille au graphique

grid()


# Réalisation d'une analyse de variance (ANOVA) sur les notes en fonction de l'interaction entre 'Lycée' et 'Sexe'

data$interaction <- interaction(Lycée,Sexe)

model <- aov(Note~interaction,data=data)


# Réalisation d'un test post-hoc HSD (Honest Significant Difference) sur le modèle ANOVA

HSD.test(model, "interaction", group = TRUE) -> myhsd


# Extraction des interactions à partir des résultats du test HSD

mes_interactions <- rownames(myhsd$groups)


# Chargement de la bibliothèque 'stringr'

library(stringr)


# Séparation des interactions en deux facteurs

str_split_fixed(mes_interactions, "\\.",2)->mes_fac


# Tri des interactions en fonction du deuxième facteur puis du premier facteur

order(mes_fac[,2])->ordre # Trier les valeurs de sexe FFFFMMMM

ordre[order(mes_fac[ordre,1])]->ordre # Trier les valeurs de Lycée AABBCCDD

ordre[order(mes_fac[ordre,2])]->ordre # Retrier en fonction du sexe pour avoir FA,FB,FC,FD,MA,MB,MC,MD


rownames(myhsd$groups)[ordre] # contrôler le tri

text(mybar,matriceIC_u+1,myhsd$groups$groups[ordre]) # Afficher les lettres de significativité