Il n'est en fait pas très difficile de gérer l'hétéroscédasticité dans des modèles linéaires simples (par exemple, des modèles de type ANOVA unidirectionnels ou bidirectionnels).
Robustesse de l'ANOVA
Premièrement, comme d'autres l'ont noté, l'ANOVA est incroyablement robuste aux écarts par rapport à l'hypothèse de variances égales, surtout si vous avez des données approximativement équilibrées (nombre égal d'observations dans chaque groupe). Les tests préliminaires sur des variances égales, en revanche, ne le sont pas (bien que le test de Levene soit bien meilleur que le test F communément enseigné dans les manuels). Comme l'a dit George Box:
Faire le test préliminaire sur les écarts, c'est un peu comme mettre en mer un bateau à rames pour savoir si les conditions sont suffisamment calmes pour qu'un paquebot quitte le port!
Même si l'ANOVA est très robuste, car il est très facile de prendre en compte l'hétéroscédaticité, il n'y a pas de raison de ne pas le faire.
Tests non paramétriques
Si les différences de moyens vous intéressent vraiment , les tests non paramétriques (par exemple, le test de Kruskal – Wallis) ne sont vraiment d'aucune utilité. Ils testent les différences entre les groupes, mais ils ne testent pas en général les différences de moyens.
Exemples de données
Générons un exemple simple de données où l'on aimerait utiliser l'ANOVA, mais où l'hypothèse de variances égales n'est pas vraie.
set.seed(1232)
pop = data.frame(group=c("A","B","C"),
mean=c(1,2,5),
sd=c(1,3,4))
d = do.call(rbind, rep(list(pop),13))
d$x = rnorm(nrow(d), d$mean, d$sd)
Nous avons trois groupes, avec des différences (claires) dans les moyennes et les variances:
stripchart(x ~ group, data=d)
ANOVA
Sans surprise, une ANOVA normale gère très bien cela:
> mod.aov = aov(x ~ group, data=d)
> summary(mod.aov)
Df Sum Sq Mean Sq F value Pr(>F)
group 2 199.4 99.69 13.01 5.6e-05 ***
Residuals 36 275.9 7.66
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Alors, quels groupes diffèrent? Utilisons la méthode HSD de Tukey:
> TukeyHSD(mod.aov)
Tukey multiple comparisons of means
95% family-wise confidence level
Fit: aov(formula = x ~ group, data = d)
$group
diff lwr upr p adj
B-A 1.736692 -0.9173128 4.390698 0.2589215
C-A 5.422838 2.7688327 8.076843 0.0000447
C-B 3.686146 1.0321403 6.340151 0.0046867
Avec une valeur P de 0,26, nous ne pouvons prétendre à aucune différence (dans les moyennes) entre le groupe A et B. Et même si nous ne tenions pas compte du fait que nous avons fait trois comparaisons, nous n'obtiendrions pas un P faible - valeur ( P = 0,12):
> summary.lm(mod.aov)
[…]
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.5098 0.7678 0.664 0.511
groupB 1.7367 1.0858 1.599 0.118
groupC 5.4228 1.0858 4.994 0.0000153 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 2.768 on 36 degrees of freedom
Pourquoi donc? Sur la base de l'intrigue, il y a une différence assez claire. La raison en est que l'ANOVA suppose des variances égales dans chaque groupe et estime un écart type commun de 2,77 (indiqué comme `` erreur standard résiduelle '' dans le summary.lm
tableau, ou vous pouvez l'obtenir en prenant la racine carrée du carré moyen résiduel (7,66) dans le tableau ANOVA).
Mais le groupe A a un écart-type (population) de 1, et cette surestimation de 2,77 rend (inutilement) difficile l'obtention de résultats statistiquement significatifs, c'est-à-dire que nous avons un test avec une puissance (trop) faible.
'ANOVA' avec des variances inégales
Alors, comment adapter un bon modèle, celui qui prend en compte les différences de variances? C'est facile dans R:
> oneway.test(x ~ group, data=d, var.equal=FALSE)
One-way analysis of means (not assuming equal variances)
data: x and group
F = 12.7127, num df = 2.000, denom df = 19.055, p-value = 0.0003107
Donc, si vous voulez exécuter une 'ANOVA' unidirectionnelle simple dans R sans supposer des variances égales, utilisez cette fonction. Il s'agit essentiellement d'une extension du (Welch) t.test()
pour deux échantillons avec des variances inégales.
Malheureusement, cela ne fonctionne pas avec TukeyHSD()
(ou la plupart des autres fonctions que vous utilisez sur les aov
objets), donc même si nous sommes presque sûrs qu'il existe des différences de groupe, nous ne savons pas où ils se trouvent.
Modélisation de l'hétéroscédasticité
La meilleure solution consiste à modéliser explicitement les variances. Et c'est très facile dans R:
> library(nlme)
> mod.gls = gls(x ~ group, data=d,
weights=varIdent(form= ~ 1 | group))
> anova(mod.gls)
Denom. DF: 36
numDF F-value p-value
(Intercept) 1 16.57316 0.0002
group 2 13.15743 0.0001
Des différences encore importantes, bien sûr. Mais maintenant, les différences entre les groupes A et B sont également devenues statistiquement significatives ( P = 0,025):
> summary(mod.gls)
Generalized least squares fit by REML
Model: x ~ group
[…]
Variance function:
Structure: Different standard
deviations per stratum
Formula: ~1 | group
Parameter estimates:
A B C
1.000000 2.444532 3.913382
Coefficients:
Value Std.Error t-value p-value
(Intercept) 0.509768 0.2816667 1.809829 0.0787
groupB 1.736692 0.7439273 2.334492 0.0253
groupC 5.422838 1.1376880 4.766542 0.0000
[…]
Residual standard error: 1.015564
Degrees of freedom: 39 total; 36 residual
Donc, utiliser un modèle approprié aide! Notez également que nous obtenons des estimations des écarts-types (relatifs). L'écart type estimé pour le groupe A se trouve au bas des résultats, 1,02. L'écart type estimé du groupe B est de 2,44 fois cela, ou 2,48, et l'écart type estimé du groupe C est de même 3,97 (tapez intervals(mod.gls)
pour obtenir des intervalles de confiance pour les écarts types relatifs des groupes B et C).
Correction pour plusieurs tests
Cependant, nous devons vraiment corriger les tests multiples. C'est facile en utilisant la bibliothèque 'multcomp'. Malheureusement, il n'a pas de support intégré pour les objets 'gls', nous devrons donc d'abord ajouter quelques fonctions d'assistance:
model.matrix.gls <- function(object, ...)
model.matrix(terms(object), data = getData(object), ...)
model.frame.gls <- function(object, ...)
model.frame(formula(object), data = getData(object), ...)
terms.gls <- function(object, ...)
terms(model.frame(object),...)
Maintenant, mettons-nous au travail:
> library(multcomp)
> mod.gls.mc = glht(mod.gls, linfct = mcp(group = "Tukey"))
> summary(mod.gls.mc)
[…]
Linear Hypotheses:
Estimate Std. Error z value Pr(>|z|)
B - A == 0 1.7367 0.7439 2.334 0.0480 *
C - A == 0 5.4228 1.1377 4.767 <0.001 ***
C - B == 0 3.6861 1.2996 2.836 0.0118 *
Différence toujours statistiquement significative entre le groupe A et le groupe B! ☺ Et nous pouvons même obtenir (simultanément) des intervalles de confiance pour les différences entre les moyennes de groupe:
> confint(mod.gls.mc)
[…]
Linear Hypotheses:
Estimate lwr upr
B - A == 0 1.73669 0.01014 3.46324
C - A == 0 5.42284 2.78242 8.06325
C - B == 0 3.68615 0.66984 6.70245
En utilisant un modèle approximativement (ici exactement) correct, nous pouvons faire confiance à ces résultats!
Notez que pour cet exemple simple, les données du groupe C n'ajoutent pas vraiment d'informations sur les différences entre les groupes A et B, car nous modélisons à la fois des moyennes distinctes et des écarts-types pour chaque groupe. Nous aurions pu simplement utiliser des tests t par paire corrigés pour plusieurs comparaisons:
> pairwise.t.test(d$x, d$group, pool.sd=FALSE)
Pairwise comparisons using t tests with non-pooled SD
data: d$x and d$group
A B
B 0.03301 -
C 0.00098 0.02032
P value adjustment method: holm
Cependant, pour les modèles plus compliqués, par exemple les modèles bidirectionnels ou les modèles linéaires avec de nombreux prédicteurs, l'utilisation des GLS (moindres carrés généralisés) et la modélisation explicite des fonctions de variance est la meilleure solution.
Et la fonction de variance ne doit pas simplement être une constante différente dans chaque groupe; nous pouvons lui imposer une structure. Par exemple, nous pouvons modéliser la variance comme une puissance de la moyenne de chaque groupe (et donc avoir seulement besoin d'estimer un paramètre, l'exposant), ou peut-être comme le logarithme d'un des prédicteurs du modèle. Tout cela est très simple avec GLS (et gls()
en R).
Les moindres carrés généralisés sont à mon humble avis une technique de modélisation statistique très sous-utilisée. Au lieu de vous soucier des écarts par rapport aux hypothèses du modèle, modélisez ces écarts!
R
, il peut être avantageux de lire ma réponse ici: Alternatives à l'ANOVA unidirectionnelle pour les données hétéroscédastiques , qui traite de certains de ces problèmes.