본문 바로가기

Self-Taught/Machine Learning

파이썬 머신 러닝 완벽 가이드 _ CH.3

CH.3_평가

머신러닝의 프로세스

데이터 가공/변환 --> 모델 학습/예측  -->  평가 프로세스

 

성능 평가 지표는 모델이 회귀냐 분류냐에 따라 여러 종류로 나뉜다.

 

회귀 -- 실제값과 예측값 간의 오차 평균값에 기반한 성능 평가 지표

ex) 오차에 절댓값을 씌운 뒤 평균 오차 구하기 / 오차 제곱값에 루트를 씌운 뒤 평균 오차 구하기

 

분류 -- 단순히 정확도만 가지고 판단하기에는 잘못된 결과가 발생 가능

  • 정확도_Accuracy
  • 오차행렬_Confusion Matrix
  • 정밀도_Precision
  • 재현율_Recall
  • F1 스코어 
  • ROC AUC

CH.3.1_ 정확도

Accuracy = 예측 결과가 동일한 데이터 건수 / 전체 예측 데이터 건수

 

정확도는 직관적인 평가 지표지만, 이진 분류의 경우 데이터의 구성에 따라 ML 모델의 성능을 왜곡할 수 있다.

정확도 수치 하나만 가지고 성능을 평가하지는 않는다.

 

단순한 알고리즘으로 예측을 하더라도 데이터의 구성에 따라 정확도의 결과가 높게 나올 수도 있다.

from sklearn.base import BaseEstimator

class MyDummyClassifier(BaseEstimator):

    def fit(self, X, y=None):
        pass

    def predict(self, X):
        pred=np.zeros((X.shape[0], 1))
        for i in range (X.shape[0]):
            if X['Sex'].iloc[i] == 1:
                pred[i] =0
            else:
                pred[i] =1
        return pred


from sklearn.base import BaseEstimator

class MyDummyClassifier(BaseEstimator):

    def fit(self, X, y=None):
        pass

    def predict(self, X):
        pred=np.zeros((X.shape[0], 1))
        for i in range (X.shape[0]):
            if X['Sex'].iloc[i] == 1:
                pred[i] =0
            else:
                pred[i] =1
        return pred


import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split   ## 데이터 셋을 학습/테스트로 분리
from sklearn.metrics import accuracy_score

titanic_df = pd.read_csv("C:\\Users\\rud92\\Downloads\\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.2, random_state=0)

myclf = MyDummyClassifier()
myclf.fit(X_train, y_train)

mypredictions = myclf.predict(X_test)
print('Dummy Classifier의 정확도는 : {0:.4f}'.format(accuracy_score(y_test, mypredictions)))
Dummy Classifier의 정확도는 : 0.7877
 

 

 

데이터의 분포도가 균일하지 않은 경우 높은 수치가 나타날 수 있는 것이 정확도평가 지표의 가장 큰 맹점이다.

정확도 평가 지표는 불균형한 레이블 데이터 세트에서는 성능 수치로 사용돼서는 안 된다.

이런 한계점을 극복하기 위해 여러 가지 분류 지표와 함께 적용해야 한다.

 

CH.3.2_ 오차 행렬  by. confusion_matrix( ) 

오차 행렬_confusion matrix(혼동행렬) : 학습된 분류 모델이 예측을 수행하면서 얼마나 헷갈리고 있는지를 함께 보여주는 지표이다.

이진 분류의 예측 오류가 얼마인지 & 어떤 유형의 예측 오류가 발생하고 있는지를 나타낸다. 

 

TN, FP, FN, TP는 예측 클래스와 실제 클래스의 Positive 결정 값(1), Negative 결정 값(0)의 결합에 따라 결정된다.

앞의 값은 예측 클래스와 실제 클래스의 값이 같은지(T) 다른지(N)을 나타내고,

뒤의 값은 예측값이 Positive인지 Negative인지를 알려준다.

TP, TN, FP, TN 값은 Classifier 성능의 여러 면을 판단할 수 있는 기반 정보를 제공한다.

이를 조합해 Classifier의 성능을 측정할 수 있는 Accuracy & Precision & Recall 값을 알 수 있다.

 

 

정확도 = (TN+TP) / (TN+FP+FN+TP)

 

불균형한 레이블 클래스를 갖는 이진 분류 모델에서는 많은 데이터 중에서 중점적으로 찾아야 하는 매우 적은 수의 결괏값에 Positive를 설정해 1 값을 부여하고, 그렇지 않은 것에 Negative 0을 부여

ex-1) 사기 행위 예측 모델 -- 사기 행위 == Positive 1, 정상 행위 == Negative 0

