본문 바로가기

AI Study/Machine Learning

머신러닝 성능 평가 지표 (2) - 정밀도,재현율,F1 score, ROC curve

오차행렬, Confusion Matrix

  • 이진분류에서 활용, 혼동행렬이라고도 해석되며 학습된 분류 모델이 예측을 수행하면서 얼마나 헷갈리고 있는지를 함께 보여주는 지표임.
  • 이진 분류의 예측 오류가 얼마인지 + 어떤 유형의 오류가 발생하는지 함께 확인 가능

 

 

  • TN, TP, FP, FN은 예측 클래스와 실제 클래스의 Positive 결정 값(값1)과 Negative 결정값 (값 0)의 결합에 따라 결정됨
  • 앞의 값 : 예측 클래스와 실제 클래스가 같은 가
  • 뒤의 값 : 예측값이 무엇인가
  • 뒤에서 부터 읽으면 쉬움
    • TN : 예측값을 Negative 값 0으로 예측했고 실제 값 역시 Negative 값 0
    • TP : 예측값을 Positive 값 1으로 예측했고 실제 값은 Negative 값 0
    • FN : 예측값을 Negative 값 0으로 예측했고 실제 값은 Positive 값 1
    • FP : 예측값을 Positive 값 1으로 예측했고 실제 값은 Negative 값 0
  • 오차행렬 상에서의 정확도 정의
  • 정확도(Accuray) = 예측 결과와 실제 값이 동일한 건수/전체 예측 데이터 수 = (TN+TP)/(TN+TP+FP+FN)

 

In [37]:
from sklearn.metrics import confusion_matrix

# 앞절의 예측 결과인 fakepred와 실제 결과인 y_test의 Confusion Matrix출력
confusion_matrix(y_test , fakepred)
 
Out[37]:
array([[405,   0],
       [ 45,   0]], dtype=int64)
 

정밀도(Precision) 과 재현율(Recall)

  • Positive data set의 예측 성능에 좀 더 초점을 맞춘 평가 지표
  • 정밀도(양성예측도) : 예측을 Positive로 한 대상 중에 예측과 실제값이 Positive로 일치한 데이터의 비율
    • positive 예측 성능을 더욱 정밀하게 측정하기 위한 평가 지표이기에 양성 예측도라고도 불림.
      Precision = TP/(FP+TP)
  • 재현율 : 실제 값이 Positive인 대상 중에 예측과 실제 값이 Positive로 일치한 데이터의 비율
    • 민감도(Sensitivity) 또는 TPR(True Positive Rate)라고도 불림.
      Recall = TP/(FN+TP)
  • 재현율과 정밀도 모두 TP를 높이려 하지만 재현율은 FN(예측 negative, 실제 positive)을 낮추는 데에 초점을 맞춤. 정밀도는 FP(예측 positive, 실제 negative)을 낮추는데에 목적을 둠.
  • 재현율과 정밀도 모두 챙기는 것이 바람직함.
  • 정밀도 vs 재현율 (보통 재현율이 더 중요한 경우가 더 많음)
    • 재현율이 중요한 순간 : 실제 Positive 양성 데이터를 Negative로 잘못 판단하게 되면 업무상 큰 영향이 발생하는 경우
      • ex) 암 판단 모델.
        • Positive가 암이 있는 경우. 암 환자를 정상으로 판단하는 경우 매우 심각. 정상을 암환자로 예측하면 재검사 수준에서 그침.
      • ex) 금융 사기 적발 모델.
        • Positive가 금융 사기인 경우. 사기꾼을 놓치면 회사에 큰 손해. 정상을 사기꾼으로 본 경우 재확인을 더 하면 됨.
    • 정밀도가 중요한 순간 : 실제 Negative 음성 데이터를 Positive로 잘못 판단하게 되면 업무상 큰 영향이 발생하는 경우
      • ex) 스팸 메일 여부를 판단하는 모델.
        • Positive 스팸 메일을 일반 메일로 분류하면 불편한 정도. 일반 메일이 스팸 메일이 되면 업무 못함
 
  • MyFakeClassifier의 예측 결과로 정밀도와 재현율 측정
In [38]:
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
 
