Python 통계 - T검정 예제
Page content
강의 홍보
- 취준생을 위한 강의를 제작하였습니다.
- 본 블로그를 통해서 강의를 수강하신 분은 게시글 제목과 링크를 수강하여 인프런 메시지를 통해 보내주시기를 바랍니다.
스타벅스 아이스 아메리카노를 선물
로 보내드리겠습니다.
- [비전공자 대환영] 제로베이스도 쉽게 입문하는 파이썬 데이터 분석 - 캐글입문기
통계분석을 활용한 문제해결 과정
- 비즈니스에서 통계는 그저 툴이다.
- 통계를 몰라도 물건을 파는데 전혀 문제가 없다.
- 통계는 객관적인 근거를 확보하여 유효한 의사결정을 내리기 위한 그저 도구
(Tool)
이다. - 따라서, 마케팅이나 CRM과 같은 경영이슈에서도 통계는 문제해결을 이한 체계적인 절차를 제공한다.
- 문제정의
- 가설수립 및 분석방법 설정
- 유의수준 및 임계치 설정
- 분석 및 검정 통계량 산출
- 결과 해석 및 가설 검증
예제를 활용한 통계분석 예제
- 데이터 분석에서 가장 자주 사용되는 통계 기법 중의 하나는
t-검정
이다. - 처음
t-검정
을 배울 때는 비슷한 용어들이 많아서 혼동이 오기도 했다.z-검정
,t-검정
,분산분석
- 이 중 2개 이하의 집단에서 평균을 비교하는 것은
z-검정
,t-검정
은 사실 동일한 분석방법이다. - 그러나, 실무에서는
t-검정
을 자주 사용한다 (모집단의 분산을 알 수 있는 방법이 없다, 이는 자세히 한번 얘기하도록 하겠다)
(1) 문제 정의
- 이제 부터 상상의 나래를 펼쳐보자.
- 이제 온라인 쇼핑몰을 운영하는 사장이다.
- 마케팅 부서에서는 콜센터를 통해 접수된 클레임 고객에 대한
타겟마케팅
을 기획한다. 클레임 고객
은 상대적으로 매장을 찾는 횟수가 적어져이탈위험도
가 높을 것이라고 예상되기 때문이다.
(2) 가설설정 및 분석방법
- 이제 가설 설정을 한다.
t
검정을 실시할 때는 보통의 경우 평균의 차이는 없는 것으로 정한다.- $H_{0}$(귀무가설) =
A
쇼핑 클레임 고객들과 비클레임 고객들의 방문 횟수 차이는 없다. - $H_{1}$(연구가설) =
A
쇼핑 클레임 고객들과 비클레임 고객들의 방문횟수 차이는 있다.
- $H_{0}$(귀무가설) =
- 즉, 두 그룹간의
평균
비교이다.
(3) 데이터 수집 및 분석방법
- 독립표본
t-검정
을 수행하기 위해서는 평균과 등분산 여부, 그리고t-value(검정 통계량)
과p-value(유의확률)
을 출력한다.- 가장 중요한 것은 두 그룹간의 분산이 동일한지 확인할 필요가 있다.
- 먼저 데이터를 불러온다.
# Mount Google Drive
from google.colab import drive # import drive from google colab
ROOT = "/content/drive" # default location for the drive
print(ROOT) # print content of ROOT (Optional)
drive.mount(ROOT) # we mount the google drive at /content/drive
/content/drive
Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True).
# import join used to join ROOT path and MY_GOOGLE_DRIVE_PATH
from os.path import join
# path to your project on Google Drive
MY_GOOGLE_DRIVE_PATH = 'My Drive/Colab Notebooks/inflearn/Python/Kaggle_Edu/05_statistics'
PROJECT_PATH = join(ROOT, MY_GOOGLE_DRIVE_PATH)
print(PROJECT_PATH)
/content/drive/My Drive/Colab Notebooks/inflearn/Python/Kaggle_Edu/05_statistics
%cd "{PROJECT_PATH}"
/content/drive/My Drive/Colab Notebooks/inflearn/Python/Kaggle_Edu/05_statistics
import pandas as pd
data = pd.read_csv('python_stat/Ashopping.csv', sep=",", encoding='CP949')
data.head()
고객ID | 이탈여부 | 총_매출액 | 방문빈도 | 1회_평균매출액 | 할인권_사용 횟수 | 총_할인_금액 | 고객등급 | 구매유형 | 클레임접수여부 | 구매_카테고리_수 | 거주지역 | 성별 | 고객_나이대 | 거래기간 | 할인민감여부 | 멤버쉽_프로그램_가입전_만족도 | 멤버쉽_프로그램_가입후_만족도 | Recency | Frequency | Monetary | 상품_만족도 | 매장_만족도 | 서비스_만족도 | 상품_품질 | 상품_다양성 | 가격_적절성 | 상품_진열_위치 | 상품_설명_표시 | 매장_청결성 | 공간_편의성 | 시야_확보성 | 음향_적절성 | 안내_표지판_설명 | 친절성 | 신속성 | 책임성 | 정확성 | 전문성 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 4007080 | 17 | 235711 | 1 | 5445 | 1 | 4 | 0 | 6 | 6 | 1 | 4 | 1079 | 0 | 5 | 7 | 7 | 3 | 4 | 6 | 5 | 6 | 7 | 7 | 6 | 7.0 | 6.0 | 6 | 7 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 |
1 | 2 | 1 | 3168400 | 14 | 226314 | 22 | 350995 | 2 | 4 | 0 | 4 | 4 | 1 | 1 | 537 | 0 | 2 | 3 | 2 | 3 | 3 | 2 | 5 | 4 | 6 | 7 | 6 | 6.0 | NaN | 7 | 7 | 6 | 6 | 6 | 5 | 3 | 6 | 6 | 6 |
2 | 3 | 0 | 2680780 | 18 | 148932 | 6 | 186045 | 1 | 4 | 1 | 6 | 6 | 1 | 6 | 1080 | 0 | 6 | 6 | 7 | 3 | 2 | 4 | 6 | 7 | 6 | 7 | 6 | 7.0 | NaN | 6 | 6 | 6 | 6 | 6 | 7 | 7 | 6 | 6 | 7 |
3 | 4 | 0 | 5946600 | 17 | 349800 | 1 | 5195 | 1 | 4 | 1 | 5 | 5 | 1 | 6 | 1019 | 0 | 3 | 5 | 7 | 3 | 5 | 3 | 5 | 5 | 6 | 6 | 6 | 5.0 | 6.0 | 6 | 6 | 5 | 6 | 6 | 6 | 6 | 6 | 5 | 6 |
4 | 5 | 0 | 13745950 | 73 | 188301 | 9 | 246350 | 1 | 2 | 0 | 6 | 6 | 0 | 6 | 1086 | 0 | 5 | 6 | 7 | 6 | 7 | 5 | 6 | 6 | 5 | 6 | 6 | 5.0 | 6.0 | 5 | 6 | 6 | 6 | 5 | 5 | 6 | 6 | 5 | 6 |
- 데이터를 확인했다면, 이제, 클레임 접수여부에 따라 클레임이 없는 (0)고객과, 클레임이 있는 고객(1) 객체에 저장후 두 그룹의 방문빈도를 추출한다.
- 우선 클레임이 없는 고객을 뽑자.
import numpy as np
no_claim = data[data.클레임접수여부 == 0]
no_claim_array = np.array(no_claim.방문빈도)
no_claim_array
array([ 17, 14, 73, 26, 6, 17, 19, 88, 39, 12, 27, 21, 56,
16, 21, 28, 17, 15, 48, 42, 33, 9, 32, 15, 23, 24,
18, 18, 38, 15, 16, 36, 8, 33, 41, 34, 12, 56, 60,
27, 10, 39, 48, 24, 8, 7, 25, 19, 33, 22, 30, 9,
80, 18, 15, 50, 71, 15, 66, 41, 18, 5, 78, 30, 14,
10, 54, 21, 43, 33, 24, 21, 13, 25, 37, 25, 47, 60,
21, 23, 18, 26, 28, 31, 58, 88, 19, 38, 37, 20, 33,
18, 15, 7, 29, 30, 6, 16, 10, 23, 10, 14, 18, 11,
15, 14, 90, 9, 9, 5, 15, 11, 33, 9, 20, 6, 42,
17, 78, 9, 20, 37, 14, 17, 25, 52, 19, 9, 26, 16,
49, 32, 24, 40, 44, 13, 16, 25, 16, 47, 27, 9, 15,
5, 26, 34, 39, 18, 28, 16, 32, 81, 15, 41, 9, 10,
9, 8, 56, 12, 65, 10, 45, 60, 22, 52, 15, 61, 18,
12, 23, 93, 28, 12, 39, 103, 11, 28, 6, 35, 6, 86,
17, 185, 16, 37, 21, 22, 50, 37, 14, 15, 28, 14, 11,
31, 31, 59, 26, 20, 29, 23, 11, 29, 11, 108, 6, 37,
29, 12, 11, 10, 18, 36, 73, 18, 22, 14, 22, 13, 31,
15, 31, 25, 52, 10, 35, 9, 9, 5, 27, 12, 79, 21,
8, 11, 64, 22, 60, 31, 15, 48, 18, 8, 31, 14, 46,
102, 10, 34, 4, 23, 43, 45, 9, 18, 26, 12, 8, 81,
51, 14, 28, 18, 24, 28, 15, 29, 8, 5, 17, 16, 28,
36, 27, 11, 10, 20, 13, 54, 23, 14, 27, 13, 38, 38,
79, 27, 97, 8, 10, 41, 6, 19, 16, 21, 46, 23, 39,
38, 19, 7, 6, 33, 61, 15, 10, 114, 71, 33, 25, 79,
13, 29, 34, 30, 19, 23, 40, 15, 17, 8, 3, 7, 21,
9, 40, 46, 24, 73, 38, 56, 13, 13, 30, 46, 6, 30,
19, 5, 20, 23, 7, 20, 26, 15, 58, 15, 11, 31, 17,
10, 14, 20, 10, 50, 21, 37, 30, 6, 16, 23, 21, 102,
26, 43, 8, 15, 10, 14, 71, 60, 45, 25, 49, 50, 9,
18, 23, 29, 106, 35, 22, 12, 203, 12, 17, 14, 39, 11,
19, 29, 22, 21, 9, 22, 11, 21, 58, 10, 5, 16, 39,
13, 33, 13, 14, 13, 18, 42, 11, 29, 28, 35, 9, 21,
26, 17, 24, 5, 23, 71, 22, 20, 20, 7, 14, 12, 10,
16, 18, 30, 25, 22, 15, 18, 43, 33, 46, 14, 12, 24,
23, 18, 23, 9, 13, 17, 22, 7, 18, 15, 39, 22, 22,
22, 9, 15, 36, 24, 32, 38, 109, 28, 23, 20, 76, 43,
25, 5, 46, 10, 22, 18, 30, 75, 34, 11, 17, 43, 39,
84, 42, 41, 26, 32, 31, 37, 15, 50, 22, 19, 6, 19,
11, 7, 25, 63, 21, 16, 67, 27, 5, 32, 31, 114, 20,
21, 14, 80, 19, 14, 32, 4, 15, 37, 24, 14, 11, 10,
20, 30, 10, 19, 6, 26, 26, 9, 4, 66, 16, 24, 29,
33, 20, 19, 20, 49, 10, 15, 23])
- 두번째, 클레임이 있는 고객을 뽑아본다.
claim = data[data.클레임접수여부 == 1]
claim_array = np.array(claim.방문빈도)
claim_array
array([ 18, 17, 109, 15, 21, 9, 12, 28, 5, 12, 12, 13, 8,
18, 27, 34, 23, 19, 29, 10, 19, 28, 23, 30, 14, 20,
7, 14, 32, 32, 18, 17, 10, 23, 12, 9, 43, 42, 7,
12, 73, 26, 27, 25, 29, 37, 32, 45, 34, 7, 29, 26,
27, 33, 27, 28, 8, 45, 66, 14, 73, 24, 13, 54, 24,
17, 29, 29, 57, 18, 17, 27, 15, 23, 11, 4, 15, 31,
21, 21, 11, 19, 34, 41, 18, 45, 10, 72, 18, 82, 10,
26, 17, 37, 17, 8, 26, 11, 28, 17, 12, 23, 37, 19,
7, 20, 9, 14, 13, 36, 26, 23, 23, 16, 30, 13, 45,
30, 6, 44, 32, 19, 20, 24, 7, 14, 7, 65, 31, 6,
37, 91, 17, 12, 23, 61, 162, 23, 21, 12, 14, 10, 18,
14, 4, 6, 26, 19, 27, 14, 7, 32, 11, 11, 20, 7,
7, 7, 27, 16, 26, 10, 12, 8, 12, 25, 14, 18, 30,
33, 86, 20, 22, 10, 34, 36, 9, 68, 28, 14, 61, 9,
17, 6, 30, 14, 25, 32, 19, 34, 26, 17, 24, 18, 30,
15, 15, 96, 17, 18, 19, 24, 16, 6, 27, 31, 15, 38,
11, 7, 65, 15, 7, 23, 7, 15, 34, 17, 20, 19, 10,
14, 19, 69, 4, 21, 13, 20, 45, 50, 58, 6, 15, 10,
10, 19, 32, 6, 38, 36, 6, 39, 16, 20, 48, 26, 21,
22, 7, 8, 28, 8, 31, 13, 46, 20, 8, 49, 9, 48,
20, 25, 54, 21, 6, 30, 40, 11, 12, 28, 15, 24, 90,
22, 15, 14, 7, 77, 39, 11, 18, 16, 55, 15, 12, 17,
23, 15, 33, 15, 18, 28, 7, 17, 34, 27, 44, 35, 67,
12, 54, 18, 10, 21, 28, 67, 9, 126, 23, 10, 41, 15,
21, 21, 42, 18, 31, 13, 20, 19, 39, 26, 11, 22, 64,
4, 27, 21, 14, 30, 25, 18, 11, 10, 70, 24, 18, 19,
30, 30, 19, 104, 39, 92, 52, 48, 30, 79, 15, 24, 23,
14, 8, 9, 21, 18, 11, 7, 8, 13, 21, 23, 2, 12,
12, 52, 22, 20, 6, 22, 6, 24, 12, 18, 20, 11, 12,
33, 8, 24, 79, 34, 8, 36, 13, 19, 5, 12, 25, 31,
27, 17, 11, 65, 29, 18, 10, 28, 22, 12, 18, 20, 27,
17, 20, 17, 8, 38, 18, 25, 10, 7, 18, 11, 55, 5,
20, 11, 41, 12, 11, 26, 55, 25, 6, 35, 38, 32, 27,
11, 10, 11, 55, 22, 12, 18, 10, 15, 32, 13, 29, 8,
17, 83, 15, 7, 8, 11, 27, 21, 18, 15, 19, 8, 16,
35, 15, 40, 8])
- 그 후,
stats.bartlett()
함수를 이용하여 등분산 검정을 실시한다.- 함수 설명: stats.bartlett()
- 이 때, 주의해야 하는 것이 있다.
- 등분산 검정의 귀무가설과 대립가설을 다음과 같다.
- H0 : 등분산이다.
- H1 : 이분산이다(등분산이 아니다).
- 즉, 등분산 가정의 귀무가설을 채택하려면 유의확률인 0.05 > p 나와야 한다.
from scipy import stats
stats.bartlett(no_claim_array, claim_array)
BartlettResult(statistic=13.626177910965525, pvalue=0.00022305349806448475)
- 여기에서 두 고객 그룹간의 등분산 검정 결과
F
값은 13.626, 유의확률은0.05
미만으로 귀무가설이 기각된다.- 즉, 두 집단의 분산은 동일하지 않은 것으로 나타났다.
- 등분산성이 나와야 하는데, 나오지 않아서 입문자들이 조금 당혹스러워 할 수 있다.
- 굳이 당황할 필요는 없다. 분산이 동일하지 않으면 동일하지 않다고 표시만 해두면 된다.
(check: equal_var)
- 굳이 당황할 필요는 없다. 분산이 동일하지 않으면 동일하지 않다고 표시만 해두면 된다.
- 이제
ttest_ind
를 활용해서 구하도록 하자.- 함수설명: ttest_ind
print(stats.ttest_ind(no_claim_array, claim_array, equal_var=False))
Ttest_indResult(statistic=2.595726838875684, pvalue=0.009577734932789503)
- 독립표본
t-value
는2.59
이며,p-value
0.0095
로 나왔다.- 이 의미는 두 그룹간의 평균 방문 빈도에 차이가 있음을 의미한다.
- 조금 더 구체적으로 구해보자.
(4) 시각화
- 실제 두 그룹간의 차이를
matplotlib
을 활용하여 시각화로 구현해본다. - 이 때, 각 그룹의
평균(Mean)
과표준편차(Standard Deviation)
를 구한다.
# 평균 계산하기
no_claim_mean = np.mean(no_claim_array)
claim_mean = np.mean(claim_array)
print("클레임이 없는 고객의 평균 방문빈도:", no_claim_mean)
print("클레임이 있는 고객의 평균 방문빈도:", claim_mean)
# 표준편차 구하기
no_claim_std = np.std(no_claim_array)
claim_std = np.std(claim_array)
print("클레임이 없는 고객의 표준편차:", no_claim_std)
print("클레임이 있는 고객의 표준편차:", claim_std)
# 라벨 정리
viz_labels = ['No Claim', 'Claim']
x_pos = np.arange(len(viz_labels))
avg = (no_claim_mean, claim_mean)
error = [no_claim_std, claim_std]
클레임이 없는 고객의 평균 방문빈도: 28.184842883548985
클레임이 있는 고객의 평균 방문빈도: 24.736383442265794
클레임이 없는 고객의 표준편차: 22.7348095052013
클레임이 있는 고객의 표준편차: 19.234427104778828
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.bar(x_pos, avg,
yerr = error,
align='center',
alpha=0.5,
ecolor='black',
capsize=10)
ax.set_ylabel('Avg. Customer Visitation')
ax.set_xticks(x_pos)
ax.set_xticklabels(viz_labels)
ax.set_title('The Customer difference between No Claim and Claim')
ax.yaxis.grid(True)
plt.tight_layout()
plt.show()
- 막대그래프는
평균값
을 의미하고,Error bar
는표준편차
를 의미한다.
(5) T검정 해석
- 먼저 두 고객그룹간의 등분산성 검정 결과
F
값은 13.626,p-value
는0.00022
로 도출되었다.- 즉, 두 표본의 분산은 동일하지 않다.
- 따라서, 등분산이 가정되지 않은
t 통계량
을 확인하여 가설검증을 수행한다.- 분석결과 클레임 접수 경험이 있는 고객
(클레임 접수 여부=0)
의 평균 방문 횟수는 24.73회, 클레임 접수 경험이 없는 고객(클레임 접수 여부=1)
평균 방문 횟수는 28.18회이며, 이는t-값
은 2.60, 유의확률은 0.0096으로 도출되어 클레임 접수 여부에 따라 방문 빈도는 차이가 있다. (유의수준 0.05 이내)
- 분석결과 클레임 접수 경험이 있는 고객
- 위 결과를 토대로, 클레임 접수 고객이 많으면 많을수록 매장 방문 빈도가 줄어드는 것을 추론할 수 있으므로 클레임 접수 고객이 더 많이 유입되는
마케팅 지원책
을 강구해야 한다.
결론
- 위 내용은
Reference
교재에서 내용을 요약 및 보충하였다.- 조금 더 자세한 내용은 교재를 구입하자.
- 위 과정은 매우 간단한 코드로 누구나 실행해서 참고할 수 있다.
- 데이터 전처리와 그에 맞는 적절한 기초통계만으로 굉장히 의미있는 인사이트를 도출할 수 있다.
- 기초통계는 마케팅에서 즉시적으로 사용할 수 있는 기법이다. 또한 어렵지 않음을 기억하자.
Reference
- 김형수(2020). Step by Step 파이썬 비즈니스 통계분석. 서울: 프레딕스.