본문 바로가기
  • plotly로 바로쓰는 동적시각화 in R & 파이썬
통계의 기초

ANOVA in R

by 아참형인간 2022. 10. 18.
anova.knit

본 포스트는 https://medium.com/%5C@hablo/a-beginner-guide-to-t-test-and-anova-analysis-of-variance-in-r-programming-d65944a97ce1 를 참조하여 작성되었음.

ANOVA(ANalysis of VAriance) : 분산 분석

분산 분석(Analysis Of VAriance)은 둘 이상의 모집단 평균이 다른지 여부를 확인하기 위한 통계적 검정이다. 결국 둘 이상의 그룹을 비교하여 유의미한 차이가 있는지 확인하는 데 사용된다.

사실상,

  • Student t-test 는 2개의 그룹간의 평균을 비교하는 것이고,
  • ANOVA는 2개 이상의 그룹을 비교하는데 3개 이상의 그룹간의 평균의 비교에 많이 사용된다.

ANOVA는 각 표본 그룹이 정규 분포를 따르고 분산이 동일하며 독립적이라는 가정이 만족되어야 한다.

일원 분산 분석(One Way ANOVA)

일원 분산 분석(One Way ANOVA) 두 개 이상의 그룹간의 평균의 차이를 분석하는 데 사용된다.

자동차의 연비에 대한 예를 살펴보자. 종속 변수(DV)는 연료 갤런(mpg)당 자동차가 이동할 수 있는 마일이고 독립 변수(IV)는 자동차의 브랜드라고 가정한다. 다음과 같이 세개의 브랜드 자동차간의 평균이 유의하게 다른지 테스트하기 위해 분산 분석을 사용한다.

A B C
19 28 20
17 30 23
16 32 25
20 33 24
17 31 21
19 27 22
15 29 24
21 30 21

위 데이터를 R로 불러들인다.

car <- c(rep(c('A', 'B', 'C'), each = 8))
mpg <- c(19, 17, 16, 20, 17, 19, 15, 21,
         28, 30, 32, 33, 31, 27, 29, 30, 
         20, 23, 25, 24, 21, 22, 24, 21)

mpgData <- data.frame(car, mpg)
mpgData
##    car mpg
## 1    A  19
## 2    A  17
## 3    A  16
## 4    A  20
## 5    A  17
## 6    A  19
## 7    A  15
## 8    A  21
## 9    B  28
## 10   B  30
## 11   B  32
## 12   B  33
## 13   B  31
## 14   B  27
## 15   B  29
## 16   B  30
## 17   C  20
## 18   C  23
## 19   C  25
## 20   C  24
## 21   C  21
## 22   C  22
## 23   C  24
## 24   C  21

\(H0 : \mu(A) = \mu(B) = \mu(C)\)

\(Ha : \text{최소 두개의 평균은 다르다(at least two means are different)}\)

ANOVA를 실행하기 위해서는 aov()를 사용할 수 있다.

model <- aov(mpg ~ car, data = mpgData)
summary(model)
##             Df Sum Sq Mean Sq F value  Pr(>F)    
## car          2    588  294.00   77.17 2.1e-10 ***
## Residuals   21     80    3.81                    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

위의 결과를 보면 F 값(F value)는 77.17, p-value는 매우 작은 값으로 0.05보다 작게 나타나고 있다. 이로 인해 세 그룹의 평균간의 차이가 없다는 귀무 가설을 기각할 수 있고, 최소 두개의 평균은 다르다는 대립 가설을 채택한다.

그렇다면 각각의 평균은 어떻게 다르고 어떤 평균간의 차이가 의미가 있을지를 알수 있는가? 이는 TukeyHSD()를 사용한다.

TukeyHSD(model)
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = mpg ~ car, data = mpgData)
## 
## $car
##     diff       lwr       upr     p adj
## B-A 12.0  9.540175 14.459825 0.0000000
## C-A  4.5  2.040175  6.959825 0.0004259
## C-B -7.5 -9.959825 -5.040175 0.0000005

위의 결과를 보면 P-Value인 ‘p adj’ 값이 모두 0.05보다 작기 때문에 B와 A, C와 A, C와 B 간의 평균의 차이가 모두 유의미하게 차이가 있다는 것을 알 수 있는데 각각의 평균의 차이가 C-A가 4.5인 반면 B-A가 12.0으로 더 크게 나타나고 있다.

마지막으로 중요한 것은 신뢰 구간에 값 0이 포함되어 있지 않으면 두 변수의 평균 간에 상당한 차이가 있다는 것이다.

예를 들어 B-A의 상한(upr)은 14.45이고 하한(lwr)은 9.54로 그 사이에 0을 포함하고 있지 않다.

이원 분산 분석(Two Way ANOVA)

이원 분산 분석은 하나의 종속 변수와 두개의 독립변수간의 상호작용이 영향을 미치는지를 알아보기 위해 사용된다. DV의 두 IV 사이에 상호 작용이 있는지 연구하고 싶기 때문에 두 개의 독립 변수(IV)가 조합되어 종속 변수(DV)에 어떤 영향을 미치는지 분석하고자 할 때 적용됩니다.

예를 들어, 위에서 언급한 자동차의 mpg 값이 고속도로에서 운전할 때와 시내에서 운전할 때 다른지 알고 싶을때 사용할 수 있다.

A B C
city 14 28 20
city 12 26 21
city 15 26 19
highway 19 33 27
highway 18 32 26
highway 19 33 24