ex-2) 암 건진 예측 모델 -- 암이 양성 == Positive 1, 음성인 경우 == Negative 0

 

불균형한 이진 분류 데이터 셋에서는 Positive의 건수가 매우 작음 그래서 Negative로 예측 정확도가 높아지는 경향이 발생 

EX) 10,000건 중 9,900건이 Negative / 100건이 Positive면

TN이 매우 커지고, TP는 매우 작아짐  / FN이 매우 작아지고, FP도 매우 작아진다

*TN = negative로 예측했을 때 True인 경우

*TP = positive로 예측했을 때 True인 경우

*FN = negative로 예측했을 때 False인 경우

*FP = positive로 예측했을 때 False인 경우

 

 

CH.3.3_ 정밀도와 재현율

정밀도 = TP / (FP + TP)

--> 정밀도는 예측을 Positive로 한 대상* 중 예측과 실제 값이 Positive로 일치한 데이터의 비율

--> Positive 예측 성능을 정밀하게 측정함 --> 양성 예측도

*FP  &  TP == 예측을 Positive로 했는데 False인 FP와 True인 TP

 

정밀도가 중요 지표인 상황 : 실제 Negative 음성인 일반 데이터를 Positive 양성으로 분류할 경우

Ex) 스팸이 아닌 Negative 메일을 Positive 스팸 메일로 판단하면 메일을 아예 받지 못해 업무에 차질 생김

 

재현율 = TP / (FN + TP)

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

--> 민감도_Sensitivity & TPR_True Posivie Rate *

*FN & TP == 예측을 Negative로 했는데 False니까 실제값은 Positive인 FN & 예측을 Positive로 했고 실제로 True인 TP

*TPR = 재현율, 민감도  <--> TNR_true negative rate 특이성*

*특이성 = 실제값 Negative가 정확히 예측돼야 하는 수준을 나타냄 ex) 질병이 없는 사람이 질병이 없는 것으로 나타날 수준

==> 특이성 TNR = TN/(FP+TN)

 

재현율이 중요 지표인 상황 : 실제 Positive 양성 데이터를 Negative로 판단하면 업무상 큰 영향일 발생할 경우

Ex) 실제 Positive인 암 환자를 Negative로 잘못 판단했을 경우 오류가 심각한 것

Ex) 보험 사기와 같은 금융 사기 적발 모델

 

이 둘을 서로 보완적인 성능 지표임. 

 

 

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

정밀도와 재현율은 상호 보완적인 평가지표이므로 어느 한 쪽을 강제로 높이면 다른 하나의 수치는 떨어지기 쉽다. 분류 알고리즘은 예측 데이터가 특정 레이블에 속하는지를 계산하기 위해 개별 레이블별 결정 확률을 구한다일반적으로 이진 분류에서, 해당 레이블에 속할 확률이 0.5(=50%)를 넘는다면 Positive, 넘지 못한다면 Negative로 결정한다.

 

일반적으로 임곗값이 증가할 수록 정밀도 값은 동시에 높아지지만, 재현율의 값은 낮아짐을 알 수 있다. 

 

#정밀도와 재현율의 맹점

임곗값은 두 개의 수치를 상호 보완할 수 있는 수준에서 적용돼야 하지, 하나의 성능 지표 수치를 높이기 위한 수단으로 사용하면 안된다.

 

CH.3.4_ F1 스코어

F1 스코어는 정밀도와 재현율을 결합한 지표이다. 

정밀도와 재현율이 비슷한 수치를나타낼 때 상대적으로 높은 값을 갖는다. 

CH.3.5_ ROC 곡선과 AUC

ROC 곡선 _ Receiver Operation Characteristic

= 수신자 판단 곡선 by. roc_curve( )

의학 분야에서 많이 사용됨 / 머신러닝의 이진 분류 모델의 예측 성능을 판단하는 평가 지표

 