c:\users\user\appdata\local\programs\python\python37\lib\site-packages\sklearn\metrics\_classification.py:1221: UndefinedMetricWarning: Precision is ill-defined and being set to 0.0 due to no predicted samples. Use `zero_division` parameter to control this behavior.
  _warn_prf(average, modifier, msg_start, len(result))
 

오차행렬, 정확도, 정밀도, 재현율을 한꺼번에 계산하는 함수 생성

  • 오차 행렬, 정밀도, 재현율 모두 계산해보기
  • sklearn은 정밀도(Precision)을 위해 precision_score(), 재현율(Recall)을 위해 recall_score() API를 제공함.
  • confusion matrix, accuracy, precision, recall을 모두 한번에 불러오는 get_clf_eval() 함수를 만들어 편하게 이용할 것.
 
In [39]:
# confusion matrix, accuracy, precision, recall을 모두 한번에 불러오는 get_clf_eval() 함수
from sklearn.metrics import accuracy_score, precision_score , recall_score , confusion_matrix

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))
 
In [40]:
# 로지스틱 회귀 기반으로 타이타닉 생존자를 예측하고 평가를 수행

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('data/titanic_train.csv')
y_titanic_df = titanic_df['Survived']
X_titanic_df= titanic_df.drop('Survived', axis=1)
X_titanic_df = transform_features(X_titanic_df)

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.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
 
c:\users\user\appdata\local\programs\python\python37\lib\site-packages\sklearn\linear_model\_logistic.py:764: ConvergenceWarning: lbfgs failed to converge (status=1):
STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.

Increase the number of iterations (max_iter) or scale the data as shown in:
    https://scikit-learn.org/stable/modules/preprocessing.html
Please also refer to the documentation for alternative solver options:
    https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression
  extra_warning_msg=_LOGISTIC_SOLVER_CONVERGENCE_MSG)
 

Precision/Recall Trade-off

  • 위의 결과에서 정밀도에 비해 재현율이 약가 낮음 -> 어느 한 쪽을 강화하려면?
  • 정밀도/재현율 trade-off
    • 분류 엄무의 특성 상 정밀도 or 재현율이 특별히 강조돼야 할 경우 분류의 결정 임계값(Threshold)을 조정해 정밀도 or 재현율의 수치를 높일 수 있음.
    • 정밀도와 재현율은 상호 보완적인 평가 지표이기 때문에 어느 한쪽을 강제로 높이면 다른 하나의 수치는 떨어지기 쉬움.
  • sklearn의 분류 알고리즘
    • 예측 데이터가 특정 레이블(Label, 결정 크래스 값)에 속하는지를 계산하기 위해 먼저 개별 레이블 별로 결정확률을 구함
    • 예측 확률이 큰 레이블 값으로 예측하게 됨
      • ex) 이진 분류 모델에서 특정 데이터가 0이 될 확률이 10%, 1이 될 확률이 90%로 예측 -> 최종 예측은 1로 예측
    • 일반적으로 이진분류에서는 임곗값을 0.5(50%)로 정하고 이 기준 값보다 확률이 크면 Positive, 작으면 Negative로 결정.
  • sklearn은 개별 데이터 별로 예측확률을 반환하는 메서드인 predict_proba()를 제공
    • predict_proba()
      • 학습이 완료된 sklearn Classifier 객체에서 호출이 가능
      • test feature data set를 파라미터로 입력해주면 test feature record의 개별 클래스 예측 확률을 반환
      • predict method와 유사하지만, 반환 결과가 예측 결과 클래스 값이 아닌 예측 확률 결과임

predict_proba( ) 메소드 확인

  • 이진분류에서는 predict_probe()를 수행해 반환되는 ndarray는 첫번째 칼럼이 클래스 값 0에 대한 예측확률, 두번째 칼럼이 클래스값 1에 대한 예측 확률임
In [41]:
# 타이타닉 생존자 데이터를 학습한 LogisticRegression 객체에서 predict_proba() mathod를 수행한 뒤, 반환 값을 확인하고 predict() 결과와 비교

pred_proba = lr_clf.predict_proba(X_test)
pred  = lr_clf.predict(X_test)
print('pred_proba()결과 Shape : {0}'.format(pred_proba.shape))
print('pred_proba array에서 앞 3개만 샘플로 추출 \n:', pred_proba[:3])

