chapter 3 - 분류 / 3.3

dldzm·2021년 2월 8일
0

노션 정리 : https://www.notion.so/bmo29/chapter-3-0b3c96ef54fc492aa5bbbff553dc8312


3.3 성능 측정

분류기 평가는 회귀 모델보다 훨씬 어렵다. 따라서 사용할 수 있는 성능 지표가 많다.

3.3.1 교차 검층을 사용한 정확도 측정

교차 검증 구현을 사이킷런의 cross_val_score() 을 통해 구현할 수 있다.

for train_index, test_index in skfolds.split(X_train, y_train_5):
    clone_clf = clone(sgd_clf)
    X_train_folds = X_train[train_index]
    y_train_folds = y_train_5[train_index]
    X_test_fold = X_train[test_index]
    y_test_fold = y_train_5[test_index]

    clone_clf.fit(X_train_folds, y_train_folds)
    y_pred = clone_clf.predict(X_test_fold)
    n_correct = sum(y_pred == y_test_fold)
    print(n_correct / len(y_pred))

StratifiedKFold 는 클래스별 비율이 유지되도록 폴드를 만들기 위해 계층적 샘플링을 수행한다.

매 반복에서 분류기 객체를 복제하여 훈련 폴드로 훈련하고(clone_clf.fit(X_train_folds, y_train_folds)) 테스트 폴드로 예측을 만든다(y_pred = clone_clf.predict(X_test_fold)). 마지막으로는 올바른 예측의 수를 세어 정확한 예측의 비율을 출력받는다(n_correct = sum(y_pred == y_test_fold)).

k-겹 교차 검증은 훈련 세트를 k개의 폴드로 나누고 각 폴드에 대해 예측을 만들고 평가하기 위해 나머지 폴드로 훈련시킨 모델을 사용한다.

from sklearn.model_selection import cross_val_score
cross_val_score(sgd_clf, X_train, y_train_5, cv = 3, scoring = "accuracy")
from sklearn.base import BaseEstimator
class Never5Classifier(BaseEstimator):
    def fit(self, X, y=None):
        return self
    def predict(self, X):
        return np.zeros((len(X), 1), dtype=bool)
never_5_clf = Never5Classifier()
cross_val_score(never_5_clf, X_train, y_train_5, cv=3, scoring="accuracy")

모델의 정확도 ; accuracy 는 다음과 같이 나온다.

숫자 10개 중에 1개가 5이니까 나머지 5가 아닌 집단은 90%가 맞다.

정확도를 분류기의 성능 측정 지표로 선호하지 않는 이유를 보여준다. 특히 불균형한 데이터셋 을 다룰 때 (즉, 어떤 클래스가 다른 것보다 월등히 많은 경우) 특히 그렇다.

3.3.2 오차 행렬

분류기의 성능을 평가하는 방법으로는 오차 행렬 ; confusion matrix 를 조사하는 것이다. 기본적인 아이디어로 클래스 A의 샘플이 클래스 B로 분류되는 횟수를 세는 것이다. → 정답은 행으로 오답은 열로, (정답 행, 오답 열)로 확인할 수 있다.

오차 행렬을 만드려면 실제 타깃과 비교할 수 있도록 먼저 예측값을 만들어야 한다. 테스트 세트로는 출시 준비를 마치고 나서 프로젝트의 맨 마지막에 사용되어야 하므로 건드리면 안되고 대신 cross_val_predict() 함수를 이용한다.

from sklearn.model_selection import cross_val_predict

y_train_pred = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3)

cross_val_score() 함수처럼 cross_val_predict() 함수는 k-겹 교차 검증을 수행하지만 평가 점수를 반환하지 않고 각 테스트 폴드에서 얻은 예측을 반환한다. 즉, 훈련 세트의 모든 샘플에 대해 깨끗한(== 깨끗하다는 말인 즉슨 모델이 훈련하는 동안 한번도 보지 못했던 데이터에 대해 예측했다는 것) 예측을 얻게 된다는 소리다.

confusion_matrix()를 사용해 오차 행렬을 만들자. 타깃 클래스(y_train_5)와 예측 클래스(y_train_pred)를 넣고 호출하면 된다.

오차 행렬의 실제 클래스를 나타내고 예측한 클래스를 나타낸다.

이 행렬의 첫번째 행은 '5 아님'에 대한 이미지 음성 클래스 ; negative class 에 대한 것이고 53892개를 '5 아님' 클래스로 정확히 분류한(진짜 음성 ; true negative)이고 나머지 687를 '5'라고 잘못 분류한 거짓 분류 ; false negative 이다.

