Na początek kilka ważnych faktów o analizie wariancji.
Jest powszechnie stosowana metoda statystyczna pozwalająca na ocenę istotności różnic wielu średnich.
Opracował ją i upowszechnił Ronald Fisher w latach 20 XX wieku.
Jest to technika badania wyników (doświadczeń, obserwacji), które zależą od jednego (jednoczynnikowa analiza wariancji) lub kilku czynników działających równocześnie (dwuczynnikowa lub wieloczynnikowa analiza wariancji).
przykłady takich czynników: metody leczenia, płeć, sposoby nawożenia (Fisher!).
czynniki takie nazywamy czynnikami grupującymi, klasyfikacyjnymi lub zmiennymi manipulacyjnymi.
Każdy czynnik ma kilka poziomów lub wariantów (częstym wzorcem jest np. mało-średnio-dużo czegoś)
Założenia analizy wariancji są podobne, jak w przypadku regresji liniowej - homogeniczność wariancji w grupach i normalność w grupach.
Model teoretyczny
Model strukturalny leżący u podstaw analizy wariancji ma następującą postać:
\[X_{ij} = \mu + \tau_j + \epsilon_{ij}\]
\(X_{ij}\) - indywidualna obserwacja X numer \(i\) należąca do grupy \(j\)
\(\mu\) - ogólna średnia
\(\tau_j\) - efekt przynależenia do grupy \(j\)
\(\epsilon_{ij}\) - błąd
Układ hipotez przy analizie wariancji
Przy analizie wariancji mamy do czynienia z następującym układem hipotez:
\[
H_0: \mu_1 = \mu_2 = ... = \mu_k
\]
W tym wypadku \(\mu_1\) do \(\mu_k\) odnoszą się do średnich w populacji dla poszczególnych poziomów czynnika grupującego. Hipoteza zerowa stwierdza, że średnie te są sobie równe.
\[
H_A: \neg H_0
\]
Hipoteza alternatywna (ta, którą chcemy uzasadnić obalając hipotezę zerową!) głosi, że \(H_0\) jest fałszem. Warto zwrócić uwagę, że \(H_0\) jest sformułowana w bardzo specyficzny sposób i może okazać się fałszywa na wiele sposobów. Wszystkie średnie mogą być od siebie różne albo tylko niektóre. Sam test jednak powie nam jedynie tyle, że powinniśmy odrzucić hipotezę zerową. Czy możemy mimo wszystko dowiedzieć się czegoś na temat tego, w jaki sposób \(H_0\) okazała się fałszywa? Tak! Żeby to zrobić, musimy przeprowadzić analizę post-hoc. O tym jednak powiemy sobie więcej na koniec tej części kursu (Uwaga! Możemy to zrobić wyłącznie wówczas, gdy ANOVA dała istotny statystycznie wynik).
Wariancja międzygrupowa i wewnątrzgrupowa
Logika analizy wariancji polega na porównywaniu wariancji międzygrupowej i wewnątrzgrupowej. Korzystamy z faktu, że – przy założeniu hipotezy zerowej – na podstawie obu możemy skonstruować estymator wariancji populacji. Jeśli hipoteza zerowa jest zaś fałszywa, to estymator ,,działa”’ tylko w jednym przypadku. Mechanizm ten będzie jaśniejszy, jeśli prześledzimy analizę wariancji na przykładzie.
Stwórzmy ramkę danych, w której mamy poziomów czynnika (jakiegokolwiek, tutaj użyhemy niewiele znaczacych poziomów ,,bardzo mało’‘, ,,mało’‘, ,,średnio’‘, ,,dużo’’ oraz ,,bardzo dużo’’), ale wszystkie wartości pochodzą z populacji o tych samych parametrach (takiej samej średniej oraz odchyleniu standardowym). Łatwo zauważyć, że jest to sytuacja, w której hipoteza zerowa jest prawdziwa.
# Nasz czynnik grupujący ma 5 poziomów, po 200 obserwacji każdyfaktor <-rep(c('bardzo mało', 'mało', 'średnio','dużo', 'bardzo dużo'), 200)# Losujemy 1000 obserwacji z rozkładu o mu = 10 i sd = 5;# po 200 na każdy poziom czynnikawartosci <-rnorm(1000, mean =10, sd =5)# Tworzymy z naszych wylosowanych obserwacji ramkę danychdf <-data.frame(condition = faktor, value = wartosci)# Wyświetlamy pierwsze 6 wierszyhead(df)
condition value
1 bardzo mało 9.991666
2 mało 10.456780
3 średnio 2.605480
4 dużo 12.042010
5 bardzo dużo 2.771282
6 bardzo mało 10.011507
Wariancja wewnętrz grup
Obliczmy wariancje w każdej z grup za pomocą funkcji tapply.
Krótkie przypomnienie jak działa tapply. Funkcja ta bierze wartości przekazane jako pierwszy argument (tutaj: df$value) i dzieli je według czynnika przekazanego jako drugi argument (tutaj: df$condition). Następnie do każdego elementu takiego podziału stosuje funkcję przekazaną jako trzeci argument – tutaj jest to var obliczające wariancję. Funkcja ta zwróci więc tyle wartości wariancji z próby (var) ile mieliśmy poziomów czynnika grupującego (df$condition) – w naszym wypadku 5.
tapply(df$value, df$condition, var)
bardzo dużo bardzo mało dużo mało średnio
27.84940 24.56699 24.82884 20.53220 26.72689
W następnym kroku obliczymy średnią z obliczonych właśnie wariancji. W ten sposób skonstruowaliśmy pierwszy z dwóch estymator wariancji populacji – obliczyliśmy wariancję w każdej z grup z osobna i wyciągnęliśmy z nich średnią.
Częściej spotkają się Państwo ze sposobem obliczania, w którym najpierw obliczamy sumę kwadratów a następnie średni kwadrat według następujących wzorów:
\[
MSE = \frac{SSE}{n-k}
\] Sposób ten jest równoważny temu, co zrobiliśmy wcześniej, co można prześledzić wykonując umieszczony poniżej kod. W moim przekonaniu w tym sposobie nieco gorzej widać,,o co chodzi’’.
# Dzielimy wyjściową ramkę danych według czynnika z kolumny `condition` df_s <-split(df, df$condition)# Obliczamy sumę kwadratów odchyleńsse <-sum(sapply(df_s, function(x){sum((x$value -mean(x$value))^2)}))sse
[1] 24776.36
# Obliczamy średni kwadratmse <- sse/(1000-5)mse
[1] 24.90086
Wariancja między grupami
Nasz drugi estymator wariancji w populacji skonstruujemy, korzystajac z nabytej wcześniej wiedzy dotyczącej odchylenia standardowego średnich z próby. Innymi słowy - kolejny raz skorzystamy z Centralnego Twierdzenia Granicznego!
Wiemy z CTG, że:
\[
\frac{\sigma^2}{n} = s^2_{\bar{X}}
\]
Ten wzór możemy przekształcić w taki sposób, że uzyskamy:
\[
\sigma^2 = ns^2_{\bar{X}}
\] Widzimy więc, że wariancja w populacji (\(\sigma^2\)) to po prostu wariancja średnich z próby (\(s^2_{\bar{X}}\)) pomnożona przez liczebność próby.
W takim razie, żeby wyestymować wariancję w populacji, powinniśmy obliczyć wariancję średnich z próby:
# Za pomocą `tapply` obliczamy średnią# dla każdego poziomu `df$condition`# Takich średnich w naszym wypadku otrzymujemy 5# `var` oblicza wariancje dla tych 5 średnichvar(tapply(df$value, df$condition, mean))
[1] 0.09605659
# Żeby otrzymać estymator wariancji w populacji,# musimy przemnożyć nasz wynik przez n = 200# Bo tyle obserwacji mamy na każdy poziom czynnika grupującegomstreat <-var(tapply(df$value, df$condition, mean))*200mstreat
[1] 19.21132
Częściej spotkają się Państwo ze sposobem obliczania, w którym najpierw obliczamy sumę kwadratów a następnie średni kwadrat według następujących wzorów:
Zwróćmy uwagę, że obliczona przez nas wartość będzie dobrym estymatorem wariancji w populacji wyłącznie wtedy, gdy próby pochodzą z tej samej populacji, ponieważ tylko takiej sytuacji dotyczy przywołane sformułowanie Centralnego Twierdzenia Granicznego! W innym wypadku tak obliczony ,,estymator’’ nie będzie działać i ten fakt wykorzystamy do skonstruowania testu statystycznego!
Statystyka testowa
Statystyka testowa \(F\) będzie proporcją między dwiema obliczonymi własnie wartościami. W przypadku, kiedy grupa nie ma znaczenia (czyli, biorac pod uwagę nasz model teoretyczny, \(\theta = 0\)), spodziewamy się, że statystyka ta będzie wynosić 1 (taka jest jej wartość oczekiwana). Dlaczego? Ponieważ obie wartości są estymatorami tego samego parametru!
\[
F = \frac{MSA}{MSE}
\]
f_stat <- mstreat/msef_stat
[1] 0.7715122
Czy wielkośc statystyki testowej, którą otrzymaliśmy, jest duża czy mała? Możemy zobaczyć, jaki rozkład ma interesująca nas statystyka testowa, przeprowadzając odpowiednią symulację.
Możemy również posłużyć się rozkładem teoretycznym \(F\). Ma on dwa parametry: liczbę stopni swobody licznika (\(k-1\)) oraz mianownika (\(n-k\)), gdzie \(k\) to liczba poziomów czynnika grupującego, a \(n\) to całkowita liczebność próby. W naszym przykładzie mamy 5 poziomów i 1000 obserwacji, więc są to odpowiednio 4 i 995 stopni swobody.
Na początek symulacja. Sprawdzamy, jaki rozkład ma statystyka testowa \(F\) przy założeniu prawdziwości hipotezy zerowej. W tym celu powtórzymy nasz eksperyment 10 000 razy i obliczamy dla każdego powtórzenia statystykę \(F\). Następnie nakładamy na histogram statystyk \(F\) uzyskanych w symulacji odpowiednią krzywą z teoretycznego rozkładu \(F\). Finalnie możemy zobaczyć, że histogram z symulowanymi wartościami \(F\) oraz krzywa rozkładu teoretycznego świetnie do siebie pasują.
f_val <-replicate(10000, {# Najpierw symulujemy naszą próbę faktor =rep(c('bardzo mało', 'mało', 'średnio', 'dużo','bardzo dużo'), 200) wartosci <-rnorm(1000, mean =10, sd =5) df <-data.frame(condition = faktor, value = wartosci)# Obliczamy MSE i MS_Treatment mse <-mean(tapply(df$value, df$condition, var)) mstreat <-var(tapply(df$value, df$condition, mean)) *200# Obliczamy statystykę testową F# czyli iloraz tych dwóch wartości mstreat / mse})# Wyniki symulacji możemy przedstawić na histogramiehist(f_val, freq =FALSE)curve(df(x, df1 =5-1, df2 =995), add =TRUE)
Skoro obliczyliśmy już statystykę testową \(F\), to musimy jeszcze sprawdzić, czy uzyskanie takiej lub bardziej skrajnej wartości jest mniej prawdopodobne niż \(5\%\) (przyjmijmy taki konwencjonalny poziom \(\alpha\)). Żeby to zrobić, musimy posłużyć się dystrybuantą rozkładu \(F\), czyli funkcją pf. Rozkład \(F\) ma dwa parametry (dwie liczby stopni swobody). df1 będzie tutaj wynosiła \(k-1\) gdzie \(k\) jest liczbą poziomów czynnika grupującego, a df2 będzie wynosiło \(n - k\) gdzie \(n\) to (całkowita) liczebność próby.
pf(f_stat, df1 =5-1, df2 =995, lower.tail =FALSE)
[1] 0.5438073
Obliczyliśmy właśnie p-wartość i tym samym przeprowadziliśmy naszą pierwszą analizę wariancji. Oczywiście przeprowadzając analizę wariancji nie musimy wykonywać ręcznie obliczeń. Jak zwykle możemy się posłużyć wbudowaną funkcją R, którą w tym wypadku jest aov.
summary(aov(value ~ condition, df))
Df Sum Sq Mean Sq F value Pr(>F)
condition 4 77 19.21 0.772 0.544
Residuals 995 24776 24.90
Analiza wariancji na przykładzie
Prześledźmy analizę wariancji na przykładzie. W bibliotece standardowej R znajduje się zbiór danych PlantGrowth, dotyczący wpływu pewnych czynników na obfitość plonów. W jednej kolumnie mamy wagę roślin, w drugiej to, do jakiej grupy przynależy dana obserwercja. Grupy były trzy - dwie eksperymentalne (trt1 oraz trt2) i oraz grupa kontrolna (ctrl). Za pomocą analizy wariancji możemy zbadać, czy warunki eksperymentalne miały wpływ na wagę roślin.
Nasza hipoteza zerowa będzie stwierdzać, że średnia waga jest taka sama we wszystkich grupach. Innymi słowy, że obserwacje dla wszystkich trzech poziomów czynnika grupującego pochodzą z populacji o tym samym parametrze średniej. Hipoteza alterantywna będzie zaś temu zaprzeczać. Oto zbiór danych (proszę wybaczyc, że wydrukuje go w całości, ale jest dość krótki):
Na początek zawsze warto stworzyć wizualizację danych - między innymi po to, aby skontrolować to, czy nasze dane spełniają założenia analizy wariancji. Zasadniczo założenia są, podobnie jak przy regresji, dwa - równa wariancja oraz normalność w grupach. Na podstawie wykresu pudełkowego możemy “na oko” ocenić, czy mamy prawo zakładać, że założenia są spełnione. Te dane nie wyglądają bardzo źle – nie mamy powodów by powiedzieć, że w sposób oczywisty dane nie spełniają założeń.
library(ggplot2)qplot(x = group, y = weight, geom ='boxplot', data = PlantGrowth)
Warning: `qplot()` was deprecated in ggplot2 3.4.0.
Normalność w grupach możemy “na oko” ocenić za pomocą wykresu kwantyl-kwantyl dla każdej grupy z osobna. Przy małych próbach może to okazać się to bardziej pomocne niż formalne testy na normalność rozkładu. Przy rozkładzie zbliżonym do normalnego punkty powinny układać się w przybliżeniu wzdłuż prostej. Wyraźne, systematyczne odchylenia od tej linii mogą wskazywać na nienormalność rozkładu.
p <-ggplot(PlantGrowth, aes(sample = weight))# scales = "free" sprawia, że skale na każdym wykresie są osobne.p +stat_qq() +stat_qq_line() +facet_grid(group~., scales ='free')
Następnie możemy “ręcznie” przeprowadzić analizę wariancji w R. Najpierw musimy policzyć sumę kwadratów między grupami i wewnatrz grup, następnie obliczyć średni kwadrat w obu przypadkach. Po obliczeniu tych dwóch rzeczy możemy obliczyć statystykę testową F, dzieląc jedną przez drugą, i sprawdzić, korzystając z dystrybuanty rozkładu F, czy odrzucamy hipotezę zerową.
To samo możemy wykonać za pomoca wbudowanej funkcji aov. Jak widzimy, uzyskane w eksperymencie rezultaty uprawniają nas do odrzucenia hipotezy zerowej. Możemy więc stiwerdzić, że proby nie pochodzą z populacji o takich samych średnich.
fit <-aov(weight ~ group, data = PlantGrowth)summary(fit)
Df Sum Sq Mean Sq F value Pr(>F)
group 2 3.766 1.8832 4.846 0.0159 *
Residuals 27 10.492 0.3886
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Testy post-hoc
Często nie tylko interesuje nas fakt, że odrzuciliśmy hipotezę, zgodnie z którą wszystkie próby pochodzą z populacji o tej samej średniej, ale chcielibyśmy móc ustalić, między którymi grupami występują statytycznie istotne różnice. Tutaj przydatne okazują się tzw. testy post-hoc. Możemy ich użyć tylko jeśli nasza główna metoda (tutaj – ANOVA) dała statystycznie istotny wynik. Przy wykonywaniu wielu testów t bez korekty rośnie ryzyko, że przynajmniej jedną różnicę uznamy za istotną, mimo że nie ma jej w populacji. Procedury takie jak test HSD Tukeya uwzględniają wielokrotne porównania i kontrolują to ryzyko dla całego zestawu porównań. Testów post-hoc, które możemy zastosować przeprowadziwszy analizę wariancji jest kilka, najbardziej popularnym jest chyba test HSD (honest significant difference) Tukeya. Możemy taki test łatwo przeprowadzić za pomocą wbudowanej w R funkcji TukeyHSD. Na poniższym wydruku widzimy, że statystycznie istotna jest różnica pomiędzy dwoma grupami eksperymentalnymi (ale już nie między każdą z nich a grupą kontrolną!).
TukeyHSD(fit)
Tukey multiple comparisons of means
95% family-wise confidence level
Fit: aov(formula = weight ~ group, data = PlantGrowth)
$group
diff lwr upr p adj
trt1-ctrl -0.371 -1.0622161 0.3202161 0.3908711
trt2-ctrl 0.494 -0.1972161 1.1852161 0.1979960
trt2-trt1 0.865 0.1737839 1.5562161 0.0120064
Możemy wyniki naszej analizy przedstawić w formie graficznej za pomocą funkcji plot. Na osi Y mamy zestawienia ze sobą poziomów czynnika (tutaj - group), na osi X zaś 95% przedziały ufności różnicy średnich między nimi. Istotne statystycznie są te różnice, które nie obejmują zera (proszę przypomnieć sobie testowanie hipotez za pomocą przedziałów ufności).
plot(TukeyHSD(fit))
Wielkość efektu
W przypadku analizy wariancji standardowo używa się miary \(\eta^2\). Oblicza się ją dzięląc międzygrupową sumę kwadratów przez całkowitą sumę kwadratów.
Interpretacja tej miary jest analogiczna jak w przypadku znanego już Państu \(R^2\) i jest to stosunek zmienności wyjaśnianej przez nasz predyktor do całkowitej zmienności zmiennej zależnej. Jeżeli mamy taką ochotę, to mozemy skorzystać z funkcji obliczającą tę miarę w jednej z wielu bibliotek, które taką funkcję oferują. Ja skorzystałem tutaj z DescTools i funkcji EtaSq (ale jest ich wiele!).
DescTools::EtaSq(fit)
eta.sq eta.sq.part
group 0.2641483 0.2641483
Analiza wariancji a model liniowy
Istnieją bardzo podobne podobieństwa między analizą wariancji i modelem liniowym. Można nawet stwierdzić, że analiza wariancji to po prostu szczególny przypadek modelu liniowego. Fakt, że omawiane są oddzielnie podyktowane jest w znacznej mierze zaszłościami historycznymi. W artykule dostępnym w sekcji dla zalogowanych “Multiple Regression As A General Data-Analytic System” autorstwa Jacoba Cohena znajduje się dobre wyjaśnienie wielu zawiłości z tym związanych.
Zobaczmy sobie podsumowanie jednoczynnikowej analizy wariancji oraz modelu liniowego z jednym kategorialnym predyktorem.
Analiza wariancji:
fit_aov <-aov(weight ~ group, data = PlantGrowth)summary(fit_aov)
Df Sum Sq Mean Sq F value Pr(>F)
group 2 3.766 1.8832 4.846 0.0159 *
Residuals 27 10.492 0.3886
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
DescTools::EtaSq(fit_aov)
eta.sq eta.sq.part
group 0.2641483 0.2641483
Model liniowy:
fit_lm <-lm(weight ~ group, data = PlantGrowth)summary(fit_lm)
Call:
lm(formula = weight ~ group, data = PlantGrowth)
Residuals:
Min 1Q Median 3Q Max
-1.0710 -0.4180 -0.0060 0.2627 1.3690
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 5.0320 0.1971 25.527 <2e-16 ***
grouptrt1 -0.3710 0.2788 -1.331 0.1944
grouptrt2 0.4940 0.2788 1.772 0.0877 .
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.6234 on 27 degrees of freedom
Multiple R-squared: 0.2641, Adjusted R-squared: 0.2096
F-statistic: 4.846 on 2 and 27 DF, p-value: 0.01591
Zwróćmy uwagę na kilka rzeczy. Dla analizy wariancji hipoteza zerowa wygląda tak:
\[
H_0: \mu_1 = \mu_2 = \mu_3
\]
Dla modelu liniowego hipotezą zerową było:
\[
H_0: R^2 = 0
\]
Hipotezy te, chociaż pozornie brzmiące różnie, w rzeczywistości są sobie matematycznie równoważne i można je przetestować tym samym testem (na co wskazuje nam w wydruku R taka sama wartość statystyki testowej \(F\)). Możemy to zilustrować takim oto rozumowaniem.
Jeżeli hipoteza zerowa analizy wariancji jest prawdziwa (czyli średnie w grupach są w populacji identyczne), to znajomość tego, do której grupy dana obserwacja należy, nie pozwala nam przewidywać wartości tej obserwacji lepiej niż po prostu znajomość ogólnej średniej. W takiej sytuacji nasz model nie wyjaśnia żadnej części wariancji zmiennej zależnej czyli \(R^2\) jest równe zeru. Warto również zwrócić uwagę na to, że \(R^2\) jest równy obliczonemu przez nas \(\eta^2\), co nie powinno dziwić biorać pod uwagę sposób w jaki oblicza się obie te wartości.
Na kolejnych zajęciach, gdy będziemy zajmować się nieco bardziej skomplikowanymi wariantami analizy wariancji (w których uwzględniamy więcej czynników), zobaczymy w jaki sposób tę paralelę między modelem liniowym a analizą wariancji można pociągnąć dalej.