Confusion Matrix
그냥 단순히 정확도만으로 성능을 평가하면 전에 1편에서봤던 예시처럼 오류가 난다.
그래서 분류기의 성능을 평가할때 더좋은방법이 Confusion Matrix라는것이 있다. 개념은 간단한데, 예를들어 5를 3으로 구분한 경우 (miss match)까지 카운트해서 performance를 평가한다. 이것또한 scipy의 confusion 함수로 쉽게 구현할수가있다.
from sklearn.model_selection import cross_val_predicty_train_pred = cross_val_predict(sgd_clf, X_train, y_train_5, cv=5)
cross_val_predict함수는 cross_val_score함수와 거의 비슷하지만, 한가지다른점은 cross_val_score함수는 평가결과점수를 반영하지만, corss_val_predict는 각 테스트케이스의 결과를 반영한다(True, False로 반환, 따라서 NDarray로 반환한다.)
이제 해당 반환된 객체를 가지고 confusion_matrix를 만들어보자.
from sklearn.metrics import confusion_matrixprint(confusion_matrix(y_train_5, y_train_pred))
y_train_5는 좀전에 구했었던, 5값제외한 모든것은 False로 되어있는 list이고, y_train_pred는 결과값의 True,False가 된다.
결과값 : [[53595 984]
[ 1702 3719]]
위와같이 출력되며, 각 cell의 의미는 다음과같다. (랜덤값이라서 결과값이 예제와 다를수도있다.)
52743 : 전체 데이터중에서 5가 아닌것을 잘 골라낸것. (True Negative)
1832 : 전체 데이터중에서 5가아닌데 5라고 골라낸것. (False Positive)
1333 : 전체 데이터중에서 5인데 5가아니라고 골래낸것. (False Negative)
4088 : 전체 데이터중에서 5인데 5라고 잘 골라낸것. (True Positive)
위와같은 조건으로 precision과 recall을 구할수가있다.
해당값을 또 구하는게 귀찮으면.. 함수를 사용해서 간편하게 구할수가있다.
from sklearn.metrics import precision_score, recall_score
print(precision_score(y_train_5, y_train_pred)) # == 3719 / (3719 + 984)
print(recall_score(y_train_5, y_train_pred)) # == 3719 / (3719+ 1702)
결과값은 뭐 항상 다르겠지만, 반환값의 의미는 precision, recall로 똑같다.
precision과 recall을 두개 결합하여서 하나의 방정식으로 만들수가있다.
F1 점수라고 불리며, harmonic mean으로 분류할수있다.
harmonic mean과 regular mean이 있는데,
regular mean은 모든 값을 똑같이 취급(equally)하지만, harmonic mean은 더적은 값(low values)에 비중(weight)를 많이준다.
그 결과로 classifier는 recall과 precision값이 둘다 높아야지 높은 F1값을 얻을수가있다.
F1의 방정식은 다음과같다.
이것또한 간편하게 구할수가있다.
from sklearn.metrics import f1_score
print(f1_score(y_train_5, y_train_pred))
이렇게 구하면 정확한 f1의 결과값을 도출해낼수가 있다.
f1의 값이 높다고 항상 좋은것만은 아니다.
예를들어 내가 어린이에게 안전한 비디오만 보여주겠다고 생각하면, 많은 좋은 비디오(low recall) 는 버리고, 안전한 소수의 비디오만(high precision)골라내는 분류기를 만들려면 무작정 f1값이 높다고 좋은것도 아니다.
상황에 따라서 적절히 분류해내야 한다.
그래서 이상황과같이 recall값과 precision값을 적절히 조절해야할때가 있을때 Thresholds라는 것을 사용한다.
각값마다 decision function을 이용해서 Thresholds란 값을 구하고 Thresholds이하의 값은 False, 이상은 True로 판단한다.
예를들어,
Precision 75% , Recall 100% 일때 Threshold는 5000이고,
Threshold 이하의 값일때는 값을 다 5가 아닌것으로 판단하고, 이상은 다 5로판단.
Precision 80%, Recall 67% 일때는 10000,
Precision 100%, Recall 50% 일때는 15000일때 등을 계산하면 Thresholds값의 변화에 따라서 같은 X값이라도(이미지) 모델이 판단을 다르게 할수도있다.
그렇다면 어떻게해야지 좋은 Thresholds값을 선정할수가 있을까 ??
먼저 전에 이용했던 cross_val_predict함수에 인자를 다음과 같이 추가하자,
y_scores = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3, method="decision_function")
그럼 각 데이터(instance라고도 한다)들의 threshold값을 list로 반환하게된다.
이제 이 데이터를 가지고 프레임워크를 이용해서 간단하게 precisions,recalls,thresholds값을 얻을수있다.
from sklearn.metrics import precision_recall_curveprecisions, recalls, thresholds = precision_recall_curve(y_train_5, y_scores)
해당값들은 리스트로 들어오게되는데,
한눈에 보기힘드니깐, matplot을 이용해서 (X축은 thresholds, y축은 precisions와 recalls 로 두고 plot해보자 코드는 생략)

그러면 위와같이 Precision과 Recall이 반비례하는 모양의 그래프가 잘나온다.
만약에 Precision의 값을 90%으로 맞추고싶다면 어떻게해야할까 ?
그림에서 precision이 90%가 되는값의 x값이 대략 300000이라고 하고,
y_train_pred_90 = (y_scores > 300000)print(precision_score(y_train_5, y_train_pred_90)) # == 3719 / (3719 + 984)
print(recall_score(y_train_5, y_train_pred_90))
이렇게 인코딩(?) 을 해준후에,값을 확인하면 된다.
ROC Curve
또 다른 측정방법으로 ROC Curve란것이있다. (Receiver Operating Characteristic)
Precision/Recall curve와 비슷하지만 ROC Curve는 True positive 와 False positive 에 관한 측정법이다.
from sklearn.metrics import roc_curve
fpr, tpr, thresholds = roc_curve(y_train_5, y_scores)
위와같이 간단하게 값을 구할수가있다. (False Positive Rate, True Positive Rate, Thresholds 가 반환됨.)
해당값을 matplot을 써서 그래프로 나타낸다면,

위 그림과 같이 나오고,
TPR이 높아질수록, FPR도 높아지게 된다.
커브밑에 점선은 기준선을 나타내는데, ROC커브가 기준선에서 멀어질수록 성능이좋다. 또한 ROC커브의 밑 넓이가 1에 가까울수록 성능이 좋다고 판단할수있다.
ROC커브 밑넓이를 나타내는 용어가 area under the curve:AUC 라고하며, 1에 가까울수록 성능이좋고, 반대로 0.5에 가까울수록성능이 나쁘다고 판단할수있다.
Scikit-learn에서 제공하는 함수를 이용해서 AUC를 구해보자.
from sklearn.metrics import roc_auc_score
roc_auc_score(y_train_5, y_scores)
위와같이 auc의 값을 쉽게 구할수가 있다.
여태까지 SGDClassifier를 이용했다면, 이제 RandomForestClassifier를 이용해서 두개의 ROC커브와 AUC스코어를 비교해보자.
from sklearn.ensemble import RandomForestClassifier
forest_clf = RandomForestClassifier(random_state=42)
y_probs_forest = cross_val_predict(forest_clf, X_train, y_train_5, cv=3, method="predict_proba")
y_scores_forest = y_probs_forest[:, 1]
fpr_forest, tpr_forest, thresholds_forest = roc_curve(y_train_5, y_scores_forest)
위와같이 RandomForest 알고리즘을 사용한다면,
ROC값이 더 좋은 분류기를 얻을수가있다.
덧글