본문 바로가기
데이터분석-통계/통계학의 코드 구현

평균치(t) 검정 t test 구현 [One, Two, Paired Samples t-test : Python feat. SciPy & Statsmodels]

by TayLee 2024. 11. 5.
반응형

 

글의 목차
  1. Python생태계의 통계 Library
  2. SciPy, Statsmodels의 차이점
  3. SciPy에서의 평균치 검정(t-test) 사용법 (feat 이론편의 예시 그대로 구현)
    1. One sample t-test
    2. Two samples t-test (Student's & Welch's t-test)
    3. Paired samples t-test

 

 

이번 포스팅에서는 Python으로 직접 평균치 검정을 수행해볼까 합니다. 만약 평균치 검정 이론에 대한 이해가 필요하시다면,  앞선 포스팅을 보고오시길 바랍니다.

 

평균치 검정 : t검정 [One, Two(Student's & Welch's), Paired Samples t-test]

글의 목차평균치 검정의 당위성 (왜 필요한가? feat 불확실성/변동성)평균치 검정에 대한 정의 및 이해 평균치 검정에 대한 가정 (정규성, 등분산성:Two Samples t-test)평균치 검정의 종류 및 실제 계

taehyuklee.tistory.com

 

 

1. Python 생태계의 통계 라이브러리

 Python 생태계에서 통계 분석을 위한 대표적인 라이브러리로는 SciPystatsmodels가 있으며, 머신러닝 분야에서는 scikit-learn이 널리 사용된다. 이번에는 통계 분석 라이브러리로 SciPy를 주로 활용할 계획이지만, statsmodels의 특징도 함께 언급하고 넘어가고자 한다.

 

 

2. SciPy와 Statsmodels 라이브러리의 차이점

SciPy - Library

# Python Package Manger
pip install scipy
 

ttest_ind — SciPy v1.14.1 Manual

