피마 인디언 당뇨병 데이트 세트를 이용해 당뇨병 여부를 판단하는 머신러닝 예측 모델을 수립해본다
피마 인디언 당뇨병 데이터 세트의 피처 구성이다.
- Pregnancies: 임신횟수
- Glucose: 포도당 부하 검사 수치
- BloodPressure: 혈압(mm Hg)
- SkinThickness: 팔 삼두근 뒤쪽의 피하지방 측정값(mm)
- Insulin: 혈청 인슐린
- BMI: 체질량 지수
- DiabetesPedigreeFunction: 당뇨 내력 가중치 값
- Age: 나이
- Outcome: 클래스 결정값 (0 또는 1)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, precision_score, recall_score, roc_auc_score
from sklearn.metrics import f1_score, confusion_matrix, precision_recall_curve, roc_curve
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
diabetes_data = pd.read_csv('diabetes.csv')
print(diabetes_data['Outcome'].value_counts())
diabetes_data.head(3)
Negative 0 이 Positive 1보다 상대적으로 많은 것을 확인할 수 있다.
feature 타입과 Null 개수를 살펴보자
diabetes_data.info()
[output]
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 768 entries, 0 to 767
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Pregnancies 768 non-null int64
1 Glucose 768 non-null int64
2 BloodPressure 768 non-null int64
3 SkinThickness 768 non-null int64
4 Insulin 768 non-null int64
5 BMI 768 non-null float64
6 DiabetesPedigreeFunction 768 non-null float64
7 Age 768 non-null int64
8 Outcome 768 non-null int64
dtypes: float64(2), int64(7)
memory usage: 54.1 KB
null 값은 없으며 피처의 타입은 모두 숫자형이다. 그러므로 별도의 인코딩은 필요하지 않다.
이제 로지스틱 회귀를 이용해 예측 모델을 생성해보자
앞 예제에서 사용한 유틸리티 함수인 get_clf_eval(), get_eval_by_threshold(), precision_recall_curve_plot을 이용해 성능 평가 지표를 출력하고 재현율 곡선을 시각화해본다.
#피처 데이터 세트 x, 레이블 데이터 세트 y 추출
#맨 끝이 Outcome 칼럼으로 레이블 값임. 칼럼 위치 -1을 이용해 추출
X = diabetes_data.iloc[:, :-1]
y = diabetes_data.iloc[:,-1]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=156, stratify=y)
#로지스틱 회귀로 학습, 예측 및 평가 수행
Ir_clf = LogisticRegression(solver='liblinear')
Ir_clf.fit(X_train, y_train)
pred = Ir_clf.predict(X_test)
pred_proba = Ir_clf.predict_proba(X_test)[:,1]
get_clf_eval(y_test, pred, pred_proba)
[output]
오차 행렬
[[87 13]
[22 32]]
정확도:0.7727, 정밀도:0.7111, 재현율:0.5926, F1:0.6465, AUC:0.8083
전체 데이터의 65%가 Negative이므로 정확도보다는 재현율 성능에 좀 더 초점을 맞춰보자
먼저 정밀도 재현율 곡선을 보고 임곗값별 정밀도와 재현율 값의 변화를 확인해보자
pred_proba_c1 = Ir_clf.predict_proba(X_test)[:,1]
precision_recall_curve_plot(y_test, pred_proba_c1)
재현율 곡선을 보면 임곗값을 0.42 정도로 낮추면 정밀도와 재현율이 어느정도 균형을 맞출 것 같다.
하지만 두 개의 지표 모두 0.7이 안되는 수치로 값이 낮다.
임곗값을 다시 조작하기 전에 데이터 값을 점검해보자
이 데이터를 보면 min()값이 0으로 말이 되지 않는 수치로 나와있다.
plt.hist(diabetes_data['Glucose'], bins=100)
plt.show()
Glucose 피처 히스토그램을 보면 0값이 일정 수준 존재하는 것을 알 수 있다.
min()값이 0으로 돼있는 피처에 대해 0 값의 건수 및 전체 데이터 건수 대비 몇 퍼센트의 비율로 존재하는지 확인해보자
#0값을 검사할 피처명 리스트
zero_features = ['Glucose', 'BloodPressure', 'SkinThickness', 'Insulin', 'BMI']
#전체 데이터 건수
total_count = diabetes_data['Glucose'].count()
# 피처별로 반복하면서 데이터 값이 0인 데이터 건수를 추출하고, 퍼센트 계산
for feature in zero_features:
zero_count = diabetes_data[diabetes_data[feature]==0][feature].count()
print('{0}0 건수는 {1}, 퍼센트는{2:.2f}%'.format(feature, zero_count, 100*zero_count/total_count))
[output]
Glucose0 건수는 5, 퍼센트는0.65%
BloodPressure0 건수는 35, 퍼센트는4.56%
SkinThickness0 건수는 227, 퍼센트는29.56%
Insulin0 건수는 374, 퍼센트는48.70%
BMI0 건수는 11, 퍼센트는1.43%
전체 데이터 건수가 많지 않기 때문에 이들 데이터를 일괄적으로 삭제할 경우에는 학습을 효과적으로 수행하기 어려울 것같다.
위 피처의 0 값을 평균값으로 대체해보자
#zero_features 리스트 내부에 저장된 개별 피처들에 대해서 0값을 평균 값으로 대체
mean_zero_features = diabetes_data[zero_features].mean()
diabetes_data[zero_features]=diabetes_data[zero_features].replace(0,mean_zero_features)
0 값을 평균값으로 대체한 데이터 세트에 피처 스케일링을 적용해 변환해보자.
로지스틱 회귀의 경우 숫자 데이터에 스케일링을 적용하는 것이 좋다.
이후에 다시 학습/테스트 데이터 세트를 나누고 로지스틱 회귀를 적용해 성능 평가 지표를 확인해보자
X = diabetes_data.iloc[:,:-1]
y = diabetes_data.iloc[:,-1]
#standardScaler 클래스를 이용해 피처 데이터 세트에 일괄적으로 스케일링 적용
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=156, stratify=y)
#로지스틱 회귀로 학습, 예측 및 평가 수행
Ir_clf = LogisticRegression()
Ir_clf.fit(X_train, y_train)
pred = Ir_clf.predict(X_test)
pred_proba = Ir_clf.predict_proba(X_test)[:,1]
get_clf_eval(y_test, pred, pred_proba)
[output]
오차 행렬
[[90 10]
[21 33]]
정확도:0.7987, 정밀도:0.7674, 재현율:0.6111, F1:0.6804, AUC:0.8433
데이터 변환과 스케일링을 통해 성능 수치가 일정 수준 개선됐지만 재현율 수치는 개선이 더 필요해보인다.
분류 결정 임곗값을 0.3에서 0.5까지 0.03 씩 변화시키면서 성능 수치가 어느 정도 개선되는지 확인해보자
thresholds = [0.3, 0.33, 0.36, 0.39, 0.42, 0.45, 0.48, 0.50]
pred_proba = Ir_clf.predict_proba(X_test)
get_eval_by_threshold(y_test, pred_proba[:,1].reshape(-1,1), thresholds)
[output]
임곗값: 0.3
오차 행렬
[[67 33]
[11 43]]
정확도:0.7143, 정밀도:0.5658, 재현율:0.7963, F1:0.6615, AUC:0.8433
임곗값: 0.33
오차 행렬
[[72 28]
[12 42]]
정확도:0.7403, 정밀도:0.6000, 재현율:0.7778, F1:0.6774, AUC:0.8433
임곗값: 0.36
오차 행렬
[[76 24]
[15 39]]
정확도:0.7468, 정밀도:0.6190, 재현율:0.7222, F1:0.6667, AUC:0.8433
임곗값: 0.39
오차 행렬
[[78 22]
[16 38]]
정확도:0.7532, 정밀도:0.6333, 재현율:0.7037, F1:0.6667, AUC:0.8433
임곗값: 0.42
오차 행렬
[[84 16]
[18 36]]
정확도:0.7792, 정밀도:0.6923, 재현율:0.6667, F1:0.6792, AUC:0.8433
임곗값: 0.45
오차 행렬
[[85 15]
[18 36]]
정확도:0.7857, 정밀도:0.7059, 재현율:0.6667, F1:0.6857, AUC:0.8433
임곗값: 0.48
오차 행렬
[[88 12]
[19 35]]
정확도:0.7987, 정밀도:0.7447, 재현율:0.6481, F1:0.6931, AUC:0.8433
임곗값: 0.5
오차 행렬
[[90 10]
[21 33]]
정확도:0.7987, 정밀도:0.7674, 재현율:0.6111, F1:0.6804, AUC:0.8433
임곗값 0.48이 전체적인 성능 평가 지표를 유지하면서 재현율을 약간 향상시키는 좋은 임곗값으로 보인다.
앞에서 학습된 로지스틱 회귀 모델을 이용해 임곗값 0.48로 낮춘 상태에서 다시 예측을 해본다.
#임곗값을 0.48로 설정한 Binarizer 생성
binarizer = Binarizer(threshold=0.48)
#위에서 구한 Ir_clf.predict_proba() 예측 확률 array 에서 1에 해당하는 칼럼값을 Binarizer 변환
pred_th_048 = binarizer.fit_transform(pred_proba[:,1].reshape(-1,1))
get_clf_eval(y_test, pred_th_048, pred_proba[:,1])
[output]
오차 행렬
[[88 12]
[19 35]]
정확도:0.7987, 정밀도:0.7447, 재현율:0.6481, F1:0.6931, AUC:0.8433
Ref) 파이썬 머신러닝 완벽가이드
'데이터 > 머신러닝' 카테고리의 다른 글
[Clustering] Chapter 7 | 군집화 (01. K-평균 알고리즘의 이해) (0) | 2023.01.22 |
---|---|
[Classification] Chapter 4 | 분류(01. 분류의 개요~02. 결정 트리) (0) | 2022.09.05 |
[Evaluation] Chapter 3 | 평가 (04. F1 스코어 ~ 05. ROC 곡선과 AUC) (0) | 2022.08.29 |
[Evaluation] Chapter 3 | 평가 (01. 정확도 ~ 03. 정밀도와 재현율) (0) | 2022.08.28 |
[Numpy, Pandas] Chapter 2 | 사이킷런으로 시작하는 머신러닝 (06. 사이킷런으로 수행하는 타이타닉 생존자 예측) (0) | 2022.08.25 |