詳細講解分類模型評估

本篇博客讓我們來學習分類模型評估。
涉及到的知識點有:

  1. 混淆矩陣
  2. 評估指標(正確率、準確率、召回率、調和平均值F1)
  3. ROC和AUC

那我們快開始吧!

在這裏插入圖片描述

1、分類模型

分類問題在我們日常生活中處處可見,比如我們對帥哥的分類,可能對帥哥分爲非常帥和一般帥。比如我們平時刷淘寶,淘寶根據我們平時的喜好給我們推送產品,那我們就會把產品分爲感興趣和不感興趣兩類。
上述所說的問題就是典型的分類問題,確切的說其實就是二分類問題。
能夠解決這些二分類問題的數學模型就被稱爲二分類模型
用數學的方式表達就是,給定自變量X,代入到我們的分類模型F,會輸出因變量y,y的取值爲0或1,其中0代表負樣本(一般帥的帥哥、不感興趣的推送),1代表正樣本(非常帥氣的帥哥、感興趣的推送)。

主題:如何對分類模型進行評估

目標:

  • 能夠熟知混淆矩陣的含義。
  • 能夠使用各種指標對分類模型進行評估。
  • 能夠獨立繪製ROC曲線,並熟悉該曲線細節。
  • 能夠對樣本不均衡進行處理(擴展內容)。

2、混淆矩陣

混淆矩陣,可以用來評估模型分類的正確性。
該矩陣是一個方陣,矩陣的數值用來表示分類器預測的結果,包括真正例(True Positive),假正例(False Positive),真負例(True Negative),假負例(False Negative)。
在這裏插入圖片描述
矩陣的形狀是2 x 2,其中, - 矩陣的左上角表示,預測值爲1,實際值爲1(True Positive,簡稱TP); - 右上角表示預測值爲1,實際值爲0(False Positive,簡稱FP); - 左下角表示預測值爲0,實際值爲1(False Negative,簡稱FN); - 右下角表示預測值爲0,實際值爲0(True Negative,簡稱TN);

真負例(TN)+ 假正例(FP)——每個類別真實存在的負例的數量
假負例(FN)+ 真正例(TP)——每個類別真實存在的正例的數量
真負例(TN)+ 假負例(FN)——每個類別預測的真負例數量
假正例(FP)+ 真正例(TP)——每個類別預測的真正例數量

其中:

TP:真正例,實際爲正預測爲正;
FP:假正例,實際爲負但預測爲正;
FN:假反例,實際爲正但預測爲負;
TN:真反例,實際爲負預測爲負

接下來,我們通過數據來看下鳶尾花的混淆矩陣:

import numpy as np
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
# 混淆矩陣
from sklearn.metrics import confusion_matrix
import matplotlib.pyplot as plt
import warnings

plt.rcParams["font.family"] = "SimHei"
plt.rcParams["axes.unicode_minus"] = False
plt.rcParams["font.size"] = 12
warnings.filterwarnings("ignore")

iris = load_iris()  #導入鳶尾花數據集
X, y = iris.data, iris.target
X = X[y != 0, 2:]
y = y[y != 0]
y[y == 1] = 0
y[y == 2] = 1
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=2)
lr = LogisticRegression()  #使用邏輯迴歸
lr.fit(X_train, y_train)
y_hat = lr.predict(X_test)
# 根據傳入的真實值與預測值,創建混淆矩陣。
matrix = confusion_matrix(y_true=y_test, y_pred=y_hat)
print(matrix)

輸出結果:
在這裏插入圖片描述
我們還可以對其進行可視化操作:

mat = plt.matshow(matrix, cmap=plt.cm.Blues, alpha=0.5)    #cmap 指定顏色圖色系,alpha透明度
label = ["負例", "正例"]
ax = plt.gca()
ax.set(xticks=np.arange(matrix.shape[1]), yticks=np.arange(matrix.shape[0]),
        xticklabels=label, yticklabels=label, title="混淆矩陣可視化\n",
        ylabel="真實值", xlabel="預測值")
for i in range(matrix.shape[0]):
    for j in range(matrix.shape[1]):
        plt.text(x=j, y=i, s=matrix[i, j], va="center", ha="center")
a, b = ax.get_ylim()
ax.set_ylim(a + 0.5, b - 0.5)
plt.show()

代碼解析:
matshow( ) 繪製矩陣,alpha 透明度
結果:
在這裏插入圖片描述
練習:

關於混淆矩陣,說法正確的是( ABCD)。【不定項】
A 混淆矩陣可以用來評估分類模型。
B 混淆矩陣中,TP與TN的數值越大,則分類的效果越好。
C 混淆矩陣一行元素的和代表某個類別的實際數量。
D 混淆矩陣一列元素的和代表某個類別的預測數量。

3、評估指標

