[Alex] 데이터 장인의 블로그

데이터 분석을 위한 통계(카이스퀘어 검정) feat. python 본문

Statistic

데이터 분석을 위한 통계(카이스퀘어 검정) feat. python

Alex, Yoon 2020. 5. 26. 23:55

카이스퀘어 검정, 쉽게 기억하자.

카이스퀘어 검정은 카이 제곱 분포에 기초한 통계분석 방법입니다. 관찰된 '빈도'수가 기대되는 값, 즉 기댓값과 얼마나 다른지 확인함으로써 '범주형 변수'들의 관계 유무를 파악합니다. 

 

두 변수의 관계가 있는가? 없는가? 


카이제곱검정은 일어난 사건이 '통계적으로' 일어날 만한 차이인지, 희귀한 경우인지 통계적으로 파악하는데 사용합니다. 변수 관계의 유무만 확인할 수 있기 때문에 어떤 관계가 있는지는 상관분석, 회귀분석 등 추가적인 분석을 통해 알 수 있습니다. 횟수 관련 데이터, 빈도 관련 데이터를 분석할 때, 자주 사용되는 통계분석 방법입니다. 

분할표

분할표 or 빈도표 or 집계표

예를 들어보겠습니다. 횟수관련 데이터, 빈도관련 데이터 등을 보여주는 분할표를 통해 100명의 환자 상태를 표현합니다. 카이스퀘어 검정은 항상 분할표(Contingency table)와 함께합니다. 분할표란, 위의 표처럼 범주형 변수간의 빈도를 계산한 표입니다.  


기댓값

카이제곱 검정에서는 각 변수의 값이 독립적이라고 가정합니다. 때문에 전체 비율에 따라 동일한 결과가 나타날 것이라 생각하게 됩니다. 전체 환자 구성 비율을 통해 각각의 범주에 해당하는 환자 수를 구하게 되고, 이를 기댓값이라 표현합니다. 카이스퀘어 값은 방금 산출한 기대값과 실제값의 차이를 통해 계산합니다. 

카이스퀘어 값을 구해주었다면, 자유도를 활용하여 확률 분포를 결정해줍니다. 자유도를 통해 결정한 분포 그래프에서 어느 정도의 확률에 해당하는지, 이를 통해 얼마나 통계적으로 유의미한 결과가 나타난 건지 확인합니다. 


자유도

위의 예시에서 자유도는 열변수, 행 변수의 값이 각각 2개이므로 (2-1) x (2-1) = 1로 계산됩니다. 만약 아래의 분할표처럼 비만, 정상 체중의 열변수를 비만, 정상체중, 저체중으로 3개로 나누어준다면

분할표(Contingency table)의  모양은 2(행 수), 3(열 수)가 되기 때문에 자유도는 이에 따라 (2-1) x (3-1) = 2 가 됩니다. 

 

출처: 위키백과

자유도에 따라 카이스퀘어 분포의 모양은 달라집니다. 위 검정에서는 자유도의 값이 1이었기 때문에 검은색 선에서 카이스퀘어 값을 비교하게 됩니다. 

자유도에 의한 그래프 변화를 파이썬 스크립트와 함께 살펴보겠습니다. 

출처: http://박선생님의 블로그

from numpy import linspace
from scipy.stats import chi2

df = 1          # 자유도
x = linspace(0, 20, 50)
y = chi2(df).pdf(x)

plt.figure(figsize=(10, 6))
plt.plot(x, y, 'b--')

자유도 1의 카이스퀘어 그래프

df = 4          # 자유도
x = linspace(0, 20, 50)
y = chi2(df).pdf(x)

plt.figure(figsize=(10, 6))
plt.plot(x, y, 'b--')

자유도 4의 카이스퀘어 그래프

자유도에 따라서 카이스퀘어 분포가 변화하는 것을 살펴볼 수 있습니다. 자유도가 증가할수록 카이스퀘어 분포는 정규분포에 가까워 집니다. 

실제 데이터를 활용하여 카이스퀘어 분석을 진행해보겠습니다. 

data_chi.xlsx
0.01MB

1. 데이터를 불러온 이후 표로 정리합니다. 

import pandas as pd
import numpy as np
from scipy.stats import chi2_contingency

data = pd.read_excel("data_chi.xlsx")
data

contingency = pd.crosstab(data.iloc[:,1],data.iloc[:,2])
contingency

2. scipy 모듈을 사용하여 결과값을 산출합니다. 

chi, p, dof, expected = chi2_contingency(contingency)

print(f"chi 스퀘어 값: {chi}",
      f"p-value (0.05): {p}",
      f"자유도 수: {dof}",
      f"기대값: \n{pd.DataFrame(expected)}",
      f"측정값: \n{contingency}", sep = "\n" )

p-value 가 유의수준(0.05)보다 높기 때문에 귀무가설을 기각하지 못합니다. 즉, 당뇨와 비만 사이의 관계는 '없다'라고 결론내리게 됩니다. 

3. 카이스퀘어 값이 그래프 어디쯤 위치해있는지 확인해보겠습니다. 

df = 1          # 자유도
x = linspace(0, 20, 50)
y = chi2(df).pdf(x)

plt.figure(figsize=(10, 6))
plt.plot(x, y, 'b--')

plt.axvline(x=x95, color='black', linestyle=':')
plt.text(x95, .4, 'critical value\n=' + str(round(x95, 4)), 
         horizontalalignment='left', color='b')

plt.axvline(x=chi, color='r', linestyle=':')
plt.text(chi, .4, 'statistic\n' + str(round(chi, 4)), 
         horizontalalignment='left', color='b')

plt.xlabel('X')
plt.ylabel('P(X)')
plt.grid()
plt.title(r'$\chi^2$ Distribution (df = 1)')
plt.show()

그래프로 확인하여도 위의 결과(통계량)과 임계치(critical value) 왼쪽에 위치해있습니다. 이로써 위의 가정(비만과 당뇨 사이에 관계가 있다)의 귀무가설은 기각하지 못합니다. 

카이스퀘어 검정을 진행할때 주의해야 할 점이 있습니다. 

4셀 (2행 X 2행)의 소표본인 경우, p값이 원래보다 작아져 제 1종 과오를 과소평가해 버리는 경향이 있습니다. 때문에 검정통계량을 애초에 좀 작게 보정해두는 방법을 사용할 수 있습니다. : 예이츠의 연속성 보정. 

 


피셔의 정확검정

만약 사건 발생 수, 빈도 수가 극히 적거나(특히 5개 이하의 빈도가 전체 셀 중 20%이상 존재하는 경우) 서로의 빈도 수의 차이가 많이나는 경우에는 카이제곱 검정의 정확도는 낮아집니다. 이때 필요한 검정이 바로 '피셔의 정확검정'입니다. 

예시로 살펴보겠습니다. 

import pandas as pd
import numpy as np
import scipy.stats as stats
data = pd.DataFrame([[1, 6], [5, 2]])
data.columns = ['가짜 약','진짜 약']
data.index = ['효과있음', '효과없음']
data

oddsratio, pvalue = stats.fisher_exact(data)
print("oddratio:", oddsratio, "\n"
        "p-value:", pvalue )

검정 결과, 진짜 약의 유효성은 확인할 수 없었습니다. 

+ ) 같은 데이터로 R의 검정결과와 비교해보니 oddratio 값이 서로 다르다는 것을 확인하였습니다. 피셔의 정확검정에서는 p-value 값을 주로 확인하여 분석에 사용한다고하니 이점 참고하시면 좋겠습니다! 

반응형
Comments