W rzeczywistości nie jest bardzo trudno poradzić sobie z heteroscedastycznością w prostych modelach liniowych (np. Jedno- lub dwukierunkowych modelach typu ANOVA).
Solidność ANOVA
Po pierwsze, jak zauważają inni, ANOVA jest niezwykle odporna na odchylenia od założenia równych wariancji, szczególnie jeśli masz w przybliżeniu zbalansowane dane (taka sama liczba obserwacji w każdej grupie). Z drugiej strony, wstępne testy na równe wariancje nie są (chociaż test Levene'a jest znacznie lepszy niż test F powszechnie nauczany w podręcznikach). Jak ujął to George Box:
Wykonanie wstępnego testu wariancji jest raczej jak wypłynięcie w morze łodzią wiosłową, aby dowiedzieć się, czy warunki są wystarczająco spokojne, aby liniowiec mógł opuścić port!
Mimo że ANOVA jest bardzo solidna, ponieważ bardzo łatwo jest wziąć pod uwagę heteroscedyczność, nie ma powodu, aby tego nie robić.
Testy nieparametryczne
Jeśli naprawdę interesują Cię różnice w środkach , testy nieparametryczne (np. Test Kruskala – Wallisa) naprawdę nie mają żadnego zastosowania. Robią badania różnic między grupami, ale robią nie w ogólnych różnic w badanych środków.
Przykładowe dane
Wygenerujmy prosty przykład danych, w których chcielibyśmy użyć ANOVA, ale gdzie założenie równych wariancji nie jest prawdziwe.
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)
Mamy trzy grupy, z (wyraźnymi) różnicami zarówno pod względem średnich, jak i wariancji:
stripchart(x ~ group, data=d)
ANOVA
Nic dziwnego, że normalna ANOVA radzi sobie z tym całkiem dobrze:
> 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
Które grupy się różnią? Użyjmy metody HSD Tukeya:
> 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
Przy wartości P wynoszącej 0,26 nie możemy twierdzić żadnej różnicy (w środkach) między grupą A i B. I nawet gdybyśmy nie wzięli pod uwagę, że dokonaliśmy trzech porównań, nie uzyskalibyśmy niskiego P - wartość ( 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
Dlaczego? Opierając się na działce, nie jest całkiem wyraźna różnica. Powodem jest to, że ANOVA zakłada równe wariancje w każdej grupie i szacuje wspólne odchylenie standardowe na 2,77 (przedstawione w summary.lm
tabeli jako „resztkowy błąd standardowy” lub można go uzyskać, przyjmując pierwiastek kwadratowy z resztkowego średniego kwadratu (7,66) w tabeli ANOVA).
Ale grupa A ma odchylenie standardowe (populacyjne) wynoszące 1, a to przeszacowanie 2,77 utrudnia (niepotrzebnie) uzyskanie statystycznie istotnych wyników, tj. Mamy test z (zbyt) niską mocą.
„ANOVA” z nierównymi wariancjami
Jak więc dopasować odpowiedni model, który bierze pod uwagę różnice w wariancjach? To proste w 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
Jeśli więc chcesz uruchomić prostą jednokierunkową „ANOVA” w R bez zakładania równych wariancji, użyj tej funkcji. Jest to w zasadzie rozszerzenie (Welch) t.test()
dla dwóch próbek z nierównymi wariancjami.
Niestety nie działa TukeyHSD()
(lub z większością innych funkcji używanych na aov
obiektach), więc nawet jeśli jesteśmy całkiem pewni, że istnieją różnice grupowe, nie wiemy, gdzie one są.
Modelowanie heteroscedastyczności
Najlepszym rozwiązaniem jest jawne modelowanie wariancji. I to jest bardzo łatwe w 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
Oczywiście wciąż znaczne różnice. Ale teraz różnice między grupą A i B również stały się istotne statystycznie ( 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
Tak więc zastosowanie odpowiedniego modelu pomaga! Zauważ również, że otrzymujemy szacunki (względnych) odchyleń standardowych. Oszacowane odchylenie standardowe dla grupy A można znaleźć na dole wyników 1,02. Oszacowane odchylenie standardowe grupy B jest 2,44 razy większe lub 2,48, a oszacowane odchylenie standardowe grupy C wynosi podobnie 3,97 (typ, intervals(mod.gls)
aby uzyskać przedziały ufności dla względnych odchyleń standardowych grup B i C).
Korekta do wielokrotnych testów
Jednak naprawdę powinniśmy poprawić wiele testów. Jest to łatwe przy użyciu biblioteki „multcomp”. Niestety nie ma wbudowanej obsługi obiektów „gls”, dlatego najpierw musimy dodać kilka funkcji pomocniczych:
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),...)
Teraz przejdźmy do pracy:
> 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 *
Nadal istotna statystycznie różnica między grupą A i grupą B! ☺ I możemy nawet uzyskać (równoczesne) przedziały ufności dla różnic między grupami oznacza:
> 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
Używając w przybliżeniu (tutaj dokładnie) poprawnego modelu, możemy ufać tym wynikom!
Zauważ, że w tym prostym przykładzie dane dla grupy C tak naprawdę nie dodają żadnych informacji na temat różnic między grupami A i B, ponieważ modelujemy zarówno oddzielne średnie, jak i odchylenia standardowe dla każdej grupy. Moglibyśmy właśnie zastosować parowe testy t poprawione dla wielu porównań:
> 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
Jednak w przypadku bardziej skomplikowanych modeli, np. Modeli dwukierunkowych lub modeli liniowych z wieloma predyktorami, najlepszym rozwiązaniem jest użycie GLS (uogólnione najmniejsze kwadraty) i jawne modelowanie funkcji wariancji.
A funkcja wariancji nie musi być po prostu inną stałą w każdej grupie; możemy narzucić jej strukturę. Na przykład możemy modelować wariancję jako potęgę średniej z każdej grupy (a zatem potrzebujemy tylko oszacować jeden parametr, wykładnik) lub być może jako logarytm jednego z predyktorów w modelu. Wszystko to jest bardzo łatwe z GLS (i gls()
R).
Uogólnione najmniejsze kwadraty to IMHO bardzo niewykorzystana technika modelowania statystycznego. Zamiast martwić się odchyleniami od założeń modelu , modeluj te odchylenia!
R
, czy nie , skorzystaj z mojej odpowiedzi tutaj: alternatywy dla jednostronnej ANOVA dla danych heteroscedastycznych , która omawia niektóre z tych problemów.