# 예측 확률 array 와 예측 결과값 array 를 concatenate 하여 예측 확률과 결과값을 한눈에 확인

pred_proba_result = np.concatenate([pred_proba , pred.reshape(-1,1)],axis=1) # reshape는 머신러닝완벽가이드 21page확인. 
# reshape에 -1 인자로 적용 -> 원래의 ndarrau와 호환되는 새로운 shape로 변환. (-1,1)이면 1개의 컬럼에 맞게 (-1)row의 수는 유동적으로 조절

print('두개의 class 중에서 더 큰 확률을 클래스 값으로 예측 \n',pred_proba_result[:3])
 
pred_proba()결과 Shape : (179, 2)
pred_proba array에서 앞 3개만 샘플로 추출 
: [[0.46175211 0.53824789]
 [0.87863924 0.12136076]
 [0.87717092 0.12282908]]
두개의 class 중에서 더 큰 확률을 클래스 값으로 예측 
 [[0.46175211 0.53824789 1.        ]
 [0.87863924 0.12136076 0.        ]
 [0.87717092 0.12282908 0.        ]]
 

sklearn predict() method 로직 구현

  • sklearn의 predict() method는 predict_prob() method에 기반해 생성된 API임
  • predict_proba() method가 반환하는 확률값을 가진 ndaaray에서 정해진 임곗값(보통 0.5)을 만족하는 ndarray의 칼럼 위치를 받아서 최종 예측 클래스로 결정.
  • 로직 구현을 위해 Binarizer 클래스를 이용

Binarizer 활용

  • threshold 변수를 특정값으로 설정하고, Binarizer 클래스를 객체로 생성.
  • 생성된 Binarizer 객체의 fit_transform() method를 이용해 넘파이 ndarray를 입력하면
  • 입력된 ndarray의 값을 지정된 threshold보다 같거나 작으면 0, 크면 1로 변환해 반환함.
In [42]:
from sklearn.preprocessing import Binarizer

X = [[ 1, -1,  2],
     [ 2,  0,  0],
     [ 0,  1.1, 1.2]]

# threshold 기준값보다 같거나 작으면 0을, 크면 1을 반환
binarizer = Binarizer(threshold=1.1)                     
print(binarizer.fit_transform(X))
 
[[0. 0. 1.]
 [1. 0. 0.]
 [0. 0. 1.]]
 

 

분류 결정 임계값 0.5 기반에서 Binarizer를 이용하여 예측값 변환

  • 이제 앞 예제에서 본 LogisticRecression 객체의 predict_proba() 메서드로 구한 각 클래스별 예측 활률값인 pred_proba 객체 변수에
  • 분류 결정 임곗값(threshold)을 0.5로 지정한 Binarizer 클래스를 적용 -> 최종 에측값을 구함
  • 마지막으로 구한 최종 예측값에 대해 get_clf_eval() 함수를 적용해 4가지 평가 지표를 출력해봄.
In [43]:
from sklearn.preprocessing import Binarizer

#Binarizer의 threshold 설정값. 분류 결정 임곗값임.  
custom_threshold = 0.5

# predict_proba( ) 반환값의 두번째 컬럼 , 즉 Positive 클래스 컬럼 하나만 추출하여 Binarizer를 적용
pred_proba_1 = pred_proba[:,1].reshape(-1,1)

binarizer = Binarizer(threshold=custom_threshold).fit(pred_proba_1) 
custom_predict = binarizer.transform(pred_proba_1)

get_clf_eval(y_test, custom_predict)
 
오차 행렬
[[104  14]
 [ 13  48]]
정확도: 0.8492, 정밀도: 0.7742, 재현율: 0.7869
 

 

분류 결정 임계값 0.4 기반에서 Binarizer를 이용하여 예측값 변환

In [44]:
# Binarizer의 threshold 설정값을 0.4로 설정. 즉 분류 결정 임곗값을 0.5에서 0.4로 낮춤  
custom_threshold = 0.4
pred_proba_1 = pred_proba[:,1].reshape(-1,1)
binarizer = Binarizer(threshold=custom_threshold).fit(pred_proba_1) 
custom_predict = binarizer.transform(pred_proba_1)

