Classification(분류) 평가지표
이번 포스팅에서는 분류모델에 대한 평가지표에 대해 알아봅니다.
분류와 회귀의 평가방법
분류 평가 지표
- 정확도 (Accuracy)
- 정밀도 (Precision)
- 재현률 (Recall)
- F1점수 (F1 Score)
- AUC
회귀 평가방법
- MSE (Mean Squareed Error)
- RMSE (Root Mean Squared Error)
- R^2 (결정계수)
sckit-learn 평가함수
- sklearn.metrics 모듈을 통해 제공
분류(Classification) 평가 기준
- 이진 분류에서의 양성과 음성 의미
- 양성: 예측하려는(찾으려는) 대상
- 음성: 예측하려는 대상이 아닌 것
- 예
- 암환자 분류 : 양성 - 암 환자, 음성 - 정상인
- 스팸메일 분류 : 양성 - 스팸메일, 음성 - 정상메일
- 금융사기 모델: 양성 - 사기거래, 음성 - 정상거래
정확도 (Accuracy)
- 전체 예측 한 것중 맞게 예측한 비율로 평가한다.
accuracy_score(모델예측값, 정답)
Accuracy 평가지표의 문제
- 불균형 데이터의 경우 정확한 평가지표가 될 수 없다.
- 예: 양성과 음성의 비율이 1:9 인 경우 모두 음성이라고 하면 정확도는 90%가 된다.
Classification 모델링 Accuracy Score 평가 코드 예시
- MNIST Data set
- 손글씨 데이터 셋
- 사이킷런 제공 image size: 8 X 8
- https://ko.wikipedia.org/wiki/MNIST_%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4
from sklearn.datasets import load_digits
import numpy as np
import matplotlib.pyplot as plt
digit = load_digits()
X = digit.data
y = digit.target
X.shape, y.shape
#==> ((1797, 64), (1797,))
np.unique(y, return_counts=True)
#==> (array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
# array([178, 182, 177, 183, 181, 182, 181, 179, 174, 180], dtype=int64))
num1 = X[0].reshape(8,8)
num1.shape
print(y[0]) #0
plt.imshow(num1, cmap='Greys')
plt.xticks([])
plt.yticks([])
plt.show()
print(y[50]) #2
plt.imshow(X[50].reshape(8,8), cmap='Greys')
plt.xticks([])
plt.yticks([])
plt.show()
불균형 데이터셋으로 만들기
- y를 9와 나머지로 변경한다.
- Positive(양성 - 1): 9
- Negative(음성 - 0): 0 ~ 8
y = np.where(y==9, 1, 0)
y_cnt = np.unique(y, return_counts=True)
#==> (array([0, 1]), array([1617, 180], dtype=int64))
y_cnt[1]/y.shape
#==> array([0.89983306, 0.10016694])
훈련, 테스트 데이터셋 분할
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y)
X_train, X_test = X_train/255, X_test/255 #이미지 feature scaling 0 - 1
모델 생성 및 학습
- Dummy Model 정의
- Target Label중 무조건 최빈값으로 예측하는 모델을 정의한다.
from sklearn.base import BaseEstimator
class MyClassifier(BaseEstimator):
def fit(self, X, y):
# y중 최빈값을 instance변수로 저장
cnt = np.unique(y, return_counts=True)#(array([0, 1]), array([1617, 180])
max_index = np.argmax(cnt[1])
self.pred = cnt[0][max_index]
def predict(self, X):
# X의 행수와 같은 열벡터에 최빈값을 넣어 반환.
return np.full(shape=(X.shape[0], 1), fill_value=self.pred)
model = MyClassifier()
model.fit(X_train, y_train)
pred_train_dummy = model.predict(X_train)
pred_test_dummy = model.predict(X_test)
np.unique(pred_test_dummy), pred_test_dummy.shape
# ==> (array([0]), (450, 1))
모델 평가 (Accuracy_score)
from sklearn.metrics import accuracy_score
print(accuracy_score(y_train, pred_train_dummy)) # 0.8997772828507795
print(accuracy_score(y_test, pred_test_dummy)) # 0.9
혼동 행렬(Confusion Marix)
- 분류의 평가지표의 기준으로 사용된다.
- 혼동행렬을 이용해 다양한 평가지표(정확도, 재현률, 정밀도, F1 점수, AUC 점수)를 계산할 수 있다.
- 함수: confusion_matrix(정답, 모델예측값)
- 결과의 0번축: 실제 class, 1번 축: 예측 class
- TP(True Positive) - 양성으로 예측했는데 맞은 개수
- TN(True Negative) - 음성으로 예측했는데 맞은 개수
- FP(False Positive) - 양성으로 예측했는데 틀린 개수 (음성을 양성으로 예측)
- FN(False Negative) - 음성으로 예측했는데 틀린 개수 (양성을 음성으로 예측)
이진 분류 평가점수
- Accuracy (정확도)
- 전체 데이터 중에 맞게 예측한 것의 비율
- Recall/Sensitivity(재현율/민감도)
- 실제 Positive(양성)인 것 중에 Positive(양성)로 예측 한 것의 비율
- TPR(True Positive Rate) 이라고도 한다.
- ex) 스팸 메일 중 스팸메일로 예측한 비율. 금융사기 데이터 중 사기로 예측한 비율
- Precision(정밀도)
- Positive(양성)으로 예측 한 것 중 실제 Positive(양성)인 비율
- PPV(Positive Predictive Value) 라고도 한다.
- ex) 스팸메일로 예측한 것 중 스팸메일의 비율. 금융 사기로 예측한 것 중 금융사기인 것의 비율
- F1 점수
- 정밀도와 재현율의 조화평균 점수
- Specificity(특이도)
- 실제 Negative(음성)인 것들 중 Negative(음성)으로 맞게 예측 한 것의 비율
- TNR(True Negative Rate) 라고도 한다.
- Fall out(위양성률)
- 실제 Negative(음성)인 것들 중 Negative(양성)으로 잘못 예측한 것의 비율.
1 - 특이도
- FPR (False Positive Rate) 라고도 한다.
- 실제 Negative(음성)인 것들 중 Negative(양성)으로 잘못 예측한 것의 비율.
각 평가 지표 계산 함수
- sklearn.metrics 모듈
- confusion_matrix(y 실제값, y 예측값)
- 혼돈 행렬 반환
- recall_score(y 실제값, y 예측값)
- Recall(재현율) 점수 반환 (Positive 중 Positive로 예측한 비율 (TPR))
- precision_score(y 실제값, y 예측값)
- Precision(정밀도) 점수 반환 (Positive로 예측한 것 중 Positive인 것의 비율 (PPV))
- f1_score(y 실제값, y 예측값)
- F1 점수 반환 (recall과 precision의 조화 평균값)
- classification_report(y 실제값, y 예측값)
- 클래스 별로 recall, precision, f1 점수와 accuracy를 종합해서 보여준다.
Dummy 모델 혼동행렬
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, pred_test_dummy)
print(cm)
# [[405 0]
# [ 45 0]]
import seaborn as sns
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams['font.size']=20
plt.figure(figsize=(7,6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', cbar=False)
plt.title('dummy 모델 confusion matrix')
plt.ylabel('실제')
plt.xlabel('예측')
plt.xticks([0.5, 1.5], ['Neg', 'Pos'])
plt.yticks([0.5, 1.5], ['Neg', 'Pos'])
plt.show()
dummy 모델 Accuracy, Recall, Precision, F1-Score
from sklearn.metrics import accuracy_score, recall_score, precision_score, f1_score
print('정확도:', accuracy_score(y_test, pred_test_dummy))
print('recall(재현율):', recall_score(y_test, pred_test_dummy))
print('precision(정밀도):', precision_score(y_test, pred_test_dummy))
print('F1점수:', f1_score(y_test, pred_test_dummy))
# 정확도: 0.9
# recall(재현율): 0.0
# precision(정밀도): 0.0
# F1점수: 0.0
머신러닝 모델을 이용해 학습
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
# 모델들 생성
dt = DecisionTreeClassifier(max_depth=3)
rfc = RandomForestClassifier(n_estimators=100) #tree 100개 만들어라.
lr = LogisticRegression(max_iter=500)
# 모델들 학습
dt.fit(X_train, y_train)
rfc.fit(X_train, y_train)
lr.fit(X_train, y_train)
# 예측 및 평가
pred_test_dt = dt.predict(X_test)
pred_test_rfc = rfc.predict(X_test)
pred_test_lr = lr.predict(X_test)
# confusion matrix
print('결정트리 결과')
confusion_matrix(y_test, pred_test_dt)
# [[400, 5],
# [ 13, 32]]
print('랜덤포레스트 결과')
confusion_matrix(y_test, pred_test_rfc)
# [[405, 0],
# [ 9, 36]]
print('로지스틱회귀 결과')
confusion_matrix(y_test, pred_test_lr)
# [[405, 0],
# [ 45, 0]]
from sklearn.metrics import plot_confusion_matrix
plot_confusion_matrix(rfc, X_test, y_test, values_format='d', cmap='Blues') #모델, X, y
plt.show()
모델 평가
def print_metrics(y, pred_y, title=None):
print(title)
print("정확도:", accuracy_score(y, pred_y))
print('재현율(recall):', recall_score(y, pred_y))
print('정밀도(precision):', precision_score(y, pred_y))
print('F1 score:', f1_score(y, pred_y))
print_metrics(y_test, pred_test_dt, '결정트리 결과')
# 결정트리 결과
- 정확도: 0.96
- 재현율(recall): 0.7111111111111111
- 정밀도(precision): 0.8648648648648649
- F1 score: 0.7804878048780488'
print_metrics(y_test, pred_test_rfc,'랜덤포레스트 결과')
# 랜덤포레스트 결과
- 정확도: 0.98
- 재현율(recall): 0.8
- 정밀도(precision): 1.0
- F1 score: 0.888888888888889
classification_report()
from sklearn.metrics import classification_report
print(classification_report(y_test, pred_test_rfc))
재현율과 정밀도의 관계
이진 분류의 경우 Precision(정밀도)가 중요한 경우와 Recall(재현율)이 중요한 경우가 있다.
재현율이 더 중요한 경우
- 실제 Positive 데이터를 Negative 로 잘못 판단하면 업무상 큰 영향이 있는 경우.
- FN(False Negative)를 낮추는데 촛점을 맞춘다.
- 암환자 판정 모델, 보험사기적발 모델
정밀도가 더 중요한 경우
- 실제 Negative 데이터를 Positive 로 잘못 판단하면 업무상 큰 영향이 있는 경우.
- FP(False Positive)를 낮추는데 초점을 맞춘다.
- 스팸메일 판정
임계값(Threshold) 변경을 통한 재현율, 정밀도 변환
- 임계값 : 모델이 분류의 답을 결정할 때 기준값
- 정밀도나 재현율을 특히 강조해야 하는 상황일 경우 임계값 변경을 통해 평가 수치를 올릴 수있다.
- 단 극단적으로 임계점을 올리나가 낮춰서 한쪽의 점수를 높이면 안된다. (ex: 암환자 예측시 재현율을 너무 높이면 정밀도가 낮아져 걸핏하면 정상인을 암환자로 예측하게 된다.)
임계값 변경에 따른 정밀도와 재현율 변화관계
- 임계값을 높이면 양성으로 예측하는 기준을 높여서(엄격히 해서) 음성으로 예측되는 샘플이 많아 진다. 그래서 정밀도는 높아지고 재현율은 낮아진다.
- 임계값을 낮추면 양성으로 예측하는 기준이 낮아져서 양성으로 예측되는 샘플이 많아 진다. 그래서 재현율은 높아지고 정밀도는 낮아진다.
- 임계값을 변화시켰을때 재현율과 정밀도는 음의 상관관계를 가진다.
- 임계값을 변화시켰을때 재현율과 위양성율(Fall-Out/FPR)은 양의 상관관계를 가진다.
Binarizer - 임계값 변경
- Transformer로 양성 여부를 선택하는 임계값을 변경할 수 있다.
from sklearn.preprocessing import Binarizer
exam = [[0.3, 0.7, 0.6, 0.4,0.5]]
b = Binarizer(threshold=0.2)
b.fit_transform(exam)
# 양성 판단의 기준 임계점을 높이면 재현율은 낮아지고 정밀도가 높아진다.
# 양성 판단의 기준 임계점을 낮추면 재현율은 높아지고 정밀도가 낮아진다.
import numpy as np
binarizer = Binarizer(threshold=0.1) #양성판단의 임계점을 0.1로 변경.
pred_proba = dt.predict_proba(X_test)
# pred_proba[:5]
- predict_proba(X_test)
- predict_proba의 출력은 각 클래스에 대한 확률
- 각 행의 첫 번째 원소는 첫 번째 클래스의 예측 확률이고 두 번째 원소는 두 번째 클래스의 예측 확률입니다.
- 확률이기 때문에 predict_proba의 출력은 항상 0과 1 사이의 값이며 두 클래스에 대한 확률의 합은 항상 1입니다.
- 확률 합은 1이므로 두 클래스 중 하나는 50% 이상의 확률이며 바로 그 클래스가 예측값이 됩니다.
pred_test_dt2 = binarizer.fit_transform(pred_proba)[:, 1]
print_metrics(y_test, pred_test_dt, "----임계값 0.5-----")
----임계값 0.5-----
정확도: 0.96
재현율(recall): 0.7111111111111111
정밀도(precision): 0.8648648648648649
F1 score: 0.7804878048780488
print_metrics(y_test, pred_test_dt2, "----임계값 0.1-----")
----임계값 0.1-----
정확도: 0.9488888888888889
재현율(recall): 0.8666666666666667
정밀도(precision): 0.6964285714285714
F1 score: 0.7722772277227722
ROC 곡선과 AUC 점수
이진 분류 모델 성능 측정에서 중요하게 사용되는 지표.
- FPR(False Positive Rate)
- 위양성율 (fall-out)
- 1-특이도(TNR)
- 실제 음성중 양성으로 잘못 예측 한 비율
- TPR(True Positive Rate)
- 재현율(recall)
- 실제 양성중 양성으로 맞게 예측한 비율
- ROC 곡선
- FPR을 X축, TPR을 Y축으로 놓고 임계값을 변경해서 FPR이 변할 때 TPR이 어떻게 변하는지 나타내는 곡선.
- AUC
- ROC 곡선 아래쪽 면적
- 0 ~ 1 사이 실수로 나오며 클수록 좋다.
- AUC 점수기준
- 1.0 ~ 0.9 : 아주 좋음
- 0.9 ~ 0.8 : 좋음
- 0.8 ~ 0.7 : 괜찮은 모델
- 0.7 ~ 0.6 : 의미는 있으나 좋은 모델은 아님
- 0.6 ~ 0.5 : 좋지 않은 모델
- AUC 점수기준
ROC, AUC 점수 확인
- roc_curve(y값, 예측확률) : FPR, TPR, Thresholds (임계치)
- roc_auc_score(y값, 예측확률) : AUC 점수 반환
dt_pos = dt.predict_proba(X_test)[:, 1]
rfc_pos= rfc.predict_proba(X_test)[:, 1]
from sklearn.metrics import roc_curve, roc_auc_score
fprs1, tprs1, thresholds1 = roc_curve(y_test, dt_pos)
fprs2, tprs2, thresholds2 = roc_curve(y_test, rfc_pos)
plt.figure(figsize=(7,7))
plt.plot(fprs1, tprs1, label='Tree-Roc곡선')
plt.plot(fprs2, tprs2, label='RFC-Roc곡선')
plt.legend()
plt.grid(True)
plt.title('ROC Curve')
plt.show()
print("결정트리-AUC 점수")
roc_auc_score(y_test, dt_pos)
결정트리-AUC 점수
0.9217283950617283
print("랜덤포레스트-AUC점수")
roc_auc_score(y_test, rfc_pos)
랜덤포레스트-AUC점수
0.9993964334705076
728x90
반응형
'Data Analysis & ML > Machine Learning' 카테고리의 다른 글
[Machine Learning][머신러닝][지도학습] K-최근접 이웃(KNN) (0) | 2020.09.01 |
---|---|
[Machine Learning][머신러닝] 과적합과 해결방법(그리드서치/파이프라인) (0) | 2020.08.31 |
[Machine Learning][머신러닝] 데이터 전처리(범주형/연속형) (5) | 2020.08.27 |
[Machine Learning][머신러닝] 데이터셋 나누기와 교차검증 (0) | 2020.08.26 |
[Machine Learning][머신러닝] IRIS 분석 (결정 트리 모델(Decision Tree)) (0) | 2020.08.26 |