[python] 평가 (정확도, 오차행렬, 정밀도, 재현율)
2021. 5. 6. 15:32ㆍPython/문법
3.1_3-5_정확도 _ ROC_AUC 예제.ipynb
0.11MB
Ver. Jupyter Notebook (Anaconda3)
▶ 정확도
정확도 = 예측 결과가동일한 데이터 건수 / 전체 예측 데이터 건수
# 이진 분류 시 좋은 평가 지표는 아니다.
# 예) 0~10 숫자 중 0일 경우를 맞추는 문제에서, 모든 답을 아니라고 하면 정확도는 90%가 됨
더보기
>>> from sklearn.datasets import load_digits # mnist 데이터셋 로드
>>> from sklearn.model_selection import train_test_split
>>> from sklearn.base import BaseEstim
>>> from sklearn.metrics import accuracy_score
>>> import numpy as np
>>> import pandas as pd
# 모든 데이터를 0으로 만드는 클래스
>>> class MyFakeClassifier(BaseEstimator):
>>> def fit(self, X, y):
>>> pass
# 입력값으로 들어오는 X 데이터 셋의 크기만큼 모두 0값으로 만들어서 반환
>>> def predict(self, X):
>>> return np.zeros( (len(X), 1) , dtype=bool)
# 사이킷런의 내장 데이터 셋인 load_digits( )를 이용하여 MNIST 데이터 로딩
>>> digits = load_digits()
>>> digits
{'data': array([[ 0., 0., 5., ..., 0., 0., 0.],
[ 0., 0., 0., ..., 10., 0., 0.],
[ 0., 0., 0., ..., 16., 9., 0.],
...,
[ 0., 0., 1., ..., 6., 0., 0.],
[ 0., 0., 2., ..., 12., 0., 0.],
[ 0., 0., 10., ..., 12., 1., 0.]]),
'target': array([0, 1, 2, ..., 8, 9, 8]),
'frame': None,
'feature_names': ['pixel_0_0',
'pixel_0_1',
'pixel_0_2',
'pixel_0_3',
# mnist의 feature 데이터
>>> print(digits.data.shape)
>>> digits.data
(1797, 64)
array([[ 0., 0., 5., ..., 0., 0., 0.],
[ 0., 0., 0., ..., 10., 0., 0.],
[ 0., 0., 0., ..., 16., 9., 0.],
...,
[ 0., 0., 1., ..., 6., 0., 0.],
[ 0., 0., 2., ..., 12., 0., 0.],
[ 0., 0., 10., ..., 12., 1., 0.]])
# mnist의 target 데이터
>>> print(digits.target.shape)
>>> digits.target
(1797,)
array([0, 1, 2, ..., 8, 9, 8])
# 7번이면 True이고 1로 변환, 7번이 아니면 False이고 0으로 변환
>>> y = (digits.target == 7).astype(int)
>>> y
array([0, 0, 0, ..., 0, 0, 0])
# train, test 데이터 분리
>>> X_train, X_test, y_train, y_test = train_test_split(digits.data, y, random_state=11)
# InteractiveShell : print 안 써도 쉘의 모든 결과를 출력해주는 라이브러리
>>> from IPython.core.interactiveshell import InteractiveShell
>>> InteractiveShell.ast_node_interactivity = "all"
>>> X_train.shape
>>> y_train.shape
(712, 8)
(712,)
>>> X_test.shape
>>> y_test..shape
(450, 64)
(450,)
# 불균형한 레이블 데이터 분포도 확인.
>>> print('레이블 테스트 세트 크기 :', y_test.shape, '\n')
>>> print('테스트 세트 레이블 0(7이 아닌 숫자)과 1(숫자 7)의 분포도')
>>> print(pd.Series(y_test).value_counts())
레이블 테스트 세트 크기 : (450,)
테스트 세트 레이블 0(7이 아닌 숫자)과 1(숫자 7)의 분포도
0 405
1 45
dtype: int64
# MyFakeClassifier(모든 숫자 예측을 0으로(7이 아니다) 하는 모델)로 학습 및 예측
>>> fakeclf = MyFakeClassifier()
>>> fakeclf.fit(X_train , y_train)
# 정확도 평가
>>> fakepred = fakeclf.predict(X_test)
>>> print('모든 예측을 0으로 하여도 정확도는:{:.3f}'.format(accuracy_score(y_test , fakepred)))
모든 예측을 0으로 하여도 정확도는:0.900
▶ 오차 행렬
예측 클래스 (Predicted Class) |
|||
실제 클래스 (Actual Class) |
Negative(0) | Positive(1) | |
Negative(0) | TN (True Negative) |
FP (False Positive) |
|
Positive(1) | FN (False Negative) |
TP (True Positive) |
더보기
>>> from sklearn.metrics import confusion_matrix
# 예측 결과 fakepred와 실제 결과 y_test의 Confusion Matrix출력
>>> confusion_matrix(y_test , fakepred)
array([[405, 0],
[ 45, 0]], dtype=int64)
▶ 정밀도, 재현율의 관계
정밀도 = TP / (FP + TP)
재현율 = TP / (FN + TP)
# 암에 걸렸을 확률 같은 경우 임계값을 낮게 잡아 재현율을 높이는것이 유리
# 스펨 메일같은 경우 임계값을 높여 중요한 메일이 스팸으로 걸러지는 것을 방지하는 것이 좋음
더보기
>>> from sklearn.metrics import accuracy_score, precision_score , recall_score
>>> print("정밀도:", precision_score(y_test, fakepred))
>>> print("재현율:", recall_score(y_test, fakepred))
정밀도: 0.0
재현율: 0.0
# 오차행렬, 정확도, 정밀도, 재현율을 한꺼번에 계산하는 함수 생성
>>> from sklearn.metrics import accuracy_score, precision_score , recall_score , confusion_matrix
# confusion matrix, accuracy, precision, recall을 한꺼번에 계산하는 함수
>>> def get_clf_eval(y_test , pred):
>>> confusion = confusion_matrix( y_test, pred)
>>> accuracy = accuracy_score(y_test , pred)
>>> precision = precision_score(y_test , pred)
>>> recall = recall_score(y_test , pred)
>>> print('오차 행렬')
>>> print(confusion)
>>> print('정확도: {0:.4f}, 정밀도: {1:.4f}, 재현율: {2:.4f}'.format(accuracy , precision ,recall), '\n')
# 타이타닉 데이터에 로직스틱 회기 모델로 이진 분류한 후에 오차행렬, 정확도, 정밀도, 재현율 구해보기
>>> import numpy as np
>>> import pandas as pd
>>> from sklearn.model_selection import train_test_split
>>> from sklearn.linear_model import LogisticRegression
# 타이타닉 데이터 로드
>>> titanic_df = pd.read_csv('./titanic_train.csv')
# feature(X), target(y) 데이터 분리
>>> y_titanic_df = titanic_df['Survived']
>>> X_titanic_df= titanic_df.drop('Survived', axis=1)
# 데이터 전처리
>>> X_titanic_df = transform_features(X_titanic_df)
# train, test 데이터 분리
>>> X_train, X_test, y_train, y_test = train_test_split(X_titanic_df, y_titanic_df, \
test_size=0.20, random_state=11)
# 로지스틱 회귀(분류 모델) 모델 정의
>>> lr_clf = LogisticRegression()
>>> lr_clf
LogisticRegression()
# 학습
>>> lr_clf.fit(X_train , y_train)
# 예측
>>> pred = lr_clf.predict(X_test)
# 평가지표 계산
>>> get_clf_eval(y_test , pred)
오차 행렬
[[104 14]
[ 13 48]]
정확도: 0.8492, 정밀도: 0.7742, 재현율: 0.7869
# F1 Score와 ROC Curve, AUC가 가장 많이 사용됨
▶ F1 Score
더보기
>>> from sklearn.metrics import f1_score
# f1_score 클래스를 이용해서 f1 score 계산
>>> f1 = f1_score(y_test , pred) # 실제값, 예측값
>>> print('F1 스코어: {0:.4f}'.format(f1))
F1 스코어: 0.7805
>>> def get_clf_eval(y_test , pred):
>>> confusion = confusion_matrix( y_test, pred)
>>> accuracy = accuracy_score(y_test , pred)
>>> precision = precision_score(y_test , pred)
>>> recall = recall_score(y_test , pred)
# F1 스코어 추가
>>> f1 = f1_score(y_test,pred)
>>> print('오차 행렬')
>>> print(confusion)
# f1 score print 추가
>>> print('정확도: {0:.4f}, 정밀도: {1:.4f}, 재현율: {2:.4f}, F1:{3:.4f}'.format(accuracy, precision, recall, f1), '\n')
>>> thresholds = [0.4 , 0.45 , 0.50 , 0.55 , 0.60]
>>> pred_proba = lr_clf.predict_proba(X_test)
# 분류 임계값 변경을 하면서 f1 score를 포함한 평가지표 확인
>>> get_eval_by_threshold(y_test, pred_proba[:,1].reshape(-1,1), thresholds)
임곗값: 0.4
오차 행렬
[[98 20]
[10 51]]
정확도: 0.8324, 정밀도: 0.7183, 재현율: 0.8361, F1:0.7727
임곗값: 0.45
오차 행렬
[[103 15]
[ 12 49]]
정확도: 0.8492, 정밀도: 0.7656, 재현율: 0.8033, F1:0.7840
임곗값: 0.5
오차 행렬
[[104 14]
[ 13 48]]
정확도: 0.8492, 정밀도: 0.7742, 재현율: 0.7869, F1:0.7805
임곗값: 0.55
오차 행렬
[[109 9]
[ 15 46]]
정확도: 0.8659, 정밀도: 0.8364, 재현율: 0.7541, F1:0.7931
임곗값: 0.6
오차 행렬
[[112 6]
[ 16 45]]
정확도: 0.8771, 정밀도: 0.8824, 재현율: 0.7377, F1:0.8036
# 위 데이터의 경우 임계값이 0.6일 때 f1 score가 가장 높다. 그런데 재현율이 너무 낮기 때문에 여러가지 요소를 고려해야 한다.
▶ ROC Curve와 AUC
# ROC Curve : 파란색 곡선
# AUC : ROC Curve를 기준으로 아래쪽 면적
# AUC가 높을 수록 좋은 결과 값
더보기
>>> from sklearn.metrics import roc_curve
# 레이블 값이 1일때의 예측 확률을 추출
>>> pred_proba_class1 = lr_clf.predict_proba(X_test)[:, 1]
>>> print(len(pred_proba_class1))
>>> pred_proba_class1[:20]
179
array([0.53815943, 0.12133005, 0.12283041, 0.11734445, 0.14489353,
0.11774417, 0.11157936, 0.79123724, 0.21729086, 0.63044738,
0.10017 , 0.12507789, 0.1228364 , 0.11162534, 0.56354548,
0.14104185, 0.09631462, 0.26666825, 0.27536599, 0.82819347])
# fpr, tps, thresholds
>>> fprs , tprs , thresholds = roc_curve(y_test, pred_proba_class1)
>>> print('분류 임곗값 Shape :', thresholds.shape, '\n')
분류 임곗값 Shape : (55,)
# 반환된 임곗값 배열 로우가 55건이므로 샘플로 10건만 추출하되, 임곗값을 5 Step으로 추출.
>>> thr_index = np.arange(0, thresholds.shape[0], 5)
>>> print('샘플 추출을 위한 임곗값 배열의 index 10개:', thr_index)
>>> print('샘플용 10개의 임곗값: ', np.round(thresholds[thr_index], 2))
샘플 추출을 위한 임곗값 배열의 index 10개: [ 0 5 10 15 20 25 30 35 40 45 50]
샘플용 10개의 임곗값: [1.97 0.75 0.63 0.59 0.49 0.4 0.35 0.23 0.13 0.12 0.11]
# 5 step 단위로 추출된 임계값에 따른 FPR, TPR 값
>>> print('샘플 임곗값별 FPR: ', np.round(fprs[thr_index], 3))
>>> print('샘플 임곗값별 TPR: ', np.round(tprs[thr_index], 3))
샘플 임곗값별 FPR: [0. 0.017 0.034 0.051 0.127 0.161 0.203 0.331 0.585 0.636 0.797]
샘플 임곗값별 TPR: [0. 0.475 0.689 0.754 0.787 0.836 0.869 0.902 0.918 0.967 0.967]
>>> from sklearn.metrics import roc_auc_score
>>> pred_proba = lr_clf.predict_proba(X_test)[:, 1]
>>> roc_score = roc_auc_score(y_test, pred_proba)
>>> print('ROC AUC 값: {0:.4f}'.format(roc_score))
ROC AUC 값: 0.9024
'Python > 문법' 카테고리의 다른 글
[python] 텍스트 분석 (0) | 2021.05.11 |
---|---|
[python] 분류 (0) | 2021.05.07 |
[Python] 데이터 전처리 (원-핫 인코딩, 표준화, 정규화) (0) | 2021.05.05 |
[python] 사이킷런으로 머신러닝 (0) | 2021.05.04 |
[python] numpy (0) | 2021.05.03 |