이원 분산 분석을 위해 다음과 같이 데이터를 만든다.

where <- c(rep('city', 9), rep('highway', 9))
brand <- c(rep(c('A', 'B', 'C'), each = 3))
mpg2 <- c(14, 12, 15, 
          28, 26, 26, 
          20, 21, 19, 
          19, 18, 19, 
          33, 32, 33, 
          27, 26, 24)

twoway <- data.frame(where, brand, mpg2)
twoway
##      where brand mpg2
## 1     city     A   14
## 2     city     A   12
## 3     city     A   15
## 4     city     B   28
## 5     city     B   26
## 6     city     B   26
## 7     city     C   20
## 8     city     C   21
## 9     city     C   19
## 10 highway     A   19
## 11 highway     A   18
## 12 highway     A   19
## 13 highway     B   33
## 14 highway     B   32
## 15 highway     B   33
## 16 highway     C   27
## 17 highway     C   26
## 18 highway     C   24

이원 분산 분석에는 세 가지의 가설들이 검정되어야 한다.

첫 번째 가설은 다음과 같다.

\(H0 : \mu(A) = \mu(B) = \mu(C)\)

\(Ha : \text{최소 두개의 평균이 다르다(At least two means are different)}\)

model1 <- aov(mpg2 ~ where + brand + where*brand, data = twoway)

summary(model1)
##             Df Sum Sq Mean Sq F value   Pr(>F)    
## where        1  138.9  138.89 108.696 2.28e-07 ***
## brand        2  546.8  273.39 213.957 4.12e-10 ***
## where:brand  2    0.8    0.39   0.304    0.743    
## Residuals   12   15.3    1.28                     
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

위의 결과에서 p brand의 p-value는 0.05보다 작기 때문에 brand간의 평균은 최소 두개의 평균이 다르다는 대립 가설을 채택한다.

두 번째 가설은

\(H0 : \mu(city) = \mu(highway)\)

\(Ha : \mu(city) \ne \mu(highway)\)

앞선 aov()의 결과에서 brand 변수와 유사하게, 차를 운전하는 장소를 의미하는 where 변수는 p-값이 0.05(= 2.28e-07)보다 작기 때문에 장소에 따른 평균 차이가 같지 않다는 대립 가설을 채택한다.

마지막으로 다음의 가설을 검정한다.

\(H0 : \text{brand와 where간의 상호작용이 없다}\)

\(Ha : \text{brand와 where간의 상호작용이 있다}\)

앞선 aov()의 결과에서 where:brand가 where에 따른 brand의 상호작용에 대한 변수를 말한다. 이 변수의 p value가 0.743으로 매우 큰 p-value가 나온다. 이로 인해 귀무가설인 ’brand와 where 간의 상호작용이 없다’는 귀무가설을 기각할 수 없고 brand와 where간의 상호작용이 있다는 가설에 대한 충분한 증거가 없다.

이를 앞에서 사용했던 TukeyHSD()를 사용해 상세히 살펴본다. Tukey 테스트는 차이가 가장 많이 발생하는 부분과 특정 그룹의 평균이 다른 부분을 파악하는 데 도움이 된다.

TukeyHSD(model1)
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = mpg2 ~ where + brand + where * brand, data = twoway)
## 
## $where
##                  diff      lwr     upr p adj
## highway-city 5.555556 4.394531 6.71658 2e-07
## 
## $brand
##          diff       lwr       upr p adj
## B-A 13.500000 11.758872 15.241128 0e+00
## C-A  6.666667  4.925539  8.407795 8e-07
## C-B -6.833333 -8.574461 -5.092205 6e-07
## 
## $`where:brand`
##                           diff        lwr       upr     p adj
## highway:A-city:A      5.000000   1.899856  8.100144 0.0016653
## city:B-city:A        13.000000   9.899856 16.100144 0.0000001
## highway:B-city:A     19.000000  15.899856 22.100144 0.0000000
## city:C-city:A         6.333333   3.233190  9.433477 0.0001960
## highway:C-city:A     12.000000   8.899856 15.100144 0.0000002
## city:B-highway:A      8.000000   4.899856 11.100144 0.0000190
## highway:B-highway:A  14.000000  10.899856 17.100144 0.0000000
## city:C-highway:A      1.333333  -1.766810  4.433477 0.7020060
## highway:C-highway:A   7.000000   3.899856 10.100144 0.0000738
## highway:B-city:B      6.000000   2.899856  9.100144 0.0003268
## city:C-city:B        -6.666667  -9.766810 -3.566523 0.0001194
## highway:C-city:B     -1.000000  -4.100144  2.100144 0.8788715
## city:C-highway:B    -12.666667 -15.766810 -9.566523 0.0000001
## highway:C-highway:B  -7.000000 -10.100144 -3.899856 0.0000738
## highway:C-city:C      5.666667   2.566523  8.766810 0.0005535

이 결과를 시각화하면 더 알아보기가 편하다.

twoway |>
  group_by(where, brand) |>
  summarise(ave = mean(mpg2), se = sd(mpg2) / sqrt(length(mpg2)), tstar = qt(1-0.05/2, length(mpg2)-1)) |>
  ggplot(aes(x = where, y = ave)) +
  geom_point(aes(color = brand), size = 3) +
  geom_errorbar(aes(ymin = ave -se * tstar, ymax = ave + se * tstar, color = brand), width = 0.1) + 
  ylab('Average MPG')

댓글