【機器學習】--模型評估指標之混淆矩陣,ROC曲線和AUC面積

LHBlog發表於2018-03-27

一、前述

怎麼樣對訓練出來的模型進行評估是有一定指標的,本文就相關指標做一個總結。

二、具體

1、混淆矩陣

混淆矩陣如圖:

 第一個引數true,false是指預測的正確性。

 第二個引數true,postitives是指預測的結果。

 相關公式:

 

檢測正列的效果:

檢測負列的效果:

 

 

 公式解釋:

 fp_rate:

tp_rate:

recall:(召回率)

值越大越好

presssion:(準確率)

TP:本來是正例,通過模型預測出來是正列

TP+FP:通過模型預測出來的所有正列數(其中包括本來是負例,但預測出來是正列)

 值越大越好

F1_Score:

 

準確率和召回率是負相關的。如圖所示:

通俗解釋:

實際上非常簡單,精確率是針對我們預測結果而言的,它表示的是預測為正的樣本中有多少是真正的正樣本。那麼預測為正就有兩種可能了,一種就是把正類預測為正類(TP),另一種就是把負類預測為正類(FP),也就是

 

召回率是針對我們原來的樣本而言的,它表示的是樣本中的正例有多少被預測正確了。那也有兩種可能,一種是把原來的正類預測成正類(TP),另一種就是把原來的正類預測為負類(FN)。

 

其實就是分母不同,一個分母是預測為正的樣本數,另一個是原來樣本中所有的正樣本數。

2、ROC曲線

過程:對第一個樣例,預測對,閾值是0.9,所以曲線向上走,以此類推。

          對第三個樣例,預測錯,閾值是0.7 ,所以曲線向右走,以此類推。

幾種情況:

所以得出結論,曲線在對角線以上,則準確率好。

3、AUC面積

 

M是樣本中正例數

N是樣本中負例數

其中累加解釋是把預測出來的所有概率結果按照分值升序排序,然後取正例所對應的索引號進行累加

通過AUC面積預測出來的可以知道好到底有多好,壞到底有多壞。因為正例的索引比較大,則AUC面積越大。

總結:

 4、交叉驗證

為在實際的訓練中,訓練的結果對於訓練集的擬合程度通常還是挺好的(初試條件敏感),但是對於訓練集之外的資料的擬合程度通常就不那麼令人滿意了。因此我們通常並不會把所有的資料集都拿來訓練,而是分出一部分來(這一部分不參加訓練)對訓練集生成的引數進行測試,相對客觀的判斷這些引數對訓練集之外的資料的符合程度。這種思想就稱為交叉驗證。

 一般3折或者5折交叉驗證就足夠了。

 三、程式碼

 

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 檔名: mnist_k_cross_validate.py

from sklearn.datasets import fetch_mldata
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from sklearn.linear_model import SGDClassifier
from sklearn.model_selection import StratifiedKFold
from sklearn.base import clone
from sklearn.model_selection import cross_val_score
from sklearn.base import BaseEstimator #評估指標
from sklearn.model_selection import cross_val_predict
from sklearn.metrics import confusion_matrix
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score
from sklearn.metrics import precision_recall_curve
from sklearn.metrics import roc_curve
from sklearn.metrics import roc_auc_score
from sklearn.ensemble import RandomForestClassifier


# Alternative method to load MNIST, if mldata.org is down
from scipy.io import loadmat #利用Matlib載入本地資料
mnist_raw = loadmat("mnist-original.mat")
mnist = {
    "data": mnist_raw["data"].T,
    "target": mnist_raw["label"][0],
    "COL_NAMES": ["label", "data"],
    "DESCR": "mldata.org dataset: mnist_k_cross_validate-original",
}
print("Success!")
# mnist_k_cross_validate = fetch_mldata('MNIST_original', data_home='test_data_home')
print(mnist)

X, y = mnist['data'], mnist['target'] # X 是70000行 784個特徵 y是70000行 784個畫素點
print(X.shape, y.shape)
#
some_digit = X[36000]
print(some_digit)
some_digit_image = some_digit.reshape(28, 28)#調整矩陣 28*28=784 784個畫素點調整成28*28的矩陣 圖片是一個28*28畫素的圖片 每一個畫素點是一個rgb的值
print(some_digit_image)
#
plt.imshow(some_digit_image, cmap=matplotlib.cm.binary,
           interpolation='nearest')
