데이터 한 그릇

머신러닝 분류 평가 보충 본문

머신러닝/분류

머신러닝 분류 평가 보충

장사이언스 2021. 7. 27. 17:49

정밀도 재현율 트레이드 오프

정밀도 / 재현율 트레이드 오프 (Trade-off)

  • 업무에 따라 정밀도/재현율 중요도 다름
  • 분류하려는 업무 특성사 정밀도 도는 재현율이 특별히 강조되어야 할 경우
  • 분류의 결정 임계값(Threshold)을 조정해서
  • 정밀도 도는 재현율의 수치를 높일 수 있음
  • 그러나 정밀도와 재현율은 상호 보완적인 평가 지표이기 때문에
  • 어느 한쪽을 강제로 높이면 다른 하나의 수치는 떨어지는데
  • 이를 정밀도/재현율의 트레이드 오프라고 함
  • 사이킷런에서는 분류 결정 임계값을 조절해서
  • 정밀도와 재현율의 성능 수치를 상호 보완적으로 조정 가능

분류 결정 임계값

  • Positive 예측값을 결정하는 확률의 기준
  • 임계값을 낮출수록 True 값이 많아짐

사이킷런의 분류 알고리즘에서 결정 확률을 구하는 방식

  • 예측 데이터가 특정 레이블(결정 클래스 값)에 속하는지를 계산하기 위해
  • 먼저 개별 레이블 별로 결정 확률을 구하고
  • 예측 확률이 큰 레이블 값으로 예측
  • 예: 이진 분류 모델
    • 특정 데이터가 0이 될 확률 : 10%
    • 1이 될 확률 : 90%로 예측한 경우
    • 최종 예측은 더 큰 확률을 가진 1로 예측
  • 일반적으로 이진 분류에서는 이 임계값을 0.5(50%)로 정하고
  • 기준값보다 확률이 크면 Positive
  • 작으면 Negative로 결정
result = np.concatenate([pred_proba, pred.reshape(-1,1)],axis = 1)

 

임계값은 보통 0.5로 고정. target 데이터의 레이블 각각이 나올 확률을 구하고 그 확률이 0.5 이상이면 positive 로 예측, 낮으면negative 로 예측.

위 코드는 확률과 각 레이블에 대해서 예측한 결과

 

Binarizer 로 임계값 조정

 

from sklearn.preprocessing import Binarizer
X = [[1,-1,2],
    [2,0,0],
    [0,1.1,1.2]]

binarizer = Binarizer(threshold = 1.1)
print(binarizer.fit_transform(X))

 

threshold 를 1.1 로 지정하면, 1.1 이상이면 positive, 1.1 이하이면 negative 로 분류한다.

 

임계값 0.5

 

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_eva(y_test, custom_predict)

 

임계값 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_eva(y_test, custom_predict)

 

여기서 주의할게 pred_proba에서 1번째 열을 꺼내와서 그 열에서 threshold와 비교한다는 점이다.

내가 착각한 지점은 [사망확률, 생존확률] 이 존재하면, 임계값과 이 두 확률을 비교해서 더 높은 확률을 택하는 걸로 생각했다.

완전히 이상한 착각을한 셈이다.

생존칼럼이나 사망칼럼 중 하나를 택하여 뽑고 그것을 binarizer 에 넣어서 비교해야만 custom_pred 가 도출이 된다.

 

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

 

 

