자 열쩡을 가지고 해봅시다.. 열쩡열쩡열쩡..!!
https://book.naver.com/bookdb/book_detail.nhn?bid=16238302
3. 평가
- 여러 방법으로 머신러닝 예측 성능 평가 가능.
- 회귀 모델의 경우 실제 값과 예측 값의 오차 평균값 기반
- 분류 모델의 경우 정확도만으로 판단해선 안 됨
- 분류 성능 평가 지표 : 정확도, 오차행렬, 정밀도, 재현율, F1스코어, ROC AUC
- 분류는 결정 클래스 값 종류 유형에 따라 이진 분류(긍정/부정), 멀티 분류(여러개)로 나뉨.
01. 정확도(Accuracy)
정확도 : 실제 데이터와 예측 데이터가 얼마나 같은지를 판단하는 지표.
- '예측 결과==실제값' 데이터 건수 / 전체 예측 데이터 건수
- 모델의 예측 성능을 직관적으로 보여줌
- 이진 분류의 경우 모델의 성능이 왜곡될 수 있음
- 레이블 값 분포가 불균형할때에는 적합한 평가 지표가 아님 (1000개의 케이스 중 1개만 True이고 999개가 False일 때 모든 예측을 False로 한다고 해도 정확도가 0.999가 되기 때문). 이에 다른 분류 지표와 함께 적용하는 것이 좋음
02. 오차 행렬(Confusion matrix, 혼동행렬)
오차 행렬 : 학습된 (분류)모델이 예측 수행 과정에서 얼마나 헷갈리고 있는지를 보여주는 지표. 어떤 유형의 예측 오류가 일어나고 있고, 얼마나 일어나고 있는지 알려줌. 4분면 행렬에서 실제 값과 예측 값의 유형별 매핑을 알려줌.
예측→ ↓실제 |
Negaitve(0) | Positive(1) |
Negative(0) | TN (True Negative) |
FP (False Positive) |
Positive(1) | FN (False Negative) |
TP (True Positive) |
(티스토리로 표 처음 그려봐요.. 나름 열심히 그렸습니당)
- 예측값과 실제값이 같은가/다른가에 따라 T/F, 예측값이 부정인가 긍정인가에 따라 N/P가 됨.
- 오차행렬을 구하기 위해 사이킷런의 confusion_matrix() 사용.
- 정확도는 오차 행렬상에서 '"예측결과==실제값' 건수 / 전체 데이터 수 = (TN+TP) / (TN+TP+FN+FP)"로 정의 가능
03. 정밀도와 재현율
- Positive 데이터 세트 예측 성능에 초점을 맞춘 평가 지표.
- 정밀도는 TP / (FP+TP)로 계산. 예측이 Positive인 것 중에 예측값과 실제값 모두 Positive인 데이터 비율. "양성 예측도". 실제 Negative를 Positive라 판단하면 큰 영향이 발생하는 경우 중요한 지표가 됨. FP(실제 Negaitve 예측 Positive)를 낮추는 데 초점. 사이킷런의 precision_score() 사용
- 재현율은 TP / (FN+TP)로 계산. 실제로 Positive인 것 중에 예측값과 실제값 모두 Positive인 데이터 비율. "민감도", "TPR(True Positive Rate)". 실제 Positive를 Negative라 판단하면 큰 영향이 발생하는 경우 중요한 지표가 됨. FN(실제 Positive 예측 Negative)를 낮추는 데 초점. 사이킷런의 recall_score() 사용.
- 가장 좋은 성능평가는 정밀도와 재현율 모두 높은 것으로, 둘 중 하나만 높은 경우는 좋지 않음.
- 정밀도/재현율 트레이드오프
- 정밀도와 재현율 중 하나를 강조할 경우 결정 임계값(Threshold)을 조정해 성능 수치를 높일 수 있음. 다만 둘은 상호 보완적인 지표이기 때문에 하나를 높이면 하나는 떨어지는 경향이 있음. 이를 정밀도/재현율의 트레이드오프(Trade-off)라 함.
- 사이킷런의 Binarizer로 사이킷런 predict()의 pseudo 코드를 만들 수 있음.
from sklearn.preprocessing import Binarizer
custom_threshold = 0.5 #분류 결정 임계값
#칼럼 하나만 추출해 Binarizer 적용
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_eval(y_test, custom_predict)
(get_clf_eval은 오차행렬, 정확도, 정밀도, 재현율을 얻게 해 주는 함수라고 정의하였음) (*제가 캐글에서 받은 titanic 데이터가 책에서 사용된 데이터와 달라 결과값 또한 다릅니다ㅠ)
- 이는 로지스틱 회귀 Classifier의 predict()로 계산한 것과 동일. (개별 데이터별로 예측 확률을 반환하는 사이킷런의 predict_proba()는 predict() 메서드의 기반 API임)
- custom_threshold 값을 0.4로 낮추면 정확도와 정밀도는 내려가나 재현율은 올라감
- 분류 결정 임계값 : Positive 예측값을 결정하는 확률의 기준 (0.5였던 것을 0.4로 바꾸면 50% 확률이 아닌 60% 확률로 Positive라 예측하게 됨). 임계값이 낮아지면 정밀도는 내려가고 재현율은 올라감. 반대도 작용.
(임계값 변화에 따른 평가 지표 값 보기 : 사이킷런의 precision_recall_curve(). 정밀도와 재현율의 임계값에 따른 값 변화를 곡선 그래프로 시각화 할 수 있음)
from sklearn.metrics import precision_recall_curve
#레이블 값이 1일때의 예측확률 추출
pred_proba_class1 = lr_clf.predict_proba(X_test)[:, 1]
#실제값 데이터 세트, 레이블 값=1일때의 예측 확률을 precision_recall_curve 인자로 입력
precisions, recalls, thresholds = precision_recall_curve(y_test, pred_proba_class1)
print("반환된 분류 결정 임계값 배열 Shape:", thresholds.shape)
#반환된 임계값 배열 로우의 샘플 추출
thr_index = np.arange(0, thresholds.shape[0], 15)
print("샘플 추출을 위한 임계값 배열 index:", thr_index)
print("샘플 10개의 임계값:", np.round(thresholds[thr_index], 2))
#샘플 임계값의 정밀도와 재현율
print("샘플 임계값 정밀도:", np.round(precisions[thr_index], 3))
print("샘플 임계값 재현율:", np.round(recalls[thr_index], 3))
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
%matplotlib inline
def precision_recall_curve_plot(y_test, pred_proba_c1):
#threshold ndarray, threshold에 따른 정밀도/재현율 ndarray 추출
precisions, recalls, thresholds = precision_recall_curve(y_test, pred_proba_c1)
#x축 threshold, y축 정밀도, 재현율로 plot 그리기
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')
#threshold값 X축 Scale 변경
start, end = plt.xlim()
plt.xticks(np.round(np.arange(start, end, 0.1), 2))
#x축/y축 label, legend, grid 설정
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])
- 정밀도와 재현율의 맹점
- 확실할 때만 Positive, 나머지는 모두 Negative로 예측하면 정밀도 100% 가능
- 모두 Positive로 예측하면 재현율 100% 가능
- 다만 임계값의 변경은 두 수치를 상호보완 할 수 있는 수준에서 적용되어야 함
04. F1 스코어
F1 스코어 : 정밀도와 재현율을 결합한 지표. 두 값이 치우치지 않을 때 높은 값을 가짐.
- 2*(정밀도*재현율)/(정밀도+재현율)
05. ROC곡선과 AUC
ROC곡선, AUC스코어 : 이진 분류 예측 성능 측정에서 중요한 지표.
- Receiver Operation Characteristic Curve : 수신자 판단 곡선. FPR이 변할 때 TPR이 어떻게 변하는지를 나타냄.
(*FPR(False Positive Rate) : FP/(FP+TN). 1-TNR 또는 1-특이성으로 표현)
(*TPR(True Positive Rate) : 재현율. TP/(EN+TP). 민감도라고도 불림. 이는 "Positive가 정확히 예측되어야 하는 수준")
(*민감도에 대응하는 지표로 TNR(True Negative Rate), 특이성이 있음. TN/(EP+TN). 이는 "Negative가 정확히 예측되어야 하는 수준")
- 임계값을 1부터 0까지 변화시키며 FPR을 구하고 이에 따른 TPR을 구하는 것이 ROC곡선. 사이킷런의 roc_curve()로 구함
from sklearn.metrics import roc_curve
pred_proba_class1 = lr_clf.predict_proba(X_test)[:, 1]
fprs, tprs, thresholds = roc_curve(y_test, pred_proba_class1)
#반환된 임계값 배열에서 샘플로 데이터 추출
#thresholds[0]은 max(예측확률)+1. 이를 제외하기 위해 np.arange 1부터 시작
thr_index = np.arange(1, thresholds.shape[0], 5)
print("샘플 추출을 위한 임계값 배열 index:", thr_index)
print("샘플 index로 추출한 임계값:", np.round(thresholds[thr_index], 2))
print("샘플 임계값 FPR:", np.round(fprs[thr_index], 3))
print("샘플 임계값 TPR:", np.round(tprs[thr_index], 3))
- 위 결과를 시각화하는 것이 ROC곡선.
- AUC(Area Under Curve) : ROC 곡선 밑의 면적을 구하는 것. 1에 가까울수록 좋음. FPR이 작은 상태에서 얼마나 큰 TPR을 얻느냐가 관건.
- 보통의 분류는 0.5 이상의 AUC 값을 가짐(위 코드의 ROC AUC값은 0.9024034454015005)
06. 피마 인디언 당뇨병 예측(생략)
07. 정리
- 이진 분류 레이블 값이 불균형한 경우, 정확도만으로 머신러닝 모델 예측 성능을 평가해선 안됨
- 오차행렬은 실제 클래스 값(Negative/Positive)과 예측 클래스 값(False/True)에 따라 매핑되는 4분면 행렬로 예측 성능 평가. 정확도, 정밀도, 재현율은 이 값들을 결합해 만들어짐.
- 정밀도, 재현율은 Positive의 예측 성능에 초점을 맞춘 평가지표. 특정 지표를 강조해야 할 경우 임곗값을 조정함.
- F1스코어는 정밀도와 재현율을 결합한 지표. 두 지표가 치우치지 않을 때 높은 값을 가짐.
- ROC-AUC는 이진 분류 성능 평가를 위해 사용되는 지표. AUC값은 ROC곡선 밑의 면적을 구한 것.
'STUDY' 카테고리의 다른 글
파이썬 스터디 4주차(캐글) (0) | 2022.01.30 |
---|---|
파이썬 스터디 4주차(백준) (0) | 2022.01.30 |
파이썬 스터디 3주차(캐글) (0) | 2022.01.26 |
파이썬 스터디 3주차(백준) (0) | 2022.01.25 |
파이썬 스터디 2주차(머신러닝) (0) | 2022.01.24 |