분류 문제는 회귀 분석과 달리 다양한 성능 평가 기준이 필요하다.
sklearn.metrics
서브 패키지confusion_matrix()
classfication_report()
accuracy_score(y_true, y_pred)
precision_score(y_true, y_pred)
recall_score(y_true, y_pred)
fbeta_score(y_true, y_pred, beta)
f1_score(y_true, y_pred)
분류 결과표는 타겟의 원래 클래스와 모형이 예측한 클래스가 일치하는지는 갯수로 센 결과이다.
원래 클래스는 행(row)으로 예측한 클래스는 열(column)로 나타낸다.
예측 클래스 0 | 예측 클래스 1 | 예측 클래스 2 | |
---|---|---|---|
원 클래스 0 | 원 클래스가 0, 예측 클래스가 0인 표본의 수 | 원 클래스가 0, 예측 클래스가 1인 표본의 수 | 원 클래스가 0, 예측 클래스가 2인 표본의 수 |
원 클래스 1 | 원 클래스가 1, 예측 클래스가 0인 표본의 수 | 원 클래스가 1, 예측 클래스가 1인 표본의 수 | 원 클래스가 1, 예측 클래스가 2인 표본의 수 |
원 클래스 2 | 원 클래스가 2, 예측 클래스가 0인 표본의 수 | 원 클래스가 2, 예측 클래스가 1인 표본의 수 | 원 클래스가 2, 예측 클래스가 2인 표본의 수 |
from sklearn.metrics import confusion_matrix
y_true = [2, 0, 2, 2, 0, 1]
y_pred = [0, 0, 2, 2, 0, 2]
confusion_matrix(y_true, y_pred)
클래스가 0과 1 두 종류 밖에 없는 경우에는 일반적으로 클래스 이름을 "Positive"와 "Negative"로 표시한다.
또, 분류 모형의 예측 결과가 맞은 경우, 즉 Positive를 Positive라고 예측하거나 Negative를 Negative라고 예측한 경우에는 "True"라고 하고 예측 결과가 틀린 경우, 즉 Positive를 Negative라고 예측하거나 Negative를 Positive라고 예측한 경우에는 "False"라고 한다.
이 경우의 이진 분류 결과의 명칭과 결과표는 다음과 같다.
Positive라고 예측 | Negative라고 예측 | |
---|---|---|
실제 Positive | True Positive | False Negative |
실제 Negative | False Positive | True Negative |
FDS(Fraud Detection System)는 금융 거래, 회계 장부 등에서 잘못된 거래, 사기 거래를 찾아내는 시스템을 말한다. FDS의 예측 결과가 Positive 이면 사기 거래라고 예측한 것이고 Negative 이면 정상 거래라고 예측한 것이다. 이 결과가 사실과 일치하는지 틀리는지에 따라 다음과 같이 말한다.
사기 거래라고 예측 | 정상 거래라고 예측 | |
---|---|---|
실제로 사기 거래 | True Positive | False Negative |
실제로 정상 거래 | False Positive | True Negative |
모형 트레이닝 즉 최적화에서 목적함수로 사용
$$\text{accuracy} = \dfrac{TP + TN}{TP + TN + FP + FN}$$
from sklearn.metrics import *
y_true = [0, 1, 2, 2, 2]
y_pred = [0, 0, 2, 2, 1]
target_names = ['class 0', 'class 1', 'class 2']
print(classification_report(y_true, y_pred, target_names=target_names))
ROC(Receiver Operator Characteristic) 커브는 클래스 판별 기준값의 변화에 따른 Fall-out과 Recall의 변화를 시각화한 것이다.
모든 이진 분류 모형은 판별 평면으로부터의 거리에 해당하는 판별 함수(discriminant function)를 가지며 판별 함수 값이 음수이면 0인 클래스, 양수이면 1인 클래스에 해당한다고 판별한다. 즉 0 이 클래스 판별 기준값이 된다. ROC 커브는 이 클래스 판별 기준값이 달라진다면 판별 결과가 어떻게 달라지는지는 표현한 것이다.
Scikit-Learn 의 Classification 클래스는 판별 함수 값을 계산하는 decision_function
메서드를 제공한다. ROC 커브는 이 판별 함수 값을 이용하여 다음과 같이 작성한다.
일반적으로 클래스 판별 기준이 변화함에 따라 Recall과 Fall-out은 같이 증가하거나 감소한다. Fall-out보다 Recall이 더 빠르게 증가하는 모형은 좋은 모형으로 생각할 수 있다.
from sklearn.datasets import make_classification
X, y = make_classification(n_samples=10000, weights=[0.9, 0.1], random_state=1)
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
model1 = LogisticRegression().fit(X, y)
y_hat1 = model1.predict(X)
model2 = SVC(gamma=0.0026, C=10, probability=True).fit(X, y)
y_hat2 = model2.predict(X)
print(confusion_matrix(y, y_hat1))
print(confusion_matrix(y, y_hat2))
print(classification_report(y, model1.predict(X)))
print(classification_report(y, model2.predict(X)))
Scikit-Learn에서 ROC 커브를 그릴 때는 roc_curve
명령을 사용한다. 인수로는 타겟 y 벡터와 판별함수 벡터(혹은 확률 벡터)를 넣는다.
from sklearn.metrics import roc_curve
fpr1, tpr1, thresholds1 = roc_curve(y, model1.decision_function(X))
fpr2, tpr2, thresholds1 = roc_curve(y, model2.decision_function(X))
또는 다음처럼 해도 같은 결과를 얻을 수 있다.
fpr1, tpr1, thresholds1 = roc_curve(y, model1.predict_proba(X)[:, 1])
fpr2, tpr2, thresholds1 = roc_curve(y, model2.predict_proba(X)[:, 1])
plt.plot(fpr1, tpr1, label="Logistic Regression")
plt.plot(fpr2, tpr2, label="Kernel SVM")
plt.legend()
plt.plot([0, 1], [0, 1], 'k--', label="random guess")
plt.xlabel('False Positive Rate (Fall-Out)')
plt.ylabel('True Positive Rate (Recall)')
plt.title('Receiver operating characteristic example')
plt.show()
N = 500
plt.subplot(211)
plt.plot(model1.decision_function(X[:N]) * 0.1 + 1)
plt.plot(y[:N], 'o', alpha=0.5)
plt.title("Logistic Regression")
plt.subplot(212)
plt.plot(model2.decision_function(X[:N]) + 1)
plt.plot(y[:N], 'o', alpha=0.5)
plt.title("Kernel SVM")
plt.xlabel("sample number")
plt.tight_layout()
plt.show()
다중 클래스에 대해서는 ROC 커브를 그릴 수 없으므로 클래스가 여러개이면 각각의 클래스에 대해 OvR 문제를 가정하여 ROC 커브를 그린다.
from sklearn.naive_bayes import GaussianNB
from sklearn.datasets import load_iris
from sklearn.preprocessing import label_binarize
iris = load_iris()
X = iris.data
y = label_binarize(iris.target, [0, 1, 2])
fpr = [None] * 3
tpr = [None] * 3
thr = [None] * 3
for i in range(3):
model = GaussianNB().fit(X, y[:, i])
fpr[i], tpr[i], thr[i] = roc_curve(y[:, i], model.predict_proba(X)[:, 1])
plt.plot(fpr[i], tpr[i])
plt.xlabel('False Positive Rate (Fall-Out)')
plt.ylabel('True Positive Rate (Recall)')
plt.show()
AUC는 ROC curve의 면적을 뜻한다. Fall-Out 대비 Recall 값이 클 수록 AUC가 1에 가까운 값이며 민감한 모형이다.
from sklearn.metrics import auc
auc(fpr1, tpr1), auc(fpr2, tpr2)
Multi label(output) 문제도 위의 강의처럼 분류(classification) 성능 평가를 해서 precision을 구하고자 했는데
어떻게 계산을 해야하는지 계산식이 만들어지질 않네요
skilearn 홈페이지의 설명을 보아도 Multi label이 있을때 어떻게 해야할지 이해가 되지않습니다.
예시를 들어서 설명해주시거나 강의자료를 더 보완해주실 수 있을까요?
http://scikit-learn.org/stable/modules/model_evaluation.html
전 : print(confusion_matrix(iris.target, model1.predict(iris.data)))
후 : print(confusion_matrix(iris.target, model.predict(iris.data)))
model1 -> model
이 라인 밑으로도 model1 이라고 오타가 난 부분이 몇군데 있네요 ^^;