도찐개찐

[머신러닝] 06. 오차행렬 본문

PYTHON/데이터분석

[머신러닝] 06. 오차행렬

도개진 2023. 1. 3. 09:40

머신러닝의 모델평가

  • 일반적으로 머신러닝은
    • 데이터 가공/변환(전처리)
    • 모델 학습/예측
    • 평가의 과정을 거침
  • 앞의 타이타닉 예제에서 모델의 평가는 정확도만 사용했음
  • 한편, 머신러닝의 예측성능의 평가방법은 다양함
    • 회귀 - R^2, MSE평균제곱오차
    • 분류 - 혼동(오차)행렬, 크로스엔트로피, 최대우도, ROC, AUC, F1스코어

정확도의 함정

  • 앞의 타이타닉 생존자 ML예제의 정확도는 평균 80%였음
  • 그런데 정확도 지표만으로 ML 모델의 성능을 파악하기에는 다소 문제가 있음 - 왜곡의 위험
  • 즉, 탐색적 분석을 시행했을때 성별을 기준으로 생존비율은 여성일 때가 더 높았음
  • 따라서, 굳이 ML 알고리즘을 적용하지 않아도 성별이 여성일 경우 생존, 남성일 경우 사망이라고 예측해도 크게 무리 없음
  • 단순히 성별 조건 하나만 적용해도 별거 아닌 알고리즘으로도 높은 정확도가 나타나는 상황 발생

가짜 분류기 생성

  • 성별이 남자면 사망
  • 성별이 여자면 생존이라고 예측하는 더미분류기 생성
from sklearn.base import BaseEstimator

class MyDummyClassifier(BaseEstimator):
    # 아무것도 학습하지 않는 fit 메서드 정의
    def fit(self, X, y=None):
        pass

    # 성별이 1(남성)이면 0(사망), 0이면 1
    def predict(self, X):
        pred = np.zeros((X.shape[0], 1))
        # 입력데이터 크기만큼 0으로 채워진 1차원 행렬 생성

        for i in range(X.shape[0]):
            if X['gender'].iloc[i] != 1:
                pred[i] = 1
            # 성별이 여성인 경우 1로 설정

        return pred
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import sklearn

from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
titanic = pd.read_csv('../data/titanic2.csv')
titanic
data = titanic.iloc[:, 1:12]
target = titanic.survived
X_train, X_test, y_train, y_test = train_test_split(data, target, train_size = 0.7,
                stratify=target)

dmyclf = MyDummyClassifier()
dmyclf.fit(X_train, y_train)
pred = dmyclf.predict(X_test)

accuracy_score(y_test, pred)
0.7857142857142857
# 즉, 이렇게 단순한 알고리즘만으로 예측하더라도
# 데이터의 구성에 따라 정확도가 약 76%가 나옴
# 불균형한 레이블의 비율()에서는 
# 정확도 지표만으로 모델 성능을 평가하는 것은 올바르지 않음

# 예를 들어, 100개의 종속변수 중 90개의 레이블 0이고, 10개의 레이블이 1인 경우, 
# 무조건 0으로 예측결과를 반환하는 머신러닝 알고리즘의 정확도는 90%임!
# 즉, 선생님이 시험 정답지의 답을 1로만 작성한 경우, 
# 학생이 1로 찍기만 해도 100점을 맞는 경우와 비슷한 상황임!

# 따라서, 불균형한 레이블 데이터세트의 성능수치로 
# 정확도 평가지표를 사용하면 안됨
# 이러한 한계를 극복하기 위해 오차행렬 사용
# 특히, 정확도보다는 정밀도, 재현율을 더 선호

오차행렬

TP : 임신을 했다고 예측 했는데 임신을 한 케이스

TN : 임신을 안했다고 예측 했는데 임신을 안한 케이스

----------------------------------------

FP : 임신을 했다고 예측 했는데 임신을 안한 케이스

FN : 임신을 안했다고 예측했는데 임신을 한 케이스

맞는것 = 양성 : Positive, 1

틀린것 = 음성 : Negative, 0

from sklearn.metrics import confusion_matrix

confusion_matrix(y_test, pred)
array([[203,  40],
       [ 44, 105]])
from sklearn.metrics import classification_report
print(classification_report(y_test, pred))
              precision    recall  f1-score   support

           0       0.82      0.84      0.83       243
           1       0.72      0.70      0.71       149

    accuracy                           0.79       392
   macro avg       0.77      0.77      0.77       392
weighted avg       0.78      0.79      0.79       392

정확도accuracy

  • 맞는 것을 맞다고, 틀린 것을 틀리다고 올바르게 예측한 것
  • $ accuracy = \frac {TP + TN} {TP + FN + FP + TN} $
  • 위 혼동행렬 대각선 부분