對於分類模型,我們可以提取如下的評估指標:

  • 正確率(accuracy)
  • 精準率(precision)
  • 召回率(recall)
  • F1(調和平均值)

3.1 正確率

正確率(準確率)定義如下:
衡量所有樣本被分類準確的比例。
Accuracy = (TP+TN) / (TP+FP+TN+FN)
在這裏插入圖片描述
預測正確的數量除以總數量。

3.2 精準率

查準率(精準率)定義如下:
衡量正樣本的分類準確率,就是說被預測爲正樣本的樣本有多少是真的正樣本。
Precision = TP / (TP+FP)
在這裏插入圖片描述
精準率只考慮正例。

3.3 召回率

查全率(召回率)定義如下:
表示分類正確的正樣本佔總的正樣本的比例。
Recall = TP / (TP+FN)
在這裏插入圖片描述

3.4 調和平均值F1

F值(F1-scores)調和平均值F1定義如下:
精確率和召回率的調和平均。
精準率Precision和召回率Recall加權調和平均數,並假設兩者一樣重要。
在這裏插入圖片描述
F1-score = (2Recall*Precision) / (Recall + Precision)

精準率和召回率是一對矛盾的度量。一般來說,精準率高時,召回率往往偏低;而召回率高時,精準率往往偏低。通常只有在一些簡單任務中,纔可能使二者都很高。

最好的分類器當然是準確率、精確率,召回率都爲1,但實際場景中幾乎是不可能的,而且精確率和召回率往往會相互影響,一個高了另一個會有所下降,因此在實際應用中要根據具體需求做適當平衡。

讓我們做個練習加深下印象吧!

以下說法正確的是( C )。
A 使用正確率去評估一個分類模型,效果會比精準率更好。
B 使用精準率去評估一個分類模型,效果會比召回率更好。
C 精準率與召回率通常要聯合使用。
D 精準率與召回率如果有一個值較低,F1值也可能會較高。

如果精準率和召回率我們只能選擇重視一個,我們會更看重( C )。
A 精準率。
B 召回率。
C 具體場景不同,重視誰也會不同。

接下來我們通過程序來說明下:

from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score

print("正確率:", accuracy_score(y_test, y_hat))
# 默認將1類別視爲正例,可以通過pos_label參數指定。
print("精準率:", precision_score(y_test, y_hat))
print("召回率:", recall_score(y_test, y_hat))
print("F1調和平均值:", f1_score(y_test, y_hat))
# 我們也可以調用邏輯迴歸模型對象的score方法,也能獲取正確率。
# 但是需要注意,score方法與f1_score函數的參數是不同的。
print("score方法計算正確率:", lr.score(X_test, y_test))

結果:
在這裏插入圖片描述
除此之外,我們也可以使用classification_report函數來查看模型的分類統計信息,該方法會返回字符串類型,給出相關的分類指標評估值。

from sklearn.metrics import classification_report

print(classification_report(y_true=y_test, y_pred=y_hat))

結果:
在這裏插入圖片描述

練習:

如果使用精準率與召回率評估二分類模型時,我們應該將哪個類別設置爲正例? (B)
A 隨意
B 關注的類別
C 不關注的類別

4、ROC和AUC

ROC(Receiver Operating Characteristic)曲線和AUC常被用來評價一個二值分類器(binary classifier)的優劣。

4.1 ROC曲線

ROC曲線(Receiver Operating Characteristic——受試者工作特徵曲線),使用圖形來描述二分類系統的性能表現。圖形的縱軸爲真正例率(TPR——True Positive Rate),橫軸爲假正例率(FPR——False Positive Rate)。其中,真正例率與假正例率定義爲:
在這裏插入圖片描述
ROC曲線通過真正例率(TPR)與假正例率(FPR)兩項指標,可以用來評估分類模型的性能。真正例率與假正例率可以通過移動分類模型的閾值而進行計算。隨着閾值的改變,真正例率與假負例率也會隨之發生改變,進而就可以在ROC曲線座標上,形成多個點。

ROC曲線反映了FPR與TPR之間權衡的情況,通俗來說,即在TPR隨着FPR遞增的情況下,誰增長得更快,快多少的問題。TPR增長得越快,曲線越往上凸,模型的分類性能就越好。

ROC曲線如果爲對角線,則可以理解爲隨機猜測。如果在對角線以下,則其性能比隨機猜測還要差。如果ROC曲線真正例率爲1,假正例率爲0,即曲線爲與構成的折線,則此時的分類器是最完美的。

下圖就是ROC曲線的一個示意圖:
在這裏插入圖片描述
ROC曲線橫座標是FPR(False Positive Rate),縱座標是TPR(True Positive Rate)
接下來我們考慮ROC曲線圖中的四個點和一條線。

