본문 바로가기

머신러닝

파이썬 머신러닝 완벽가이드 - 3장

https://stackoverflow.com/questions/36543137/whats-the-difference-between-predict-proba-and-decision-function-in-scikit-lear/36543588

 

What's the difference between predict_proba and decision_function in scikit-learn?

I'm studying a scikit-learn example (Classifier comparison) and got confused with predict_proba and decision_function. They plot the classification results by drawing the contours using either Z ...

stackoverflow.com

 

https://nittaku.tistory.com/295

 

14. 다중 분류 모델의 성능측정 - Performance Measure( ACU, F1 score)

캡쳐 사진 및 글작성에 대한 도움 출저 : 유튜브 - 허민석님 머신러닝을 가지고 모델을 만들어 예측하다보면, 하나의 꼬리를 가지고 여러 classifier로 만들 수 있다. 예를 들어, kNN이나 Decision Tree

nittaku.tistory.com

 

https://neosla.tistory.com/18

 

[모델 평가] Confusion matrix (TP, TN, FP, FN) 및 단일/다중 클래스 평가 방법 (1)

본 포스팅에서는 단일 및 다중 분류 모델에서, 모델의 성능을 평가하기 위한 다양한 performance measures 에 대하여 포스팅한다. 1. 목적 분류 모델을 평가 하기 위해서는 다양한 평가 기준들이 존

neosla.tistory.com

 

 

회귀 : 오차 평균값으로 성능 평가

분류는 복잡

 

분류 성능 평가 지표

정확도, 오차행렬, 정밀도(precision), 재현율 (recall), f1 score, ROC AUC

 

1. 정확도

모델 성능 왜곡 가능

데이터가 불균형할 수 있기 때문이다.

90개가 0이고 10개만 1일 때 모두 0으로 예측하면 정확도 90%

 

2. 오차행렬

TN FP
FN TP

 

이진 분류에서는 많은 데이터 중에서 중점적으로 찾아야 하는 매우 적은 수의 결괏값에 positive를 설정해 1값을 부여
예를 들어 사기 행위 예측 모델에서는 사기 행위가 positive로 1. -> 목적에 따라 설정해주자.

 

 

3. 정밀도와 재현율

정밀도 = TP / (FP+TP)

재현율 = TP / (FN+TP)

 

정밀도는 내 예측의 정확도 -> 분모에 P로 '예측' 한거 들어감.

 

재현율은 실제 값이 Positive인  대상 중에 예측과 실제 값이 1로 일치한 데이터의 비율

일치한 -> 실제로 재현한다   얼마나 실제를 잘 재현해냈느냐   -> TPR

 

 

재현율이 중요한 경우는 실제 양성인 데이터를 음성으로 잘못판단하게 되면 큰 영향이 발생하는 경우

-> 암판단 모델  /  실제 양성환자를 음성으로 잘못판단하면 사람 죽음.

 

정밀도가 더 중요한 경우

스팸메일 여부 -> 실제 스팸메일을 일반 메일로 분류해도 불편을 못느끼지만 실제로 음성(일반 메일)을 양성(스팸)으로 분류하면 중요 메일을 못받을 수 있음.   -> FP를 줄이는데 초점

 

재현율, 정밀도 모두 TP를 높이는데 초점을 맞추지만 

재현율은 FN , 정밀도는 FP를 낮추는데 초점을 맞추기 때문에 trade off 존재

 

사이킷런은 개별 데이터별로 예측 확률을 반환하는 메서드인 predict_proba()를 제공

학습이 완료된 classifier 객체에서 호출이 가능하며 X_test를 인자로 가짐

(m,n)크기로 반환 n:클래스 유형 / 첫번째는 0확률

 

pred_proba = lr_clf.predict_proba(X_test)
pred = lr_clf.predict(X_test)
print(pred_proba.shape)
print(pred_proba[:3])

(179, 2)
[[0.46162417 0.53837583]
 [0.87858538 0.12141462]
 [0.87723741 0.12276259]]

 

Binarizer 클래스 : 임계값을 설정하고 임계값보다 같거나 작으면 0으로 예측

from sklearn.preprocessing import Binarizer

custom_threshold = 0.5
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)


confusion matrix
[[104  14]
 [ 13  48]]
acc : 0.8491620111731844  precison : 0.7741935483870968 recall : 0.7868852459016393

 

임계값을 낮추면 재현율이 올라감. 정밀도는 떨어짐

왜냐하면 positive로 예측을 더 너그럽게 하기 때문에 True 값이 많아짐.

임계값을 낮춤 -> 더 많이 positive로 예측 -> TN은 작아지고 FN도 줄음 -> FP, TP가 증가

positive 예측 값이 많이 하다 보니 실제 양성을 음성으로 예측하는 횟수가 상대적으로 줄어듦(FN감소-분모가 작아짐) -> 재현율 증가

 

thresholds = [0.4,0.45,0.50,0.55,0.60]

def get_eval_by_threshold(y_test, pred_proba_c1, thresholds):
    for custom_threshold in thresholds:
        binarizer = Binarizer(threshold=custom_threshold).fit(pred_proba_c1)
        custom_predict = binarizer.transform(pred_proba_c1)
        print(f'임계값 : {custom_threshold}')
        get_clf_eval(y_test, custom_predict)
        print()
        
get_eval_by_threshold(y_test, pred_proba[:,1].reshape(-1,1), thresholds)
임계값 : 0.4
confusion matrix
[[99 19]
 [10 51]]
acc : 0.8379888268156425  precison : 0.7285714285714285 recall : 0.8360655737704918

