Tomato [R_tidyverse] 분산분석 ANOVA: 일원분산분석 one-way ANOVA ①

새소식

Programs/R

[R_tidyverse] 분산분석 ANOVA: 일원분산분석 one-way ANOVA ①

  • -

 분산분석 ANOVA

  • 통계분석의 종류는 목적에 따라 크게 (그룹 간) 차이검정, (변수 간) 관계검정으로 나눌 수 있음. 이 중 그룹 간 차이를 검정하는 방법으로는 t-검정과 분산분석(ANOVA)이 있는데, t-검정은 그룹이 1~2개일 때 사용되며, ANOVA는 그룹이 3개 이상일 때 사용함.
  • 분산분석은 이름에서 알 수 있듯이 데이터의 분산, 즉 데이터가 얼마나 퍼져있는지를 분석하는 방법임. 이를 통해 여러 그룹 간의 평균이 통계적으로 유의미하게 차이가 있는지를 판단함.
  • 분산분석의 주요 가정은 정규성, 독립성, 등분산성임. 정규성은 각 그룹의 데이터가 정규분포를 따르는지, 독립성은 각 그룹의 데이터가 서로 독립적인지, 등분산성은 각 그룹의 데이터가 동일한 분산을 가지는지를 가정함.

 

  • 분산분석의 종류
일원분산분석 
One-way ANOVA
1개의 독립변수가 있는 경우, 독립변수의 각 수준(그룹)간의 평균 차이를 검정
반복측정분산분석
Repeated Measures ANOVA
1개의 독립변수와 반복 측정된 종속변수가 있는 경우, 독립변수의 각 수준(그룹)간의 평균 차이와 시간에 따른 변화를 검정
이원분산분석 
Two-way ANOVA
2개의 독립변수가 있는 경우, 독립변수들의 각 수준(그룹)간의 평균 차이를 검정하며, 또한 독립변수들 간의 상호작용 효과를 검정
이원반복측정분산분석
Two-way Repeated Measures ANOVA
2개의 독립변수와 반복 측정된 종속변수가 있는 경우, 독립변수들의 각 수준(그룹)간의 평균 차이, 두 독립변수의 상호작용 효과, 그리고 시간에 따른 변화를 검정

 

 

 

 

 

 일원분산분석 one-way ANOVA 실습

*tidyverse 패키지를 활용한 분석방법

  • 일원분산분석 one-way ANOVA는 지난번 실습한 독립표본 t-검정의 확장이라고 보면 된다.
  • 각기 다른 그룹의 데이터를 가져와서 비교하기 때문에 등분산 검정해야 함!
  • t-검정과 달리 ANOVA는 3개 이상의 그룹에 대해 차이검정을 실시한다.
  • 물론 2그룹씩 짝지어 여러번 t-tes를 진행할 수 있지만, 신뢰구간의 문제로 인해 1종 오류를 범할 확률이 증가한다.
오늘 실습할 문제는 한 프랜차이즈 카페에서 4개 지점(강남, 강서, 강동, 강북) 간 고객만족도 차이가 있는지, 어디가 가장 안좋은지를 확인하고자하는 상황이다.
귀무가설: 네 지점 간 고객만족도에 차이가 없다/   대체가설: 어느 한 지점이라도 차이가 있다.
  • 4개 집단 간 하나의 점수를 놓고 비교하기 때문에 일원분산분석을 실시한다.
  • 평균과 각 그룹의 점수를 비교하는데 평균으로부터 얼마나 흩어져 있는지, 즉 분산을 활용하여 차이검정한다.
  • 그룹 내의 변동성과 그룹 간의 변동성을 비교하여 후자가 충분히 크다면 그룹 간 차이가 있다고 간주한다.

 

 

 

 

 

차례

1.  패키지 설치 및 불러오기
2. 데이터 불러오기, 기술통계, 그래프그리기
3.  이상치 제거
4.  샤피로 테스트: 정규분포 검정
5.  등분산 검정
6.  그룹 간 차이검정: F값 검정
7.  사후검정: 다중비교
8.  사후검정: 서브그룹 묶어 표현하는 법

 

 

 

 1. 패키지 설치 및 불러오기

오늘의 실습을 위해 필요한 R 패키지. 패키지는 한 번 설치하면 다음에 다시 설치할 필요 없음.

그러나 라이브러리는 매번 불러와야 함!

# 패키지 설치
install.packages("tidyverse") #쌍따옴표 주의
install.packages("tidymodels")
install.packages("rstatix")
install.packages("rskim")
install.packages("AlgDesign")
install.packages("agricolae")

