빅데이터 분석기사/작업 유형 3 (stats)

ANOVA 이론 및 실습

유방울 2023. 6. 10. 20:58

anova

독립변수 - 범주형

종속변수 - 연속형

으로 하는 3개 이상의 집단 평균을 비교 2개는 t검정

 

집단간분산/분단내분산 기반의 f분포를 이용해 가설 검정을 함 -> 정규성, 등분산성, 독립성을 가정

집단 간 분산, 집단 내 분산을 이용 -> 분산분석

귀무가설 기각 시 구체적인 차이를 파악하기 위해 사후검정(post hoc test)이 필요함

등분산,동일크기 표본 -> tukey검정

등분산, 다른 크기 표본 -> scheffe 검정, fisher's lsd 검정

 

분산 분석은 <그룹 사이>, <그룹내>의 분산을 분석함!!

 

일원분산분석 one-way anova 범주형 독립 변수가 한 개인 경우 사용

계절별 아이스크림 판매량 평균이 동일하다

귀무 : 모든 집단의 평균이 같다.

대립 : 하나 이상의 집단의 평균이 다르다

 

이원산분산분석 two-way ANOVA

범주형 독ㄹㅣㅂ 변수가 두 개인 경우 사용

주효과 : 각 변수로 일원분산분석한 결과 

귀무가설, 대립가설이 3개 세트

날씨 및 계절의 아이스크림 판매량에 대한 각각의 영향도와 상호작용을 확인한다

두 요인이 연속형 종속변수에 영향을 주는지 안 주는지 분석

귀무H0  : 1변수 그룹들의 평균은 동일하다

대립H1  : 1변수 그룹들의 평균은 다르다.

귀무H0  : 2변수 그룹들의 평균은 동일하다

대립H1  : 2변수 그룹들의 평균은 다르다.

귀무 H0 : 두 변수 사이의 상호작용 효과가 없다. 

대립 H0 : 두 변수 사이의 상호작용 효과가 있다. 

 

동일 평균 다른 분산의 예시

평균값은 동일 BUT 분산 값이 다름으로 전체적인 데이터의 모습이 달라보임

분산이 클수록 집단의 평균값의 차이가 무의미

집단간 평균값의 분산이 클수록 집단 내 분산이 작아질수록 평균의 차이 분명해짐

Beteen 집단간

J 집단 번호 나타냄 

집단 내 평균 - 평균의 제곱한 것을 모두 더함

 

Within 집단 내, 오차

그룹만큼 반복해서 더

j가 한 번 바뀔때마다 i는 1부터 n까지! 각각 데이터 빼기 그 데이터가 포함된 그룹의 평균을 제곱해서 누적함!

 

Total (SST = SSB + SSW)

 

c(target) : 집단간 분산 

residual : 집단내 분산

 

df : degree of freedom

c의 df : 그룹수 - 1

그룹이 3개라 3-1 = 1

residual의 df : 전ㅊㅔ 데이터 수 - 그룹 수

150 - 3 = 147

 

ANOVA 함수

way1

scipy.stats

 

way2

statsmodels.api.stats

import statsmodels.api as sm

from statsmodel.formula.api import ols 

 

ols : ordinary least squared

- 오차 제곱의 합이 최소가 되는 해를 구하는 방법을 사용하는 선형 모델

 

ANOVA를 위한 formula

value ~C(treatment) : 종속변수 ~c(독립변수)

 

일원분산분석 one-way ANOVA

독립변수 : 범주형 1개, 종속변수 : 연속형

독립변수의 변화가 종속변수에 미치는 영향을 보기 위해 사용

가정 : 독립성, 정규성, 등분산성

# [1] 데이터 가져오기
import pandas as pd

iris = pd.read_csv('bigdata/iris_data.csv')
iris.columns = ['sepal_length', 'sepal_width', 
                'petal_length', 'petal_width', 'target']
iris.columns

Index(['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'target'], dtype='object')
# 품질별 각 변수의 평균 구하기
iris.groupby('target').mean()

	sepal_length	sepal_width	petal_length	petal_width
target				
0	5.006	3.428	1.462	0.246
1	5.936	2.770	4.260	1.326
2	6.588	2.974	5.552	2.026
# [2-2] 특정 변수에 대한 품종별 평균 확인
feature = 'sepal_width'
iris.groupby('target')[feature].mean()

target
0    3.428
1    2.770
2    2.974
Name: sepal_width, dtype: float64
for x in iris.groupby('target')[feature]:
	print(x[0],x[1].values)
    
0 [3.5 3.  3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 3.7 3.4 3.  3.  4.  4.4 3.9 3.5
 3.8 3.8 3.4 3.7 3.6 3.3 3.4 3.  3.4 3.5 3.4 3.2 3.1 3.4 4.1 4.2 3.1 3.2
 3.5 3.6 3.  3.4 3.5 2.3 3.2 3.5 3.8 3.  3.8 3.2 3.7 3.3]
1 [3.2 3.2 3.1 2.3 2.8 2.8 3.3 2.4 2.9 2.7 2.  3.  2.2 2.9 2.9 3.1 3.  2.7
 2.2 2.5 3.2 2.8 2.5 2.8 2.9 3.  2.8 3.  2.9 2.6 2.4 2.4 2.7 2.7 3.  3.4
 3.1 2.3 3.  2.5 2.6 3.  2.6 2.3 2.7 3.  2.9 2.9 2.5 2.8]
2 [3.3 2.7 3.  2.9 3.  3.  2.5 2.9 2.5 3.6 3.2 2.7 3.  2.5 2.8 3.2 3.  3.8
 2.6 2.2 3.2 2.8 2.8 2.7 3.3 3.2 2.8 3.  2.8 3.  2.8 3.8 2.8 2.8 2.6 3.
 3.4 3.1 3.  3.1 3.1 3.1 2.7 3.2 3.3 3.  2.5 3.  3.4 3. ]
import matplot.pyplot as plt

data = [x[1].values for x in iris.group('target')[feature]]

plt.figure(figsize=(4,3))
plt.boxplot(data, labels=['setosa','versicolor','virginica'])
plt.show()

# 정규성 검사
from scipy.stats import shapiro
data = [x[1].values for x in iris.groupby('target')[feature]]
_, pvalue0 = shapiro(data[0])
_, pvalue1 = shapiro(data[1])
_, pvalue2 = shapiro(data[2])
print(f'{pvalue0:.4f},{pvalue1:.4f},{pvalue2:.4f}')

0.2715 0.3380 0.1809
# 등분산성 확인
from scipy.stats import bartlett
_,pvalue = bartlett(data[0],data[2],data[2])

0.3515

way 1

from scipy.stats import f_oneway
# way 1
#F, pvalue = f_oneway(data[0],data[1],data[2])

# 인덱스 내부의 것들을 제외함!
F, pvalue = f_oneway(*data)
print(f'{F:.1f},{pvalue:.5f}')
print('pvalue 작으므로 유의미한 차이있음' if pvalue <0.05 else '유의미한 차이없음')

#if pvalue < 0.05:
#    print('P-value 값이 충분히 작음으로 인해 \
#그룹의 평균값이 통계적으로 유의미한 차이가 있음')

way 2

import statsmodels.spi as sm
from statsmodels.formula.api as ols
data = [iris.x[1] for x in iris.groupby('target')[feature]] 
lm = ols('sepal_width ~ C(target)', data).fit()
result = sm.stats.anova_lm(lm)
print(result)
              df     sum_sq   mean_sq         F        PR(>F)
C(target)    2.0  11.344933  5.672467  49.16004  4.492017e-17
Residual   147.0  16.962000  0.115388       NaN           NaN