get_clf_eval(y_test , custom_predict)
 
오차 행렬
[[98 20]
 [10 51]]
정확도: 0.8324, 정밀도: 0.7183, 재현율: 0.8361
 

 

여러개의 분류 결정 임곗값을 변경하면서 Binarizer를 이용하여 예측값 변환

In [45]:
# 테스트를 수행할 모든 임곗값을 리스트 객체로 저장. 
thresholds = [0.4, 0.45, 0.50, 0.55, 0.60]

def get_eval_by_threshold(y_test , pred_proba_c1, thresholds):
    # thresholds list객체내의 값을 차례로 iteration하면서 Evaluation 수행.
    for custom_threshold in thresholds:
        binarizer = Binarizer(threshold=custom_threshold).fit(pred_proba_c1) 
        custom_predict = binarizer.transform(pred_proba_c1)
        print('임곗값:',custom_threshold)
        get_clf_eval(y_test , custom_predict)

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
임곗값: 0.45
오차 행렬
[[103  15]
 [ 12  49]]
정확도: 0.8492, 정밀도: 0.7656, 재현율: 0.8033
임곗값: 0.5
오차 행렬
[[104  14]
 [ 13  48]]
정확도: 0.8492, 정밀도: 0.7742, 재현율: 0.7869
임곗값: 0.55
오차 행렬
[[109   9]
 [ 15  46]]
정확도: 0.8659, 정밀도: 0.8364, 재현율: 0.7541
임곗값: 0.6
오차 행렬
[[112   6]
 [ 16  45]]
정확도: 0.8771, 정밀도: 0.8824, 재현율: 0.7377
 

 

precision_recall_curve( ) 를 이용하여 임곗값에 따른 정밀도-재현율 값 추출

In [46]:
from sklearn.metrics import precision_recall_curve

# 레이블 값이 1일때의 예측 확률을 추출 
pred_proba_class1 = lr_clf.predict_proba(X_test)[:, 1] 

# 실제값 데이터 셋과 레이블 값이 1일 때의 예측 확률을 precision_recall_curve 인자로 입력 
precisions, recalls, thresholds = precision_recall_curve(y_test, pred_proba_class1 )
print('반환된 분류 결정 임곗값 배열의 Shape:', thresholds.shape)
print('반환된 precisions 배열의 Shape:', precisions.shape)
print('반환된 recalls 배열의 Shape:', recalls.shape)

print("thresholds 5 sample:", thresholds[:5])
print("precisions 5 sample:", precisions[:5])
print("recalls 5 sample:", recalls[:5])

#반환된 임계값 배열 로우가 147건이므로 샘플로 10건만 추출하되, 임곗값을 15 Step으로 추출. 
thr_index = np.arange(0, thresholds.shape[0], 15)
print('샘플 추출을 위한 임계값 배열의 index 10개:', thr_index)
print('샘플용 10개의 임곗값: ', np.round(thresholds[thr_index], 2))

# 15 step 단위로 추출된 임계값에 따른 정밀도와 재현율 값 
print('샘플 임계값별 정밀도: ', np.round(precisions[thr_index], 3))
print('샘플 임계값별 재현율: ', np.round(recalls[thr_index], 3))
 
반환된 분류 결정 임곗값 배열의 Shape: (143,)
반환된 precisions 배열의 Shape: (144,)
반환된 recalls 배열의 Shape: (144,)
thresholds 5 sample: [0.10394781 0.10395007 0.10397544 0.10773598 0.10892335]
precisions 5 sample: [0.38853503 0.38461538 0.38709677 0.38961039 0.38562092]
recalls 5 sample: [1.         0.98360656 0.98360656 0.98360656 0.96721311]
샘플 추출을 위한 임계값 배열의 index 10개: [  0  15  30  45  60  75  90 105 120 135]
샘플용 10개의 임곗값:  [0.1  0.12 0.14 0.19 0.28 0.4  0.56 0.67 0.82 0.95]
샘플 임계값별 정밀도:  [0.389 0.44  0.466 0.539 0.647 0.729 0.836 0.949 0.958 1.   ]
샘플 임계값별 재현율:  [1.    0.967 0.902 0.902 0.902 0.836 0.754 0.607 0.377 0.148]
 
 