#설치한 패키지 불러오기 (라이브러리)
library(tidyverse) #쌍따옴표 없음
library(tidymodels)
library(rstatix)
library(rskim)
library(AlgDesign)
library(agricolae)

 

 

 

 

 2. 데이터 불러오기, 기술통계, 그래프 그리기

# 데이터 불러오기
owa_tb <- read_csv("08.owa.csv",
                   col_names = T,
                   na = ".",
                   locale = locale("ko", encoding = "euc-kr")) %>%
  mutate_if(is.character, as.factor) %>%
  mutate(매장명 = factor(매장명,
                         levels = c(1:4),
                         labels = c("강남","강서","강동","강북")))
# 기술통계
str(owa_tb)
owa_tb
skim(owa_tb)

## 그룹쪼개서 확인해보기
owa_tb %>%
  group_by(매장명) %>%
  get_summary_stats(만족도)
# 그래프 그리기
## box-plot과 histogram을 그려서 데이터의 이상치와 분포 확인하기
owa_tb %>%
  ggplot(mapping = aes(x = 매장명,
                       y = 만족도)) +
  geom_boxplot() 

owa_tb %>%
  ggplot(mapping = aes(x = 만족도)) +
  geom_histogram(bins = 10,
                 color = "white",
                 fill = "steelblue") +
  facet_wrap(~매장명)

 

 

 

 

 

 3. 이상치 제거

통계분석을 위해 분포에서 벗어나는 극단적인 값, 이상치를 제거해야 함. identify_outliers() 함수를 활용하면 간단히 파악 가능.

박스플랏에 나타나지 않았던 이상치가 나타나기도 함.

# 각각의 그룹을 나누어서 이상치 확인
owa_tb %>%
  group_by(매장명) %>%
  identify_outliers(만족도)

이상치 없으니 넘어감!

 

 

 

 

 

 

 4. 샤피로 테스트: 정규분포검정

  • 통계분석은 데이터의 분포가 정규분포일 것을 가정하고 이루어짐. 따라서 통계분석을 위해서는 이 데이터의 분포가 정규분포를 따르는지 검정해보아야 함.
  • 그럴때 사용되는 것이 샤피로 테스트. 샤피로 테스트의 귀무가설은 '이 데이터의 분포가 정규분포를 따른다'는 것이고, 반대되는 대체가설은 '정규분포를 따르지 않는다' 가 됨. 샤피로 테스트의 p밸류 값이 0.05 이상이라면 귀무가설이 채택되면서 정규분포를 따른다고 볼 수 있음
  • shapiro_test() 함수를 활용하면 됨
  • 독립표본 t-검정에서는 각각의 그룹에 대해 확인해야 함
owa_tb %>%
  group_by(매장명) %>%
  shapiro_test(만족도)

위의 코드 입력 결과 아래와 같이 출력됨. 다 p밸류 0.05 이상이기 때문에 귀무가설이 채택됨. 즉, 이 데이터의 분포가 정규분포라고 받아들일 수 있음

# A tibble: 4 × 4
  매장명 variable statistic     p
  <fct>  <chr>        <dbl> <dbl>
1 강남   만족도       0.956 0.137
2 강서   만족도       0.957 0.231
3 강동   만족도       0.959 0.299
4 강북   만족도       0.973 0.454

 

 

 

 

 

 

 5. 등분산검정

서로 다른 그룹을 가져와서 차이검정하기 때문에 등분산검정 필요
levene test 시행: 귀무가설은 “두 그룹간 분산의 동질성이 있다”

owa_tb %>%
  levene_test(만족도 ~ 매장명) # 그룹 간 분포의 동질성 보기 때문에 group_by 필요없음

p값 0.05 이상 → 귀무가설 채택 → “그룹간 분산의 동질성이 있다" → 등분산!

# A tibble: 1 × 4
    df1   df2 statistic     p
  <int> <int>     <dbl> <dbl>
1     3   135      1.06 0.369

 

 

 

 

 

 

 6. 그룹 간 차이검정: F값 검정

이제 4개의 지점 간 만족도 점수에 차이가 있는지 없는지를 보고자 함. 아래의 코드 실행하여 ANOVA 테스트.

owa_tb %>%
  anova_test(만족도 ~ 매장명) # p값 극히 작다 -> 귀무가설 기각 "차이가 있다"

# 더 디테일한 정보가 필요하다면
owa_results <- aov(만족도 ~ 매장명,
                   data = owa_tb)
tidy(owa_results)

귀무가설이 기각되면서 ‘그룹 간 차이가 있다.’ 로 간주됨.