>>> import numpy as np >>> from scipy import stats >>> rng = np.random.default_rng() Test with sample with identical means: >>> rvs1 = stats.norm.rvs(loc=5, scale=10, size=500, random_state=rng) >>> rvs2 = stats.norm.rvs(loc=5, scale=10, size=500, random_s

docs.scipy.org

 

statsmodels - Library

# Python Package Manger
pip install statsmodels
 

statsmodels.stats.weightstats.ttest_ind - statsmodels 0.14.4

statsmodels.stats.weightstats.ttest_ind statsmodels.stats.weightstats.ttest_ind(x1, x2, alternative='two-sided', usevar='pooled', weights=(None, None), value=0)[source] ttest independent sample Convenience function that uses the classes and throws away the

www.statsmodels.org

 

두 Library모두 사용해본 결과 다음과 같이 요약할 수 있을 것 같다. 

 

  • SciPy : p-value와 기본 통계량을 빠르게 산출하는 데 최적화되어 있으며, 대용량 데이터를 처리할때나, 빠른 판단이 필요한 경우 간단한 통계 계산을 수행하는 데 많이 사용된다.

 t-test는 결과 값에 있어 큰 차이 없어서, 선형 회귀 분석을 예시로 출력 차이를 보고자 한다.

# Scipy 출력
Slope: -1.7
Intercept: 86.16666666666667
R-squared: 0.12690281030444972
P-value: 0.19248793653349897

 

  • Statsmodels : 통계 모델의 진단과 평가에 필요한 다양한 기능을 제공한다. 예를 들어 선형 회귀분석 후 각 변수의 검정통계량 (t-값), 모델의 검정통계량 (F-값), 모델 성능 지표 (결정계수 R-squared) 등을 포함한 상세한 통계량을 제공한다. 다양한 지표들을 통해 통계 모델을 해석하고 검증하는 데 활용할 수 있다.

 

Statsmodels로 선형회귀로 할 경우는 다음과 같은 출력이 나온다

# Statsmodels 기준의 출력
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                 scores   R-squared:                       0.127
Model:                            OLS   Adj. R-squared:                  0.060
Method:                 Least Squares   F-statistic:                     1.890
Date:                Mon, 04 Nov 2024   Prob (F-statistic):              0.192
Time:                        00:20:44   Log-Likelihood:                -40.667
No. Observations:                  15   AIC:                             85.33
Df Residuals:                      13   BIC:                             86.75
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const         86.1667      1.597     53.969      0.000      82.717      89.616
group_code    -1.7000      1.237     -1.375      0.192      -4.372       0.972
==============================================================================
Omnibus:                        1.370   Durbin-Watson:                   0.739
Prob(Omnibus):                  0.504   Jarque-Bera (JB):                0.911
Skew:                          -0.272   Prob(JB):                        0.634
Kurtosis:                       1.922   Cond. No.                         2.92
==============================================================================

 

 정리하자면, 빠른 판단이 필요하고 p-value 및 검정 통계량(statistics)을 신속하게 산출하고자 한다면 SciPy를 이용하는 것이 적합해 보인다. 반면, 보다 정밀한 검증과 모델 진단이 필요하다면 Statsmodels를 사용하는 것이 좋을 거라 생각한다.

 

 


3. SciPy를 이용한 평균치 검정 (t-test)

 예시에 대한 일관성을 가져가기 위해 앞서 포스팅했던 t-test이론 편에서의 예제를 그대로 가져오도록 하겠습니다. 앞에서 손으로 직접 계산한 검정통계량 (t-value)와 p-value가 일치하는지 확인해 보시길 바랍니다.

 

 

3.1 One sample t-test (일 표본 t-test)

[Table1. 환자 번호 & 약물 투여 후 측정된 혈압]

환자 리스트 투약 후 혈압 (mm Hg)
환자1 118
환자2 121
환자3 119
환자4 117
환자5 120

이 집단의 평균 혈압이 기준 혈압(120mm Hg)과 유의미하게 다른지 검정한다.

 

 

[Python SciPy One sample t-test 사용법]

# scipy.stats에서 ttest_1samp method 사용
from scipy import stats
import numpy as np

x1 = np.array([118, 121, 119, 117, 120])
mu0 = 120.0  # 비교할 평균값
result = stats.ttest_1samp(x1, popmean=mu0, alternative=alternative, axis=0)
# 결과 Result (t 검정통계량, p-value)
TtestResult(statistic=np.float64(-1.414213562373095), pvalue=np.float64(0.23019964108049873), df=np.int64(4))

 

일표본 t-test의 경우 scipy.stats 안에 존재한다. method명은 ttest_1samp 이다. (공식 문서 기준)

 

위치 인자

첫 번째 인자 (x1): 내가 검정할 표본을 넣게 된다. Python List를 넣어도 상관없고, Pandas에서 Slice해서 넣어도 상관 없다. 내부적으로 numpy로 변환하는 듯 해보인다. (공식문서 기준) 되도록이면, numpy로 넣어주도록 하자.

 

기본인자 (공식문서 순서만 지키면 위치 인자로도 사용 가능)

popmean = {popmean 인자}

 임의로 'mu0'라고 넣었지만, 해당 인자에는 내가 기대하는 평균값을 넣게 된다. 위의 예시에서는 '120'을 넣었다.

 

alternative = {alternative-인자 : str type}

  1. "two-sided" : 양측 검정 : 귀무가설 : 표본 평균 != ref_avg (기준 평균) (default)
  2. "less" 단측 검정 (좌측) : 귀무가설 : 표본 평균 < ref_avg (기준 평균)
  3. "greater" 단측 검정 (우측) : 귀무가설 : 표본 평균 > ref_avg (기준 평균)

axis = {axis - 인자 : int type}

  1. 0 : 0으로 세팅하게 되면 을 기준으로 읽게 된다 (default)
  2. 1 : 1로 세팅하게 되면 을 기준으로 읽게 된다 (2D Matrix일때 사용)
  3. None : ravled (평탄화) 2차원을 1차원으로 만들어서 검정에 들어갑니다.
from scipy import stats
import numpy as np

# 인자 axis에 따른 결과 예시
arr = np.array([[1.5, 2.3, 3.7],
                [4.1, 5.2, 6.8],
                [7.4, 8.5, 9.1],
                [10.2, 11.4, 12.9],
                [13.3, 14.1, 15.6]])
                
mu0 = 5  

'''
참고로 위의 예제에서는 result 객체로 그냥 print했지만, 
unpack으로 검정통계량, p-value로 분할하여 return이 가능하다.
'''
t_stat, p_value = stats.ttest_1samp(arr, popmean=mu0, axis=0)
t_stat, p_value = stats.ttest_1samp(arr, popmean=mu0, axis=1)
t_stat_axis1, p_value_axis1 = stats.ttest_1samp(arr, popmean=mu, axis=None)
# 각 각에 대한 결과
# axis = 0 일때의 결과 (열 기준으로 3개의 값이 나오는 것을 확인 가능)
T-statistic: [1.09461774 1.56522962 2.1804585 ]
P-value: [0.33517446 0.19258282 0.09469596]


# axis = 1 일때의 결과 (행 기준으로 5개의 값이 나오는 것을 확인 가능)
T-statistic: [-3.88856886  0.46776758  6.6964953   8.3223972  13.84510894]
P-value: [0.06022121 0.68597053 0.02158075 0.01413253 0.00517637]


# axis = None 일때의 결과 (모두 1차원으로 만들어 1개의 값이 나오는 것을 확인 가능)
T-statistic: 2.947475125290377
P-value: 0.010598724800782978

 

위의 코드 조각에서 axis옵션에 따른 결과가 어떻게 달라지는지 확인해 보았다.

 

  그 외에 nan_policy 등과 같이 NaN값을 어떻게 처리할지에 대한 것이 있지만, 이 부분은 통계와는 큰 관계없는 Option이므로 넘어가도록 한다.

 

 

 

3.2 Two samples t-test (독립 표본 t-test)

[Table2. 환자 번호, 집단 분류 & 약물 복용 여부측정된 혈압]

환자 리스트 집단 분류 투약 후 혈압 (mm Hg)
환자1 복용 115
환자2 복용 118
환자3 복용 116
환자4 미복용 122
환자5 미복용 124

약물을 복용한 집단과 미복용 집단의 평균 혈압이 유의미하게 다른지 검정한다. (두 집단의 표본수가 꼭 같을 필요는 없다)

 

 

3.2.1 Student's t-test

[Python SciPy Student's t-test 사용법]

from scipy import stats
import numpy as np

x1 = np.array([115, 118, 116])  # 복용 집단
x2 = np.array([122, 124])       # 미복용 집단

t_stat, p_val = stats.ttest_ind(x1, x2, equal_var=True, alternative=alternative)
# Result - Student's t-test 결과 equal_var = True 일때 
T-statistic: -4.898979485566359
P-value: 0.016276603459428517

독립 표본 t-test의 경우 scipy.stats 안에 존재하며, method명은 ttest_ind이다. (공식 문서)

 

위치 인자

 첫 번째 인자(x1) /  두 번째 인자(x2) : 첫 번째 표본, 두 번째 표본에 해당되며, 검정 통계량의 분자 항 E[X1] - E[X2] 에 대응된다고 생각하면 된다.

 

기본인자 (공식문서 순서만 지키면 위치 인자로도 사용 가능)

eqaul_var = {equal_var-인자 : bool type}

  1. "True" : X1, X2 표본 집단에 대한 등분산성 가정이 충족 된다.
  2. "False" : X1, X2 표본 집단에 대한 등분산성 가정이 충족 되지 않는다. (자동으로 Welch's t-test로 넘어감)

alternative = {alternative-인자 : str type}

  1. "two-sided" : 양측 검정 : 귀무가설 : 표본1 평균 != 표본2 평균 (해당 인자가 default 로 되어 있다)
  2. "less" 단측 검정 (좌측) : 귀무가설 : 표본1 평균 < 표본2 평균
  3. "greater" 단측 검정 (우측) : 귀무가설 : 표본1 평균 > 표본2 평균

axis = {axis - 인자 : int type}

  1. 0 : 0으로 세팅하게 되면 을 기준으로 읽게 된다 (default)
  2. 1 : 1로 세팅하게 되면 을 기준으로 읽게 된다 (2D Matrix일때 사용)
  3. None : 2차원을 1차원으로 변환하여 검정에 들어간다. (위에서 했기 때문에 생략한다)
data = np.array([[115, 118, 116],  
                 [122, 124, 123]]) 

data1 = np.array([[231, 123, 132],  
                 [223, 321, 421]])

# 1. axis=0 (열 기준)
t_stat_axis0, p_val_axis0 = stats.ttest_ind(data, data1, axis=0, equal_var=True)

# 2. axis=1 (행 기준)
t_stat_axis1, p_val_axis1 = stats.ttest_ind(data, data1, axis=1, equal_var=True)
# axis에 따른 결과 
# axis=0 
T-statistic: [-20.41364284  -1.01973393  -1.08618662]
P-value: [0.00239111 0.41512875 0.39087777]

# axis=1
T-statistic: [-1.31950545 -3.47552886]
P-value: [0.25745718 0.02545524]

 

 

3.2.2 Welch's t-test

[Python SciPy Welch's t-test 사용법]

from scipy import stats
import numpy as np

x1 = np.array([115, 118, 116])  # 복용 집단
x2 = np.array([122, 124])       # 미복용 집단

t_stat, p_val = stats.ttest_ind(x1, x2, equal_var=False, alternative=alternative)
# Result - Welch's t-test 결과 equal_var = False 일때 
T-statistic: -5.0000000000000036
P-value: 0.025054956171761823

 

 Student's t-test랑 mehotd는 같지만, equal_var 옵션을 False로 함으로써 사용할 수 있는 검정 기법이다. (등분산성 가정을 충족하지 못할때)

fig. official docs
출처: 공식문서 ttest_ind

 

 나머지 인자들은 Student's t-test 인자랑 똑같으므로, 위의 

 

 

 

3.3 Paired Samples t-test (대응 표본 t-test)

[Table3. 환자 번호 & 약물 투여 전/후 혈압]

환자 리스트 투약 전 혈압 (mm Hg) 투약 후 혈압 (mm Hg)
환자1 130 120
환자2 128 119
환자3 135 125
환자4 132 123
환자5 129 121

약물 투여 전후의 평균 혈압 차이가 유의미하게 감소했는지 검정한다. 

 

이론편에서는 유의미하게 같은지를 확인했지만, 이번에는 유의미하게 감소했는지를 검정해보도록 한다. 

 

[Python SciPy Paired Samples t-test 사용법]

# 투약 전 혈압 데이터 (data)
data = np.array([130, 128, 135, 132, 129]) 

# 투약 후 혈압 데이터 (data1)
data1 = np.array([120, 119, 125, 123, 121])

# 대응 표본 t-검정 수행
t_stat, p_val = stats.ttest_rel(data, data1, alternative='less')  # 'less'는 감소했는지를 검정
# Result
T-statistic: 24.58803425594304
P-value: 0.9999918819424217

대응 표본 t-test의 경우 scipy.stats 안에 존재하며, method명은 ttest_rel이다. (공식 문서)

 유의수준을 0.05로 한다고 했을때 이미, 0.9999이므로 귀무가설을 채택한다. 즉, 약효과에 의해 혈압이 유의미하게 감소하였음을 알 수 있다. 나머지 axis, alternative 등의 인자들은 위에서 설명했으므로, 생략하도록 한다.

 

*단, Paired Samples t-test의 경우는 양쪽 데이터 쌍의 개수가 일치해야 한다. 일치하지 않을 경우 ValueError가 발생한다.

ValueError: unequal length arrays

 

 

결론 맺음말

 이번에는 앞서 이론으로 알아보았던, 평균치 검정에 대해서 SciPy Library를 이용해서 구현하는 방법을 알아보았습니다. 앞서 이론 파트에서 직접 손으로 계산했던 t-통계량, p-value과 Python으로 구현한 값과 비교했을때 일치했음을 알 수 있었습니다. 이 부분들을 직접 손으로 계산도 해보고 구현해보길 바랍니다.

 

참고 자료

  1. Scipy 공식문서
  2. Statsmodels 공식 문서
  3. 자료분석개론 학교 수업 (전공 수업)
반응형