임계값 : 0.45
confusion matrix
[[103  15]
 [ 12  49]]
acc : 0.8491620111731844  precison : 0.765625 recall : 0.8032786885245902

임계값 : 0.5
confusion matrix
[[104  14]
 [ 13  48]]
acc : 0.8491620111731844  precison : 0.7741935483870968 recall : 0.7868852459016393

임계값 : 0.55
confusion matrix
[[109   9]
 [ 15  46]]
acc : 0.8659217877094972  precison : 0.8363636363636363 recall : 0.7540983606557377

임계값 : 0.6
confusion matrix
[[112   6]
 [ 16  45]]
acc : 0.8770949720670391  precison : 0.8823529411764706 recall : 0.7377049180327869

 

 

precision_recall_curve()는 예측 모델의 임곗값별 정밀도와 재현율을 반환

입력 : 

y_test, 레이블 값이 1일 때의 예측 확률 값(predict_proba(X_test)[:, 1])

반환 : numpy

 

from sklearn.metrics import precision_recall_curve

pred_proba_class1 = lr_clf.predict_proba(X_test)[:, 1]

precisions, recalls, thresholds = precision_recall_curve(y_test, pred_proba_class1)
print(f'반환된 임계값 배열의 shape {thresholds.shape}')

thr_index = np.arange(0, thresholds.shape[0], 15)
print(f'임계값 배열의 index 10개 {thr_index}')
print(f'샘플용 10개 임계값: {np.round(thresholds[thr_index],2)}')

print(f'precision : {np.round(precisions[thr_index],2)}')
print(f'recall : {np.round(recalls[thr_index],2)}')
반환된 임계값 배열의 shape (143,)
임계값 배열의 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]
precision : [0.39 0.44 0.47 0.54 0.65 0.73 0.84 0.95 0.96 1.  ]
recall : [1.   0.97 0.9  0.9  0.9  0.84 0.75 0.61 0.38 0.15]
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
%matplotlib inline

def precicison_recall_curve_plot(y_test, pred_proba_c1):
    precisions, recalls, thresholds = precision_recall_curve(y_test, pred_proba_c1)
    
    plt.figure(figsize=(8,6))
    threshold_boundary = thresholds.shape[0]
    print(thresholds)
    print(threshold_boundary)
    plt.plot(thresholds, precisions[0:threshold_boundary], linestyle='-', label='precision')
    plt.plot(thresholds, recalls[0:threshold_boundary], label='recalls')
    start, end = plt.xlim()
    plt.xticks(np.round(np.arange(start, end,0.1),2))
    plt.legend()
    plt.grid()
    
precicison_recall_curve_plot(y_test, lr_clf.predict_proba(X_test)[:, 1])

4. F1 score

정밀도 + 재현율

정밀도와 재현율이 어느 한쪽으로 치우치지 않는 수치를 나타낼때 높은 수치를 가짐.

 

 

5. ROC 곡선과 AUC

이진 분류에서 중요

ROC곡선의 y좌표는 TPR (재현율)

tpr에 대응하는 지표로는 TNR(특이성) -> TN / (FP+TN)

 

ROC곡선의 x좌표는 FPR -> 1-TNP or FP / (FP+TN)

어떻게 FPR을 0~1까지 변경? -> 임계값 변경 

FPR을 0으로 만드려면 임계값을 1로 지정 -> positive 예측 기준이 매우 높기 때문에 positive 예측 불가-> 아예 positive로 예측하지 않기 때문에 FP가 0이 되어서 Fpr은 0이됨.

 

 

 

 

FPR이 작은 상태에서 얼마나 큰 TPR을 얻을 수 있느냐가 관건

from sklearn.metrics import roc_curve

pred_proba_class1 = lr_clf.predict_proba(X_test)[:, 1]

fprs, tprs, thresholds = roc_curve(y_test, pred_proba_class1)
thr_index = np.arange(1, thresholds.shape[0],5)
print(f'임계값 배열의 index 10개 {thr_index}')
print(f'샘플용 10개 임계값: {np.round(thresholds[thr_index],2)}')

print(f'precision : {np.round(fprs[thr_index],2)}')
print(f'recall : {np.round(tprs[thr_index],2)}')
임계값 배열의 index 10개 [ 1  6 11 16 21 26 31 36 41 46 51]
샘플용 10개 임계값: [0.97 0.65 0.63 0.56 0.45 0.38 0.31 0.13 0.12 0.11 0.1 ]
precision : [0.   0.02 0.03 0.08 0.13 0.19 0.24 0.58 0.62 0.75 0.81]
recall : [0.03 0.64 0.7  0.75 0.8  0.85 0.9  0.9  0.95 0.97 1.  ]

 

 

def roc_curve_plot(y_test, pred_proba_c1):
    fprs, tprs, thresholds = roc_curve(y_test, pred_proba_c1)
    plt.plot(fprs, tprs, label='ROC')
    plt.plot([0,1],[0,1], 'k--', label='Random')
    start, end = plt.xlim()
    plt.xticks(np.round(np.arange(start, end,0.1),2))
    plt.legend()
    plt.grid()
    
roc_curve_plot(y_test, pred_proba[:,1])

 

 

AUC는 1에 가까울수록 좋음

 

 

 

roc_auc_score

 

 

 

predict는 임계값을 변경 못하므로 Binarizer로 변환

from sklearn.preprocessing import Binarizer
binarizer = Binarizer(threshold=0.48)
pred_th_048 = binarizer.fit_transform(pred_proba[:,1].reshape(-1,1))