본문 바로가기
개념정리/머신러닝

머신러닝 - 오차행렬 , 정확도 , 정밀도, 재현율

by 화영쌤 2023. 5. 15.
728x90

▷ 정확도

  • 실제 데이터에서 예측 데이터가 얼마나 같은지를 판단하는 지표
  • 정확도 = 예측결과가 동일한 데이터 건수 / 전체 예측 데이터 건수 = ( TN + TP ) / ( TN + FP + FN + TP )

▷ 오차행렬

  • 학습된 분류 모델이 예측을 수행하면서 얼마나 헷갈리고 있는지도 함께 보여주는 지표
  • 이진 분류의 예측 오류가 얼마인지와 더불어 어떠한 유형의 예측 오류가 발생하고 있는지를 함께 나타내는 지표
  • 4분면 행렬에서 실제 레이블 클래스 값과 예측 레이블 클래스 값이 어떠한 유형을 가지고 매핑되는지를 나타냄
클래스 구분 예측 클래스 ( Predicted Class ) 
실제 클래스 (Actual Class)   Negative(0) Positive(1)
Negative(0) TN (True Negative) FP (False Positive)
Positive(1) FN (False Negative) TP (True Positive)

▷ 정밀도

  • 예측을 Positive 로 한 대상 중에 예측과 실제 값이 Positive 로 일치한 데이터의 비율
  • TP / ( FP + TP) , TP를 높이고 FP를 낮추는데 초점을 맞춤
  • Positive 예측 성능을 더욱 정밀하게 측정하기 위한 평가 지표 , 양성 예측도라고 불림
  • 실제 Negative 음성 데이터를 Positive 양성으로 잘못 판단하게 되면 업무상 큰 영향이 발생하는 경우 ( ex) 암 환자)

▷ 재현율

  • 실제 값이 Positive 인 대상 중에 예측과 실제 값이 Positive 로 일치한 데이터의 비율
  • TP / ( FN + TP) , TP를 높이고 FN를 낮추는데 초점을 맞춤
  • 민감도 ( Sensitivity ) 또는 TPR ( True Positive Rate ) 라고 불림
  • 실제 Positive 양성 데이터를 Negative 음성으로 잘못 판단하게 되면 업무상 큰 영향이 발생하는 경우 ( ex)스팸 메일, 보험 사기)

▷데이터에 적용하기

- 데이터 불러오기 & 함수 생성하기 ( 정확도 : 83.2% , 정밀도 : 75.4% , 재현율 : 75.4% )

# 데이터 불러오기
df = pd.read_csv('titanic_train.csv')
y = df['Survived']
x = df.drop(columns='Survived')
x = transform_features(x)
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=11)

# 함수 생성하기
def get_clf_eval(y_test,pred):
    # 관련 모듈 import 하기
    from sklearn.metrics import accuracy_score,precision_score,recall_score,confusion_matrix
    # 오차행렬
    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(f'정확도 : {accuracy:.4f} 정밀도 : {precision:.4f} 재현율 : {recall:.4f}')

get_clf_eval(y_test,pred)

 

- 로지스틱 회귀 기반으로 평가 수행하기 ( 정확도 : 84.9% , 정밀도 : 77.4% , 재현율 : 78.6% )

# 관련 모듈 import 하기
from sklearn.linear_model import LogisticRegression

# LogisticRegression 객체 생성하기
lr_clf = LogisticRegression(max_iter=200)

# LogisticRegression 학습하기
lr_clf.fit(x_train,y_train)

# LogisticRegression 예측하기
pred = lr_clf.predict(x_test)

get_clf_eval(y_test,pred)


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

  • 분류하려는 업무의 특성상 특별히 강조돼야 할 경우 분류의 결정 임계값을 조정해 정밀도 또는 재현율의 수치를 높이는 방법
  • 정밀도와 재현율은 상호 보완적인 평가 지표이기 때문에 어느 한쪽을 강제로 높이면 다른 하나의 수치가 떨어짐
# LogisticRegression 객체 생성하기
pred_proba = lr_clf.predict_proba(x_test)

# LogisticRegression 예측하기
pred = lr_clf.predict(x_test)

# 예측 확률 array 와 예측 결과값 array 를 병합(concatenate)해 예측 확률과 결과값 확인하기
np.concatenate([pred_proba,pred.reshape(-1,1)],axis=1)

- Binarizer ( 정확도 : 87.7% , 정밀도 : 88.2% , 재현율 : 73.7% )

# 관련 모듈 import 하기
from sklearn.preprocessing import Binarizer

# Binarizer 객체 생성하기
# threshold 설정값(분류 결정 임계값) 을 0.4 로 설정하기
binarizer = Binarizer(threshold=0.6)