임곗값의 변경에 따른 정밀도-재현율 변화 곡선을 그림

In [47]:
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
%matplotlib inline

def precision_recall_curve_plot(y_test , pred_proba_c1):
    # threshold ndarray와 이 threshold에 따른 정밀도, 재현율 ndarray 추출. 
    precisions, recalls, thresholds = precision_recall_curve( y_test, pred_proba_c1)
    
    # X축을 threshold값으로, Y축은 정밀도, 재현율 값으로 각각 Plot 수행. 정밀도는 점선으로 표시
    plt.figure(figsize=(8,6))
    threshold_boundary = thresholds.shape[0]
    plt.plot(thresholds, precisions[0:threshold_boundary], linestyle='--', label='precision')
    plt.plot(thresholds, recalls[0:threshold_boundary],label='recall')
    
    # threshold 값 X 축의 Scale을 0.1 단위로 변경
    start, end = plt.xlim()
    plt.xticks(np.round(np.arange(start, end, 0.1),2))
    
    # x축, y축 label과 legend, 그리고 grid 설정
    plt.xlabel('Threshold value'); plt.ylabel('Precision and Recall value')
    plt.legend(); plt.grid()
    plt.show()
    
precision_recall_curve_plot( y_test, lr_clf.predict_proba(X_test)[:, 1] )
 
 

F1 Score

  • F1 score : 정밀도 + 재현율 (결합)
    • 정밀도와 재현율이 어느 한쪽으로 치우치지 않는 수치를 나타낼 때, 상대적으로 높은 값을 가짐
  • $$ F1 = \frac {2} {\frac {1} {recall} + \frac {1} {precision}} = 2*\frac {presision*recall} {precision+recall} $$
    • ex) A 예측 모델 : 정밀도가 0.9, 재현율이 0.1 -> F1 score = 0.18
    • ex) B 예측 모델 : 정밀도가 0.5, 재현율이 0.5 -> F1 score = 0.5 (우수함)
  • sklearn에서는 F1 score를 구하기 위해 f1_score() API를 제공
 
In [48]:
# 정밀도/재현율 예제에서 학습/예측한 RogisticRegression 기반 titanic 생존자 모델의 F1 score를 구함
from sklearn.metrics import f1_score 
f1 = f1_score(y_test , pred)
print('F1 스코어: {0:.4f}'.format(f1))
 
F1 스코어: 0.7805
 
In [49]:
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))

thresholds = [0.4 , 0.45 , 0.50 , 0.55 , 0.60]
pred_proba = lr_clf.predict_proba(X_test)
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
 

ROC Curve와 AUC

  • ROC(Receiver Operation Characteristic Curve) : FPR(False Positive Rate)이 변할 때 TPR(True Positive Rate)이 어떻게 변하는지를 나타내는 곡선
  • x축 : FPR, y축 : TPR
  • AUC는 ROC Curve에 기반함.
  • TPR = TP / (FN + TP) = 재현율 = 민감도
  • 민감도에 대응하는 지표로 TNR(True Negative Rate) (= 특이성) 이 있음
  • TNR = TN / (FP + TN)
    • 민감도(TPR, 재현율) : 실제값 Positive(양성)가 정확히 예측되어야 하는 수준을 나타냄
      • ex) 질병이 있는 사람은 질병이 있는 것으로 양성 판정
    • 특이성(TNR)은 실제값 Negative(음성)가 정확히 예측되어야 하는 수준을 나타냄
      • ex) 질병이 없는 건강한 사람은 질병이 없는 것으로 음성 판정
  • FPR = FP / (FP + TN) = 1 - TNR = 1 - 특이성
  • 가운데 직선 = ROC 곡선의 최저 값
In [51]:
from sklearn.metrics import roc_curve

# 레이블 값이 1일때의 예측 확률을 추출 
pred_proba_class1 = lr_clf.predict_proba(X_test)[:, 1] 