第一個點,(0,1),即FPR=0, TPR=1,這意味着FN(false negative)=0,並且FP(false
positive)=0。這是一個完美的分類器,它將所有的樣本都正確分類。
第二個點,(1,0),即FPR=1,TPR=0,類似地分析可以發現這是一個最糟糕的分類器,因爲它成功避開了所有的正確答案。
第三個點,(0,0),即FPR=TPR=0,即FP(false positive)=TP(true
positive)=0,可以發現該分類器預測所有的樣本都爲負樣本(negative)。
第四個點(1,1),分類器實際上預測所有的樣本都爲正樣本。經過以上的分析,我們可以斷言,ROC曲線越接近左上角,該分類器的性能越好。

如何畫ROC曲線:

對於一個特定的分類器和測試數據集,顯然只能得到一組FPR和TPR結果,而要得到一個曲線,我們實際上需要一系列FPR和TPR的值,這又是如何得到的呢?我們先來看一下wikipedia上對ROC曲線的定義:

A receiver operating characteristic curve, i.e. ROC curve, is a
graphical plot that illustrates the diagnostic ability of a binary
classifier system as its discrimination threshold is varied.
譯:ROC曲線是由一系列因區分閾值變化產生的點,用於描述二分類模型的判斷能力

這裏的關鍵在於 “its discrimination threshold is varied” ,因爲對於一個二分類模型,它的輸出結果其實是判斷這個樣本屬於正樣本的概率值,假如我們已經得到了所有樣本的概率輸出(屬於正樣本的概率),現在的問題是如何改變“discrimination threashold”?我們根據每個測試樣本屬於正樣本的概率值從大到小排序。下圖是一個示例,圖中共有20個測試樣本,“Class”一欄表示每個測試樣本真正的標籤(p表示正樣本,n表示負樣本),“Score”表示每個測試樣本屬於正樣本的概率
在這裏插入圖片描述
然後我們按照樣本的score值,從大到小依次作爲閾值,當樣本score值大於等於閾值時則判定爲正樣本,否則爲負樣本。
例如第一個閾值取0.9,這時只有id=1的樣本被預測爲正樣本,其餘都是負樣本,此時TPR=1/1+9=0.1, FPR=0/0+10=0。還例如:對於圖中的第4個樣本,其“Score”值爲0.6,那麼樣本1,2,3,4都被認爲是正樣本,因爲它們的“Score”值都大於等於0.6,而其他樣本則都認爲是負樣本。

詳細如下:
在這裏插入圖片描述
由此我們便得到了一組(FPR,TPR)的值,可以繪製出ROC曲線:
在這裏插入圖片描述
當我們將threshold設置爲1和0時,分別可以得到ROC曲線上的(0,0)和(1,1)兩個點。將這些(FPR,TPR)對連接起來,就得到了ROC曲線。當threshold取值越多,ROC曲線越平滑。

4.2 AUC

AUC(Area Under the Curve)是指ROC曲線下的面積,使用AUC值作爲評價標準是因爲有時候ROC曲線並不能清晰的說明哪個分類器的效果更好,而AUC作爲數值可以直觀的評價分類器的好壞,值越大越好。
在這裏插入圖片描述
AUC是ROC曲線下的面積。
AUC的取值爲[0.5-1],0.5對應於對角線的“隨機猜測模型”。
AUC值是一個概率值,當你隨機挑選一個正樣本以及負樣本,當前的分類算法根據計算得到的Score值將這個正樣本排在負樣本前面的概率就是AUC值,AUC值越大,當前分類算法越有可能將正樣本排在負樣本前面,從而能夠更好地分類。

從AUC判斷分類器(預測模型)優劣的標準:
在這裏插入圖片描述

例如一個模型的AUC是0.7,其含義可以理解爲:給定一個正樣本和一個負樣本,在70%的情況下,模型對正樣本的打分(概率)高於對負樣本的打分。

三種AUC值示例:
在這裏插入圖片描述
簡單說:AUC值越大的分類器,正確率越高。

那麼爲什麼要用AUC作爲二分類模型的評價指標呢?爲什麼不直接通過計算準確率來對模型進行評價呢?
因爲機器學習中的很多模型對於分類問題的預測結果大多是概率,即屬於某個類別的概率,如果計算準確率的話,就要把概率轉化爲類別,這就需要設定一個閾值,概率大於某個閾值的屬於一類,概率小於某個閾值的屬於另一類,而閾值的設定直接影響了準確率的計算。也就是說AUC越高說明閾值分割所能達到的準確率越高。

小練習:

以下說法正確的是( ABD)。【不定項】
A 隨着閾值的降低,TPR與FPR都會增大。
B TPR與召回率的值是相同的。
C 如果AUC的值非常低,例如,0.1,則該模型效果很差,也很難調優。
D 無論是什麼分類模型,ROC曲線一定會經過(0, 0)與(1,1)這兩個點。