accuracy_score(y_test, pred)

# array([[203,  40],
#        [ 44, 105]])
0.7857142857142857
(203 + 105) / (203 + 44 + 40 + 105)
0.7857142857142857

정밀도Precision

  • 모델의 예측값이 얼마나 올바른지 알아봄
  • 양성이라고 예측한 것이 얼마나 맞았는지 알아봄 * 스팸분류 분야에서 주 활용 됨
  • $precision = \frac {TP} {TP+FP}$
  • 위 오차행렬 1열 부분
from sklearn.metrics import precision_score

precision_score(y_test, pred)
0.7241379310344828

재현율Recall

  • 실제로 맞는 것 중 맞다고 예측된 것들의 비율
  • 민감도Sensitivity(통계학), 적중률hit rate(마케팅) * 임상분야에서 주 활용 됨
  • $recall = \frac {TP} {TP+FN}$
  • 위 오차행렬 1행 부분
# array([[203,  40],
#        [ 44, 105]])
(203) / (203 + 40)
0.8353909465020576

특이도Specificity

  • 틀린 것 중 틀리다고 예측된 것들의 비율
  • $\frac {FP} {TN+FP}$
  • 위 오차행렬의 2행 부분
(40) / (105 + 40)
0.27586206896551724

간단예제 - 정확도, 정밀도, 재현율(민감도)

  • 6마리의 동물형상 중 개p/고양이n를 맞추는 게임을 진행
  • 정답 = [개 개 개 고양이 개 고양이]
  • 예측 = [개 고양이 개 고양이 개 개 ]
def getAnimal(x):
    return 'p' if x == '개' else 'n'
### 오차행렬
#        predict
# actual [3    1][개,개 | 개,고양이]
#        [1    1][고양이,개 | 고양이,고양이]
### 정확도 = 개를 '개'라고, 고양이를 '고양이'라고 예측한 비율
4/6
0.6666666666666666
### 정밀도 = 얼마나 개를 잘 예측 했는가?
### 개라고 예측 : 1, 3, 5, 6
## 실제 개 : 1, 2, 3, 5
3/4
0.75
### 재현율 - 실제 개중에서 얼마나 적중했는가?
### 실제 개 : 1, 2, 3, 5
### 개라고 적중 :  1, 3, 5, 6
3/4
0.75
ytest = ['개', '개', '개', '고양이', '개', '고양이']
pred = ['개', '고양이', '개', '고양이', '개', '개' ]
confusion_matrix(ytest, pred)
array([[3, 1],
       [1, 1]])
# print(classification_report(y_test, pred, pos_label='개'))
#정확도
accuracy_score(ytest, pred)
0.6666666666666666
#정밀도
precision_score(ytest, pred, pos_label='개')
0.75
#재현률
from sklearn.metrics import recall_score
recall_score(ytest, pred, pos_label='개')
0.75

1종오류/2종오류 알아보기

  • 전자회로기판PCB 생산업체에서 불량률이 6% 이하일때
  • 계약업체로 선적해서 납품한다는 품질보증계약 체결함
  • 불량률 6% 이하 선적 함(P), 불량률 6% 초과 선적 안함(N)
# 2종 오류(FN)
# 4000개의 회로판에서 표본 50개 추출
# 4개가 불량 -> 0.08 -> 8% -> 선적x
# 그런데, 4개의 불량이 전체 4000개에서 유일하다면?
# 불량률 0.1% -> 선적취소는 잘못된 결정
# 1종 오류(FP)
# 4000개의 회로판에서 표본 50개 추출
# 2개가 불량 -> 0.04 -> 4% -> 선적o
# 그런데, 48개 정상품이 전체 4000개에서 유일
# 불량률 98.8% -> 선적허용은 잘못된 결정

정밀도/재현율 trade-off

  • 분류하는 업무의 특성상 정밀도 또는 재현율이 특별히 강조되어야 하는 경우(특히 임상의료)
    • 정밀도 : 스팸분류(FP 중시 - 1종 오류)
    • 재현률 : 임상실험(FN 중시 - 2종 오류)
  • 결정 임계값을 조정하면 정밀도 또는 재현율을 높일 수 있음
    • 즉, 이진분류에서 0 또는 1로 판정할 기준값을 의미
    • 임계값을 0.5로 정하는 경우 기준값보다 확률이 크면 positive, 작으면 negative로 결정
  • 한편, 정밀도와 재현율은 상호보완적인 지표이기때문에,
  • 어느 한쪽을 올리면 다른 한쪽은 떨어지는 관계를 뜀
728x90
Comments