두번째 행은 '5' 이미지 양성 클래스 ; positive class 에 대한 것으로, 1891개를 '5 아님'으로 잘못 분류한 거짓 음성 ; false negative 이고 나머지 3530개를 정확히 '5'로 분류한 진짜 양성 ; true positive 이다.

완벽한 분류기라면 진짜 양성과 진짜 음성만을 가지고 있을 것이므로 다음과 같이 오차 행렬의 주대각선만 0이 아닌 값이 된다.

이보다 더 요약된 지표가 필요할 때 양성 예측의 정확도를 보여주는 분류기의 정밀도 ; prediction 을 확인해보자.

prediction=TPTP+FPprediction = \frac{TP}{TP+FP}

TP 는 진짜 양성의 수이고 FP 는 거짓 양성의 수다.

정밀도는 재현율 ; recall 이라는 지표와 같이 사용한다. 재현율은 분류기가 정확하게 감지한 양성 샘플의 비율로 민감도 ; sensitivity 또는 진짜 양성 비율 ; true positive rate (TPR) 이라고 한다.

recall=TPTP+FNrecall = \frac{TP}{TP+FN}

FN 은 거짓 음성의 수이다.

3.3.3 정밀도와 재현율

  • prediction : 양성이라고 예측한 것 대비 실제 양성의 비율 → 5로 판별된 이미지 중 83%만 정확
  • recall : 실제 양성인 것 대비 양성이라 예측 성공한 비율 → 전체 숫자 5에서 65%만 감지

정밀도와 재현율을 F1F_1점수 를 통해 하나의 숫자로 만들어 편리하게 사용한다. 특히 두 분류기를 비교할 때 그렇다. F1F_1 점수는 정밀도와 재현율의 조화 평균 ; harmonic mean 이다.

F1F_1 score은 다음과 같다.

F1=21precision+1recall=2precisionrecallprecision+recall=TPTP+FN+FP2F_1 = \frac {2}{\frac1{precision}+\frac1{recall}} = 2 *\frac{precision*recall}{precision+recall} = \frac{TP}{TP+\frac{FN+FP}{2}}

>>> cm[1, 1] / (cm[1, 1] + (cm[1, 0] + cm[0, 1]) / 2)

다음과 같이 입력하여도 같은 값이 나온다. 이 코드는 위의 맨 오른쪽 공식을 참고한 것이다.

정밀도와 재현율이 비슷한 분류기는 F1 점수가 높다. 하지만 이게 항상 바람직하지는 않다. 상황에 따라 정밀도 또는 재현율이 중요할 수도 있다.

그러나 정밀도를 올리면 재현율이 줄고 그 반대도 마찬가지다. 이를 정밀도/재현율 트레이드오프 라고 한다.

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

SGDClassifier 가 분류를 어떻게 결정하는지 살펴보자. 이 분류기는 결정 함수 ; decision function 을 사용하여 각 샘플의 점수를 계산한다. 이 점수가 임곗값보다 크면 샘플을 양성 클래스에 할당, 낮으면 음성 클래스에 할당한다. 여러 임계값 중 결정 임곗값 ; decision threshold 를 설정하여 정밀도와 재현율을 조정한다.

보통 임곗값이 높을수록 재현율(감지)은 낮아지고 반대로 보통 정밀도(정확)는 높아진다.

각 샘플의 점수를 확인할 수 있다.

만약 임곗값을 0으로 만든다면 predict() 메서드는 True 결괏값을 보인다.

임곗값을 높이면 재현율(감지)이 줄어든다는 것을 볼 수 있다.

이미지가 실제로 숫자 5일 때 임곗값이 0 이라면 분류기가 이를 감지했지만, 임곗값을 8000으로 높이면 이를 놓치게 된다.

y_scores = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3,
                             method="decision_function")

적절한 임곗값을 설정하기 위해 cross_val_predict 함수를 이용하여 모든 샘플의 점수를 구한다. 여기서 예측 결과가 아닌 결정 점수를 반환받는다.

from sklearn.metrics import precision_recall_curve

precisions, recalls, thresholds = precision_recall_curve(y_train_5, y_scores)

def plot_precision_recall_vs_threshold(precisions, recalls, thresholds):
    plt.plot(thresholds, precisions[:-1], "b--", label="Precision", linewidth=2)
    plt.plot(thresholds, recalls[:-1], "g-", label="Recall", linewidth=2)