FPR이 변할 때 TPR이 어떻게 변하는지를 나타내는 곡선*

   *FPR - x축  / TPR - y축                        --> TPR = 재현율, 민감도                     --> FPR = 1 - TNR(특이성_Specificity)

AUC = Area Under Curve _ ROC 곡선 밑의 면적을 구한 것

일반적으로 1에 가까울 수록 좋은 수치 

 

CH.3.6_ 피마 인디언 당뇨병 예측

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, precision_score, recall_score, roc_auc_score
from sklearn.metrics import f1_score, confusion_matrix, precision_recall_curve, roc_curve
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

diabetes_data = pd.read_csv("C:\\Users\\rud92\\Downloads\\diabetes.csv")
print(diabetes_data['Outcome'].value_counts())
diabetes_data.head(3)

 

X = diabetes_data.iloc[:, :-1]
y = diabetes_data.iloc[:, -1]

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=156, stratify=y)

lr_clf = LogisticRegression(solver='liblinear')
lr_clf.fit(X_train, y_train)
pred = lr_clf.predict(X_test)
pred_proba = lr_clf.predict_proba(X_test)[:,1]

get_clf_eval(y_test, pred, pred_proba)

 

pred_proba_c1 = lr_clf.predict_proba(X_test)[:,1]
precision_recall_curve_plot(y_test, pred_proba_c1)
diabetes_data.describe()
plt.hist(diabetes_data['Glucose'], bins=100)
plt.show()
zero_features = ['Glucose', 'BloodPressure', 'SkinThickness', 'Insulin', 'BMI']

total_count = diabetes_data['Glucose'].count()

for feature in zero_features:
    zero_count = diabetes_data[diabetes_data[feature]==0][feature].count()
    print('{0} 0 건수는 {1}, 퍼센트는 {2:.2f}%'.format(feature, zero_count, 100*zero_count/total_count))

mean_zero_features = diavetes_data[zero_features].mean()
diabetest_data[zero_features]=diabetes_data[zero_features].replace(0, mean_zero_features)

X = diabetes_data.iloc[:, :-1]
y = diabetes_data.iloc[:, -1]

scaler = LogisticRegression()
X_scaled = scaler.fit_transform(X)


X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=156, stratify=y)

lr_clf = LogisticRegression()
lr_clf.fit(X_train, y_train)
pred = lr_clf.predict(X_test)
pred_proba = lr_clf.predict_proba(X_test)[:,1]

get_clf_eval(y_test, pred, pred_proba)

thresholds = [0.3, 0.33, 0.36, 0.39, 0.42, 0.45, 0.48, 0.50]
pred_proba = lr.clf.predict_proba(X_test)
get_clf_eval(y_test, pred[:,1].reshape(-1,1), thresholds)

binarizer = Binarizier(threshold=0.48)
pred_th_048 = binarizer.fit_transform(pred_proba[:,1].reshape(-1,1))
get_clf_eval(y_test, pred_th_048, pred_proba[:,1])

 

CH.3.7 _ 정리

오차 행렬은 4분면 행렬을 기반으로 예측 성능을 평가함. 이 수치를 기반으로 정확도, 정밀도, 재현율 수치를 판단하게 된다.

특히, 정밀도와 재현율은 Positive 데이터 세트의 예측 성능에 좀 더 초점을 맞췄고, Threshold_임곗값을 조절해 정밀도 또는 재현율의 수치를 높일 수 있다.

F1 스코어는 정밀도와 재현율을 결합한 평가 지표이고, 어느 한쪽으로 치우치지 않았을 때 높은 지표값을 갖게 된다.

ROC-AUC는 이진 분류의 성능 평가에 가장 많이 사용되는 지표로  AUC는 1에 가까울 수록 좋다.

 

*이미지 출처 :

https://velog.io/@gangjoo/ML-%ED%8F%89%EA%B0%80-%EC%98%A4%EC%B0%A8-%ED%96%89%EB%A0%AC-Confusion-Matrix-%EC%A0%95%EB%B0%80%EB%8F%84-Precision-%EC%9E%AC%ED%98%84%EC%9C%A8-Recall

https://dev-adela.tistory.com/261