thresholds= [0.4,0.45,0.5,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('\n임계값 : ', custom_threshold)
        
        get_clf_eva(y_test, custom_predict)
        
get_eval_by_threshold(y_test, pred_proba_1, thresholds)

 

임계값이 높아질수록 positive로 예측하는 횟수가 적어지기 때문에 tp 가 줄어든다.negative 를 많이 하기 때문에 fn 이 높아진다. 따라서 재현율은 낮아진다.

반면에 정밀도는 positive 로 예측한 횟수가 줄어들기 때문에 fp 의 개수가 줄어들어서 높아진다.

따라서 정밀도와 재현율은 서로 트레이드 오프 관계임을 알 수 있다.

 

임계값의 변화에 따른 정밀도-재현율 변환 곡선을 그래프로 표현

 

import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
%matplotlib inline


def precision_recall_curve_plot(y_test, pred_proba_c1): #curve 함수는 확률이 필요하기 때문에
    precisions, recalls, thresholds = precision_recall_curve(y_test, pred_proba_c1)
    
    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')
    
    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

  • 정밀도와 재현율을 결합한 지표
  • 정밀도와 재현율이 어느 한쪽으로 치우치지 않는 수치를 나타낼때
  • 높은 값을 가짐
  • 예: 2개의 예측 모델 비교 A 예측 모델
    • 정밀도 : 0.9
    • 재현율 : 0.1 (극단적 차이)
    • F1 스코어 : 0.18
    B 예측 모델
    • 정밀도 : 0.5
    • 재현율 : 0.5 (큰 차이 없음)
    • F1 스코어 : 0.5
    B 모델의 F1 스코어가 A 모델에 비해 매우 우수
  •  

ROC Curve와 AUC

**이진 분류** 모델을 평가할 때 사용한다.

ROC 곡선

  • FPR이 변할 때 TPR 이 어떻게 변하는지를 나타내는 곡선
  • 양성으로 잘못 판단한 것에 대한 진짜 양성의 비율을 나타내는 곡선 (정의)

ROC(Receiver Operation Characterisic Curve)

  • 임계값을 1부터 0까지 변화시키면서 FPR(X축)을 구하고
  • FPR(X축)의 변화에 따른 TPR(Y축)을 구하는 곡선
  • 머신러닝의 이진 분류 모델의 예측 성능을 판단하는 평가 지표

TPR(True Positie Rate) : 재현율(민감도)

  • 실제 Positive를 Positive로 예측한 비율
  • 질병이 있는 사람을 질병이 있는 것으로 양성 판정
  • 값이 클수록 좋음 (양성을 잘 예측)

FPR(False Positive Rate)

  • 실제는 Negative인데 Positive로 잘못 예측한 비율
  • 1 - 특이성

TNR(True Negative Rate) : 특이성 (Specificity)

  • 실제 음성인데 음성으로 예측한 비율
  • 질병이 없는 사람을 질병이 없는 것으로 음성 판정
  • 값이 클수록 좋음 (음성을 잘 예측)

사이킷런의 roc_curve() APi 이용해서 타이타닉 생존자 예측 모델의 FPR, TPR, 임계값 구하기

정밀도와 재현율에서 학습한 LogisticRegression의 predic_proba() 결과 이용

roc_curve(실제 데이터, 예측 확률)

  • FPR, TRP, thresholds 반환
from sklearn.metrics import roc_curve

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

fprs, tprs, thresholds = roc_curve(y_test, prd_proba_class1)

thr_index = np.arange(0, thresholds.shape[0], 5)
print('샘플 추출을 위한 임계값 배열의 index : ', thr_index)
print('샘플임계값 : ', np.round(thresholds[thr_index], 2))

# 5단계 단위로 추출된 임계값에 따른 FPR, TPR 값 출력
print('샘플 임계값 FPR : ', np.round(fprs[thr_index], 3))
print('샘플 임계값 TPR : ', np.round(tprs[thr_index], 3))

# 결과
# 임계값이 1에 가까운 값에서 점점 작아지면서 FPR이 점점 커짐
# FPR이 조금씩 커질 때 TPR은 가파르게 증가

 

값 확인

 

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.savefig('graph_roc_auc')
    plt.show()
    
roc_curve_plot(y_test, lr_clf.predict_proba(X_test)[:, 1] )

# 그래프 설명
# 일반적으로 곡선 자체는 RPR과 TRP의 변화값을 보든데 이용하고
# 분류의 성능 지표로 사용되는 것은 ROC 곡선 면적에 기반한 AUC 값으로 결정
# AUC(Area Under Curve) 값은 ROC 곡선 밑의 면적을 구한 것으로
# 일반적으로 1에 가까울수록 좋음
# AUC 수치가 커지려면 FPR이 작은 상태에서 얼마나 큰 TPR을 얻을 수 있느냐가 관건
# 가운데 직선에서 멀어지고 왼족 상단 모서리 쪽으로 가파르게 곡선이 이동할 수록
# 직사각형에 가까운 곡선이 되어 면적이 1에 가까워지는
# 좋은 ROC AUC 성능 수치를 얻게 됨
# 가운데 직선은 랜덤 수준의 이진 분류 AUC 값으로 0.5
# 따라서 보통의 분류는 0.5이상의 AUC 값을 가짐

 

 

ROC_AUC 그래프 그리기

선 밑의 넓이가 1에 가까울수록 성능이 좋은 것

중간 선과 거리가 멀어야 좋은 성능의 모델

Comments