plot_precision_recall_vs_threshold(precisions, recalls, thresholds)
plt.show()

왜 정밀도 곡선이 재현율 곡선보다 울퉁불퉁할까? 임곗값을 올리더라도 정밀도가 낮아지는 일이 있기 때문. (보통은 높아져야 한다.)

또는 정밀도/재현율 트레이드오프를 선택하기 위해 재현율에 대한 정밀도 곡선을 그리는 것도 방법이다.

재현율 80% 근처에서 정밀도가 급격하게 줄어드는 것을 볼 수 있는데 이 하강점 직전을 정밀도/재현율 트레이드오프로 선택하는 것이 좋다.

정밀도 90%를 달성하는 것을 목표로 하자.

threshold_90_precision = thresholds[np.argmax(precisions >= 0.90)]

다음과 같이 90% 이상의 정밀도를 갖는 임곗값을 찾은 후, 훈련 세트에 대한 예측을 만들기 위해 predict 함수를 호출하는 대신 다음과 같이 부등호(≥)를 이용해 분류한다. 그 후정밀도와 재현율을 확인한 사진이다.

3.3.5 ROC 곡선

수신기 조작 특성 ; receiver operating characteristic (ROC) 곡선은 이진 분류에서 널리 사용하는 도구다. 정밀도/재현율 곡선과 매우 비슷하지만, ROC 곡선은 정밀도에 대한 재현율 곡선이 아니고 거짓 양성 비율 ; false positive rate (FPR)에 대한 진짜 양성 비율 ; true negative rate (TNR)의 곡선이다.

양성으로 잘못 분류한 음성 샘플의 비율을 FPR이라 하고 이는 1에서 음성으로 정확하게 분류한 음성 샘플의 비율 TNR을 뺀 값이다. 1=FPR+TNR1 = FPR + TNR

TNR특이도 ; specify 이라고 한다. 그러므로 ROC는 민감도(재현율)에 대한 1-특이도 그래프이다.

여러 임계삾에서 TPR과 FPR을 계산할 수 있다.

from sklearn.metrics import roc_curve

fpr, tpr, thresholds = roc_curve(y_train_5, y_scores)

모든 가능한 임곗값에서 진짜 양성 비율(TPR)에 대한 거짓 양성 비율(FPR)을 나타낸 곡선이다.

TPR민감도재현율이라고도 부르는데 이는 분류기가 정확 하게 감지한 양성 샘플의 비율을 말한다. 이를 진짜 양성 비율이라고 부른다. 거짓 양성 비율 FPR은 거짓 양성 수(FP)와 진짜 음성 수(TN)를 더해 총 거짓 양성 수로 나눈 값인데 양성 클래스에서 잘못된 예측의 비율이라 보는 것이 쉽다. 모르겠다면 다음을 참고해라 : 혼동행렬_기억법 , 각 용어 정리

재현율(TPR)이 높을 수록 분류기가 만드는 FPR이 늘어난다. 점선은 완전한 랜덤 분류기의 ROC곡선을 의미하는데 좋은 분류기는 최대한 이 점선으로부터 멀리 떨어져 있어야 한다.

곡선 아래 면적 ; area under the curve (AUC) 을 통해 분류기들을 비교할 수 있다. 완벽한 분류기는 ROC의 AUC가 1이고 완전한 분류기는 0.5이다.

일반적으로 양성 클래스가 드물거나 거짓 음성보다 거짓 양성이 더 중요하다면 PR 곡선을 사용한다 그렇지 않으면 ROC 곡선을 사용한다.

predict_proba() 메서드는 샘플이 행, 클래스가 열이고 샘플이 주어진 클래스에 속할 확률을 담은 배열을 반환한다.

from sklearn.ensemble import RandomForestClassifier

forest_clf = RandomForestClassifier(random_state = 42)
y_probas_forest = cross_val_predict(forest_clf, X_train, y_train_5,
																		cv=3, method = "predict_proba")

y_scores_forest= y_probas_forest[:, 1]
fpr_forest, tpr_forest, thresholds_forest = roc_curve(y_train_5, y_scores_forest)

AUC 값이 큰 것이 좋다. 따라서 이 그래프 기반으로는 Random Forest가 더 좋다는 것을 알 수 있다.

profile
🛰️ 2021 fall ~

0개의 댓글