# Binarizer 학습하기 - fit_transform() 이용
pred_1 = binarizer.fit_transform(pred_proba[:,1].reshape(-1,1))

# 함수 적용하기
get_clf_eval(y_test,pred_1)

 

- precision_recall_curve 

# 관련 모듈 import 하기
from sklearn.metrics import precision_recall_curve

# 실제값 데이터 세트와 레이블 값이 1일 때의 예측 확률을 precision_recall_curve 인자로 입력하기
precisions,recalls,thresholds = precision_recall_curve(y_test,pred_proba[:,1])

+ 시각화하기

# 관련 모듈 import 하기
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
%matplotlib inline

# 함수 생성하기
def precision_recall_curve_plot(y_test,pred_proba):
    # threshold ndarray 와 이 threshold에 따른 정밀도, 재현율 ndarray 추출하기
    precisions,recalls,thresholds = precision_recall_curve(y_test,pred_proba)
    plt.figure(figsize=(8,6))
    threshold_boundary = thresholds.shape[0]
    # x축을 threshold 값으로, y축은 정밀도 값으로 plot 수행, 정밀도는 점선으로 표시 
    plt.plot(thresholds,
             precisions[0:threshold_boundary],
             linestyle='--',
             label='precision')
    # x축을 threshold 값으로, y축은 재현율 값으로 plot 수행
    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))
    # 범례 설정하기
    plt.legend()
    # 눈금 설정하기
    plt.grid()
    plt.show()
precision_recall_curve_plot(y_test,pred_proba[:,1])


F1 스코어

  • 정밀도와 재현율을 결합한 지표
  • 정밀도와 재현율이 어느 한쪽으로 치우치지 않는 수치를 나타낼 때 상대적으로 높은 값을 가짐
# 관련 모듈 import 하기
from sklearn.metrics import f1_score

# f1_score 적용하기
f1 = f1_score(y_test,pred)
print(f'F1 스코어 : {f1:.4f}')


ROC 곡선

  • 수신자 판단 곡선, 이진 분류 모델의 예측 성능을 판단하는 지표
  • FPR (False Positive Rate) 이 변할 때 TPR (True Positive Rate , 재현율(민감도)) 이 어떻게 변하는지를 나타내는 곡선
  • AUC(Area Under Curve) : ROC 곡선 밑의 면적을 구한 것 , 일반적으로 1에 가까울수록 좋은 수치
# 관련 모듈 import 하기
from sklearn.metrics import roc_curve

# roc_curve 적용하기
fprs,tprs,thresholds = roc_curve(y_test,pred_proba(x_test)[:,-1])

+ 시각화 하기

# 함수 생성하기
def roc_curve_plot(y_test,pred_proba):
    # 임계값에 따른 FPR, TPR 값을 반환받기
    fprs,tprs,thresholds = roc_curve(y_test,pred_proba)
    # ROC 곡선을 그래프 곡선으로 그리기
    plt.plot(fprs,tprs,label='ROC')
    # k는 black을 뜻함 , 가운데 대각선 직선을 그리기
    plt.plot([0,1],[0,1],'k--',label='Random')
    # FPR x 축의 scale 을 0.1 단위로 변경하기
    start,end = plt.xlim()
    plt.xticks(np.round(np.arange(start,end,0.1),2))
    # x축 눈금 설정하기
    plt.xlim(0,1)
    # y축 눈금 설정하기
    plt.ylim(0,1)
    # 범례 표시하기
    plt.legend()
    plt.show()
    
roc_curve_plot(y_test,pred_proba)


▷ 함수 생성하기 ( 임계값, 오차행렬, 정확도, 정밀도, 재현율,  F1,  AUC )

def get_clf_eval(y_test,pred=None,pred_proba=None):
    from sklearn.metrics import accuracy_score,precision_score,recall_score,confusion_matrix,f1_score,roc_auc_score
    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_score(y_test,pred_proba)
    print('오차행렬')
    print(confusion)
    print(f'정확도 : {accuracy:.4f} 정밀도 : {precision:.4f} 재현율 : {recall:.4f} F1 : {f1:.4f} AUC : {roc_auc:.4f}')

def get_eval_by_threshold(y_test,pred_proba,thresholds):
    from sklearn.preprocessing import Binarizer
    for threshold in thresholds:
        pred = Binarizer(threshold=threshold).fit_transform(pred_proba)
        print('임계값 : ',threshold)
        get_clf_eval(y_test,pred,pred_proba)
# 임계값 설정하기
thresholds = [0.4,0.45,0.5,0.55,0.6]
pred_proba = lr_clf.predict_proba(x_test)[:,1].reshape(-1,1)
get_eval_by_threshold(y_test,pred_proba,thresholds)