4.3 ROC曲線程序示例

我們首先來看一個簡單的程序示例,藉此來說明sklearn庫中,ROC曲線的實現細節。

4.3.1 roc_curve函數的參數
import numpy as np
from sklearn.metrics import roc_curve, auc, roc_auc_score
y = np.array([0, 0, 1, 1])
scores = np.array([0.2, 0.4, 0.35, 0.8])
# 返回ROC曲線相關值。返回FPR,TPR與閾值。當分值達到閾值時,將樣本判定爲正類,
# 否則判定爲負類。
# y_true:二分類的標籤值(真實值)。
# y_score:每個標籤(數據)的分值或概率值。當該值達到閾值時,判定爲正例,否則判定爲負例。
# 在實際模型評估時,該值往往通過決策函數(decision_function)或者概率函數(predict_proba)獲得。
# pos_label:指定正例的標籤值。
fpr, tpr, thresholds = roc_curve(y, scores, pos_label=1)
print(f"fpr:{fpr}")
print(f"tpr:{tpr}")
print(f"thresholds:{thresholds}")
# auc與roc_auc_score函數都可以返回AUC面積值,但是注意,兩個函數的參數是不同的。
print("AUC面積值:", auc(fpr, tpr))
print("AUC面積得分:", roc_auc_score(y_true=y, y_score=scores))
#### 3.3.2 roc_curve函數的返回值

結果:
在這裏插入圖片描述
1.8 是怎麼來的?
1.8是閾值中最大值+1(0.8+1)得來的。爲什麼這麼算?因爲要使得最開始得到的所有閾值都不會超過這個值,才能過(0,0)和(1,1)這兩個點。

4.3.2 roc_curve函數的返回值

roc_curve函數具有3個返回值:

  • fpr 對應每個閾值(thresholds)下的fpr值。
  • tpr 對應每個閾值(thresholds)下的tpr值。
  • thresholds 閾值。

roc_curve函數會從y_score參數中,選擇部分元素作爲閾值(選擇哪些元素屬於實現細節,會根據sklearn版本的不同,也可能會有所差異。),然後進行降序排列,作爲roc_curve函數的第3個返回值(thresholds)。同時,根據thresholds中的每個元素(閾值),分別計算fpr與tpr。

iris = load_iris()
X, y = iris.data, iris.target
X = X[y != 0, 2:]
y = y[y != 0]
y[y == 1] = 0
y[y == 2] = 1
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25,
random_state=2)
# lr = LogisticRegression(multi_class="multinomial", solver="lbfgs")
lr = LogisticRegression(multi_class="ovr", solver="liblinear")
lr.fit(X_train, y_train)
# 使用概率來作爲每個樣本數據的分值。
probo = lr.predict_proba(X_test)
fpr, tpr, thresholds = roc_curve(y_true=y_test, y_score=probo[:, 1],
pos_label=1)
display(probo[:, 1])
# 從概率中,選擇若干元素作爲閾值,每個閾值下,都可以確定一個tpr與fpr,
# 每個tpr與fpr對應ROC曲線上的一個點,將這些點進行連接,就可以繪製ROC曲線。
display(thresholds)

結果:
在這裏插入圖片描述

# 隨着閾值的不斷降低,fpr與tpr都在不斷的增大。
fpr, tpr

結果:
在這裏插入圖片描述

4.3.3 繪製ROC曲線
有了fpr與tpr的值,繪製ROC曲線是非常容易的,只不過是最簡單的一個plot而已。
plt.figure(figsize=(10, 6))
plt.plot(fpr, tpr, marker="o", label="ROC曲線")
plt.plot([0,1], [0,1], lw=2, ls="--", label="隨機猜測")
plt.plot([0, 0, 1], [0, 1, 1], lw=2, ls="-.", label="完美預測")
plt.xlim(-0.01, 1.02)
plt.ylim(-0.01, 1.02)
plt.xticks(np.arange(0, 1.1, 0.1))
plt.yticks(np.arange(0, 1.1, 0.1))
plt.xlabel("False Positive Rate(FPR)")
plt.ylabel("True Positive Rate(TPR)")
plt.grid()
plt.title(f"ROC曲線-AUC值爲{auc(fpr, tpr):.2f}")
plt.legend()
plt.show()

在這裏插入圖片描述

5、總結

混淆矩陣的含義。
正確率,精準率,召回率與調和平均值F1的含義。
ROC與AUC。

在這裏插入圖片描述
參考資料:
1、https://blog.csdn.net/zuolixiangfisher/article/details/81328297
2、https://www.jianshu.com/p/2feb00839154
3、https://www.cnblogs.com/kamekin/p/9788730.html
4、https://www.jianshu.com/p/c61ae11cc5f6

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章