fprs , tprs , thresholds = roc_curve(y_test, pred_proba_class1)
# 반환된 임곗값 배열에서 샘플로 데이터를 추출하되, 임곗값을 5 Step으로 추출. 
# thresholds[0]은 max(예측확률)+1로 임의 설정됨. 이를 제외하기 위해 np.arange는 1부터 시작
thr_index = np.arange(1, thresholds.shape[0], 5)
print('샘플 추출을 위한 임곗값 배열의 index:', thr_index)
print('샘플 index로 추출한 임곗값: ', np.round(thresholds[thr_index], 2))

# 5 step 단위로 추출된 임계값에 따른 FPR, TPR 값
print('샘플 임곗값별 FPR: ', np.round(fprs[thr_index], 3))
print('샘플 임곗값별 TPR: ', np.round(tprs[thr_index], 3))
 
샘플 추출을 위한 임곗값 배열의 index: [ 1  6 11 16 21 26 31 36 41 46 51]
샘플 index로 추출한 임곗값:  [0.97 0.65 0.63 0.56 0.45 0.4  0.35 0.15 0.13 0.11 0.11]
샘플 임곗값별 FPR:  [0.    0.017 0.034 0.076 0.127 0.169 0.203 0.466 0.585 0.686 0.797]
샘플 임곗값별 TPR:  [0.033 0.639 0.721 0.754 0.803 0.836 0.885 0.902 0.934 0.967 0.984]
 
In [52]:
from sklearn.metrics import roc_curve

# 레이블 값이 1일때의 예측 확률을 추출 
pred_proba_class1 = lr_clf.predict_proba(X_test)[:, 1] 
print('max predict_proba:', np.max(pred_proba_class1))

fprs , tprs , thresholds = roc_curve(y_test, pred_proba_class1)
print('thresholds[0]:', thresholds[0])
# 반환된 임곗값 배열 로우가 47건이므로 샘플로 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))

# 5 step 단위로 추출된 임계값에 따른 FPR, TPR 값
print('샘플 임곗값별 FPR: ', np.round(fprs[thr_index], 3))
print('샘플 임곗값별 TPR: ', np.round(tprs[thr_index], 3))
 
max predict_proba: 0.9650902019156496
thresholds[0]: 1.9650902019156495
샘플 추출을 위한 임곗값 배열의 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]
샘플 임곗값별 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]
 
In [53]:
def roc_curve_plot(y_test , pred_proba_c1):
    # 임곗값에 따른 FPR, TPR 값을 반환 받음. 
    fprs , tprs , thresholds = roc_curve(y_test ,pred_proba_c1)

    # ROC Curve를 plot 곡선으로 그림. 
    plt.plot(fprs , tprs, label='ROC')
    # 가운데 대각선 직선을 그림. 
    plt.plot([0, 1], [0, 1], 'k--', label='Random')
    
    # FPR X 축의 Scale을 0.1 단위로 변경, X,Y 축명 설정등   
    start, end = plt.xlim()
    plt.xticks(np.round(np.arange(start, end, 0.1),2))
    plt.xlim(0,1); plt.ylim(0,1)
    plt.xlabel('FPR( 1 - Sensitivity )'); plt.ylabel('TPR( Recall )')
    plt.legend()
    plt.show()
    
roc_curve_plot(y_test, lr_clf.predict_proba(X_test)[:, 1] )
 
 
In [54]:
from sklearn.metrics import roc_auc_score

### 아래는 roc_auc_score()의 인자를 잘못 입력한 것으로, 책에서 수정이 필요한 부분입니다. 
### 책에서는 roc_auc_score(y_test, pred)로 예측 타겟값을 입력하였으나 
### roc_auc_score(y_test, y_score)로 y_score는 predict_proba()로 호출된 예측 확률 ndarray중 Positive 열에 해당하는 ndarray입니다. 

#pred = lr_clf.predict(X_test)
#roc_score = roc_auc_score(y_test, pred)

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
 
In [56]:
def get_clf_eval(y_test, pred=None, pred_proba=None):
    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_score(y_test,pred)
    # ROC-AUC 추가 
    roc_auc = roc_auc_score(y_test, pred_proba)
    print('오차 행렬')
    print(confusion)
    # ROC-AUC print 추가
    print('정확도: {0:.4f}, 정밀도: {1:.4f}, 재현율: {2:.4f},\
          F1: {3:.4f}, AUC:{4:.4f}'.format(accuracy, precision, recall, f1, roc_auc))