그럼 그룹 간에 어떤 차이가 있는지 사후검정(다중비교) 해야함.

 

 

 

 

 

 

 7. 사후검정: 다중비교

이제 어느 그룹이 차이가 있는지 보기 위해 각 그룹 둘씩 짝지어서 확인해야 함.

보정된 t-test 실시(본페르니, 피셔, 튜키 등의 보정사용) → pairwise t-test

각각의 보정방법에 따라 결과는 조금씩 달라질 수 있음

# 1. Fisher LSD
owa_tb %>%
  pairwise_t_test(formula = 만족도 ~ 매장명, # formula 써도되고 안써도 되고
                  p.adj = "non") 

## 결과
  .y.    group1 group2    n1    n2           p p.signif     p.adj p.adj.signif
* <chr>  <chr>  <chr>  <int> <int>       <dbl> <chr>        <dbl> <chr>       
1 만족도 강남   강서      38    32 0.376       ns         3.76e-1 ns          
2 만족도 강남   강동      38    30 0.000000547 ****       5.47e-7 ****        
3 만족도 강서   강동      32    30 0.0000448   ****       4.48e-5 ****        
4 만족도 강남   강북      38    39 0.00179     **         1.79e-3 **          
5 만족도 강서   강북      32    39 0.0331      *          3.31e-2 *           
6 만족도 강동   강북      30    39 0.023       *          2.3 e-2 *     

### 강남-강동, 강서-강동 큰 차이
# 2. 본페로니
owa_tb %>%
  pairwise_t_test(formula = 만족도 ~ 매장명,
                  p.adj = "bonferroni") 

## 결과
  .y.    group1 group2    n1    n2           p p.signif     p.adj p.adj.signif
* <chr>  <chr>  <chr>  <int> <int>       <dbl> <chr>        <dbl> <chr>       
1 만족도 강남   강서      38    32 0.376       ns         1   e+0 ns          
2 만족도 강남   강동      38    30 0.000000547 ****       3.28e-6 ****        
3 만족도 강서   강동      32    30 0.0000448   ****       2.69e-4 ***         
4 만족도 강남   강북      38    39 0.00179     **         1.07e-2 *           
5 만족도 강서   강북      32    39 0.0331      *          1.99e-1 ns          
6 만족도 강동   강북      30    39 0.023       *          1.38e-1 ns   

### 강남-강동, 강서-강동 큰 차이
#3. 튜키
owa_results %>%
  TukeyHSD() %>% 
  tidy()


## 결과
  term   contrast  null.value estimate conf.low conf.high adj.p.value
  <chr>  <chr>          <dbl>    <dbl>    <dbl>     <dbl>       <dbl>
1 매장명 강서-강남          0    -1.01   -3.98      1.95   0.811     
2 매장명 강동-강남          0    -6.11   -9.12     -3.09   0.00000325
3 매장명 강북-강남          0    -3.45   -6.27     -0.634  0.00956   
4 매장명 강동-강서          0    -5.09   -8.23     -1.95   0.000259  
5 매장명 강북-강서          0    -2.44   -5.39      0.508  0.142     
6 매장명 강북-강동          0     2.65   -0.348     5.66   0.103  

### 강동-강남, 강북-강남, 강동-강서 큰 차이

 

 

 

 

 

 

 

 

 8. 사후검정: 서브그룹 묶어 표현하는 법

비교적 동질한 그룹끼리 묶어 표현하는 방법이 있음. (LSD, duncan, schffe 등 활용 가능)

따로 아래의 패키지를 활용해야함

# 패키지 설치 및 라이브러리 불러오기
install.packages("AlgDesign")
install.packages("agricolae")
library(AlgDesign)
library(agricolae)
# 1.
owa_results %>%
  LSD.test("매장명",
           group = T,
           console = T) 

## 결과
       만족도 groups 
강남 90.60526      a
강서 89.59375      a
강북 87.15385      b
강동 84.50000      c

### a -강남, 강서(두 그룹 비교적 동질)/ b - 강북/ c - 강동
# 2.
owa_results %>%
  duncan.test("매장명",
              group = T,
              console = T)

## 결과
      만족도 groups
강남 90.60526      a
강서 89.59375      a
강북 87.15385      b
강동 84.50000      c

### a -강남, 강서(두 그룹 비교적 동질)/ b - 강북/ c - 강동
# 3.
owa_results %>%
  scheffe.test("매장명",
               group = T,
               console = T)

## 결과
 만족도 groups
강남 90.60526      a
강서 89.59375     ab
강북 87.15385     bc
강동 84.50000      c

 

 

 

 

 

 

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.