plt.axis('off')
plt.show()
#
X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[:60000]#6/7作為訓練,1/7作為測試
shuffle_index = np.random.permutation(60000)#返回一組隨機的資料 shuffle 打亂60000中每行的值 即每個編號的值不是原先的對應的值
X_train, y_train = X_train[shuffle_index], y_train[shuffle_index] # Shuffle之後的取值
# #
y_train_5 = (y_train == 5)# 是5就標記為True,不是5就標記為false
y_test_5 = (y_test == 5)
print(y_test_5)
#這裡可以直接寫成LogGression
sgd_clf = SGDClassifier(loss='log', random_state=42)# log 代表邏輯迴歸 random_state或者random_seed 隨機種子 寫死以後生成的隨機數就是一樣的
sgd_clf.fit(X_train, y_train_5)#構建模型
print(sgd_clf.predict([some_digit]))# 測試模型 最終為5
# #
### K折交叉驗證
##總共會執行3次
skfolds = StratifiedKFold(n_splits=3, random_state=42)# 交叉驗證 3折 跑三次 在訓練集中的開始1/3 中測試,中間1/3 ,最後1/3做驗證
for train_index, test_index in skfolds.split(X_train, y_train_5):
    #可以把sgd_clf = SGDClassifier(loss='log', random_state=42)這一行放入進來,傳不同的超引數 這裡就不用克隆了
    clone_clf = clone(sgd_clf)# clone一個上一個一樣的模型 讓它不變了 每次初始隨機引數w0,w1,w2都一樣,所以設定隨機種子是一樣
    X_train_folds = X_train[train_index]#對應的是訓練集中訓練的X 沒有陰影的
    y_train_folds = y_train_5[train_index]# 對應的是訓練集中的訓練y 沒有陰影的
    X_test_folds = X_train[test_index]#對應的是訓練集中的測試的X 陰影部分的
    y_test_folds = y_train_5[test_index]#對應的是訓練集中的測試的Y 陰影部分的

    clone_clf.fit(X_train_folds, y_train_folds)#構建模型
    y_pred = clone_clf.predict(X_test_folds)#驗證
    print(y_pred)
    n_correct = sum(y_pred == y_test_folds)# 如若預測對了加和 因為true=1 false=0
    print(n_correct / len(y_pred))#得到預測對的精度 #用判斷正確的數/總共預測的 得到一個精度
# #PS:這裡可以把上面的模型生成直接放在交叉驗證裡面傳一些超引數比如阿爾法,看最後的準確率則知道什麼超引數最好。

#這是Sk_learn裡面的實現的函式cv是幾折,score評估什麼指標這裡是準確率,結果類似上面一大推程式碼
print(cross_val_score(sgd_clf, X_train, y_train_5, cv=3, scoring='accuracy')) #這是Sk_learn裡面的實現的函式cv是幾折,score評估什麼指標這裡是準確率


class Never5Classifier(BaseEstimator):#給定一個分類器,永遠不會分成5這個類別 因為正負列樣本不均勻,所以得出的結果是90%,所以只拿精度是不準確的。
    def fit(self, X, y=None):
        pass

    def predict(self, X):
        return np.zeros((len(X), 1), dtype=bool)


never_5_clf = Never5Classifier()
print(cross_val_score(never_5_clf, X_train, y_train_5, cv=3, scoring='accuracy'))#給每一個結果一個結果
# #
# #
##混淆矩陣 可以準確地知道哪一個類別判斷的不準
y_train_pred = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3)#給每一個結果預測一個概率
print(confusion_matrix(y_train_5, y_train_pred))
# #
y_train_perfect_prediction = y_train_5
print(confusion_matrix(y_train_5, y_train_5))
#準確率,召回率,F1Score
print(precision_score(y_train_5, y_train_pred))
print(recall_score(y_train_5, y_train_pred))
print(sum(y_train_pred))
print(f1_score(y_train_5, y_train_pred))

sgd_clf.fit(X_train, y_train_5)
y_scores = sgd_clf.decision_function([some_digit])
print(y_scores)

threshold = 0 # Z的大小 wT*x的結果
y_some_digit_pred = (y_scores > threshold)
print(y_some_digit_pred)

threshold = 200000
y_some_digit_pred = (y_scores > threshold)
print(y_some_digit_pred)

y_scores = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3, method='decision_function')
print(y_scores)#直接得出Score

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


def plot_precision_recall_vs_threshold(precisions, recalls, thresholds):
    plt.plot(thresholds, precisions[:-1], 'b--', label='Precision')
    plt.plot(thresholds, recalls[:-1], 'r--', label='Recall')
    plt.xlabel("Threshold")
    plt.legend(loc='upper left')
    plt.ylim([0, 1])


# plot_precision_recall_vs_threshold(precisions, recalls, thresholds)
# plt.savefig('./temp_precision_recall')

y_train_pred_90 = (y_scores > 70000)
print(precision_score(y_train_5, y_train_pred_90))
print(recall_score(y_train_5, y_train_pred_90))


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


def plot_roc_curve(fpr, tpr, label=None):
    plt.plot(fpr, tpr, linewidth=2, label=label)
    plt.plot([0, 1], [0, 1], 'k--')
    plt.axis([0, 1, 0, 1])
    plt.xlabel('False Positive Rate')
    plt.ylabel('True positive Rate')


plot_roc_curve(fpr, tpr)
plt.show()
# plt.savefig('img_roc_sgd')

print(roc_auc_score(y_train_5, y_scores))

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)
plt.plot(fpr, tpr, 'b:', label='SGD')
plt.plot(fpr_forest, tpr_forest, label='Random Forest')
plt.legend(loc='lower right')
plt.show()
# plt.savefig('./img_roc_forest')

print(roc_auc_score(y_train_5, y_scores_forest))

#
#

 

 

 

 

acc 看中整體
auc看中正例

 

相關文章