一、 混淆矩陣
在機器學習領域,混淆矩陣(Confusion Matrix),又稱為「可能性矩陣」或「錯誤矩陣」。混淆矩陣是可視化工具,特别用于監督學習,在無監督學習一般叫做比對矩陣。在圖像精度評價中,主要用于比較分類結果和實際測得值,可以把分類結果的精度顯示在一個混淆矩陣裡面。
混淆矩陣的結構一般如下圖表示
混淆矩陣表達的含義:
TP(True Positive) :将正類預測為正類數,真實為0,預測為0
FN(False Negative):将正類預測為負類數,真實為0,預測為1
FP(False Positive) :将負類預測為正類數,真實為1,預測為0
TN(True Negative) :将負類預測為負類數,真實為1,預測為1
該矩陣常用于易于了解的二分類問題,但通過向混淆矩陣添加更多行和列,也可輕松應用于多分類問題。
舉例:如有150個樣本資料,預測為類I,類II,類III 各為50個。分類結束後得到的混淆矩陣為:
每一行之和表示該類别的真實樣本數量,每一列之和表示被預測為該類别的樣本數量。
第1行第1列中的43表示有43個實際歸屬第一類的執行個體被預測為第一類,同理,第1行第2列的2表示有2個實際歸屬為第一類的執行個體被錯誤預測為第二類。
混淆矩陣是對分類問題預測結果的總結。使用計數值彙總正确和不正确預測的數量,并按每個類進行細分,這是混淆矩陣的關鍵所在。
混淆矩陣顯示了分類模型的在進行預測時會對哪一部分産生混淆。它不僅可以讓您了解分類模型所犯的錯誤,更重要的是可以了解哪些錯誤類型正在發生。正是這種對結果的分解克服了僅使用分類準确率所帶來的局限性。
二、分類名額
從混淆矩陣當中,可以得到更進階的分類名額:Accuracy(精确率),Precision(正确率或者準确率),Recall(召回率),Specificity(特異性),Sensitivity(靈敏度)。
2.1 精确率(Accuracy)
精确率是最常用的分類性能名額。可以用來表示模型的精度,即模型識别正确的個數/樣本的總個數。一般情況下,模型的精度越高,說明模型的效果越好。
Accuracy = (TP+TN)/(TP+FN+FP+TN)
2.2 正确率或者準确率(Precision)
又稱為查準率,表示在模型識别為正類的樣本中,真正為正類的樣本所占的比例。一般情況下,查準率越高,說明模型的效果越好。
Precision = TP/(TP+FP)
2.3 召回率(Recall)
召回率又稱為查全率,召回率表現出在實際正樣本中,分類器能預測出多少。
Recall(召回率)= Sensitivity(敏感名額,True Positive Rate,TPR)= 查全率
表示的是,模型正确識别出為正類的樣本的數量占總的正類樣本數量的比值。一般情況下,Recall越高,說明有更多的正類樣本被模型預測正确,模型的效果越好。
Recall = TP/(TP+FN)
查準率和查全率是一對沖突的名額。一般來說,查準率高時,查全率往往偏低;當查全率高時,查準率往往偏低。
2.4 精确率(Accuracy)和正确率(Precision)的差別
精确率(Accuracy),不管是哪個類别,隻要預測正确,其數量都放在分子上,而分母是全部資料量,說明這個精确率是對全部資料的判斷。
而正确率(Precision)在分類中對應的是某個類别,分子是預測該類别正确的數量,分母是預測為該類别的全部數量。
即:Accuracy是對分類器整體上的精确率的評價,而Precision是分類器預測為某一個類别的精确評價。
2.5 Specificity(特異性)
特異性名額,表示的是模型識别為負類的樣本的數量,占總的負類樣本數量的比值。負正類率(False Positive Rate, FPR),計算公式為:
FPR=FP/(TN+FP)
計算的是模型錯識别為正類的負類樣本占所有負類樣本的比例,一般越低越好。
Specificity = 1 - FPR
2.6 Fβ_Score
Fβ的實體意義就是将正确率和召回率的一種權重平均,在合并的過程中,召回率的權重是正确率的β倍。
F1分數認為召回率和正确率同等重要,F2分數認為召回率的重要程度是正确率的2倍,而F0.5分數認為召回率的重要程度是正确率的一半。比較常用的是F1分數(F1 Score),是統計學中用來衡量二分類模型精确度的一種名額。
F1_Score:數學定義為 F1分數,又稱為平衡F分數(Balanced Score),它被定義為正确率和召回率的調和平均數。在 β=1 的情況,F1-Score的值是從0到1的,1是最好,0是最差。
是以我們知道,計算Precision,Recall,Specificity等隻是計算某一分類的特性,而Accuracy和F1-Score是判斷分類模型總體的标準。
三、ROC 曲線
橫坐标 :1-Specificity,僞正類率(False positive rate,FPR),預測為正但實際為負的樣本占所有負例樣本的比例。
縱坐标:Sensitivity,真正類率(True positive rate,TPR),預測為正且實際為正的樣本占所有正例樣本 的比例。
在一個二分類模型中,假設采用邏輯回歸分類器,其給出針對每個執行個體為正類的機率,那麼通過設定一個門檻值如0.6,機率大于等于0.6的為正類,小于0.6的為負類。對應的就可以算出一組(FPR,TPR),在平面中得到對應坐标點。随着門檻值的逐漸減小,越來越多的執行個體被劃分為正類,但是這些正類中同樣也摻雜着真正的負執行個體,即TPR和FPR會同時增大。門檻值最大時,對應坐标點為(0,0),門檻值最小時,對應坐标點(1,1)。
如下面這幅圖,(a)圖中實線為ROC曲線,線上每個點對應一個門檻值。
① 理想情況下,TPR應該接近1,FPR應該接近0。ROC曲線上的每一個點對應于一個threshold,對于一個分類器,每個threshold下會有一個TPR和FPR。比如Threshold最大時,TP=FP=0,對應于原點;Threshold最小時,TN=FN=0,對應于右上角的點(1,1)。
② P和N得分不作為特征間距離d的一個函數,随着門檻值theta增加,TP和FP都增加。
3.1 如何畫ROC曲線
對于一個特定的分類器和測試資料集,顯然隻能得到一個分類結果,即一組FPR和TPR結果,而要得到一個曲線,我們實際上需要一系列FPR和TPR的值,這又是如何得到的呢?我們先來看一下Wikipedia上對ROC曲線的定義:
In signal detection theory, a receiver operating characteristic (ROC), or simply ROC curve, is a graphical plot which illustrates the performance of a binary classifier system as its discrimination threshold is varied.
問題在于"as its discrimination threashold is varied"。如何了解這裡的"discrimination threashold"呢?我們忽略了分類器的一個重要功能"機率輸出",即表示分類器認為某個樣本具有多大的機率屬于正樣本(或負樣本)。通過更深入地了解各個分類器的内部機理,我們總能想辦法得到一種機率輸出。通常來說,是将一個實數範圍通過某個變換映射到(0,1)區間。
假如我們已經得到了所有樣本的機率輸出(屬于正樣本的機率),現在的問題是如何改變"discrimination threashold"?我們根據每個測試樣本屬于正樣本的機率值從大到小排序。下圖是一個示例,圖中共有20個測試樣本,"Class"一欄表示每個測試樣本真正的标簽(p表示正樣本,n表示負樣本),"Score"表示每個測試樣本屬于正樣本的機率。
接下來,我們從高到低,依次将"Score"值作為門檻值threshold,當測試樣本屬于正樣本的機率大于或等于這個threshold時,我們認為它為正樣本,否則為負樣本。舉例來說,對于圖中的第4個樣本,其"Score"值為0.6,那麼樣本1,2,3,4都被認為是正樣本,因為它們的"Score"值都大于等于0.6,而其他樣本則都認為是負樣本。每次選取一個不同的threshold,我們就可以得到一組FPR和TPR,即ROC曲線上的一點。這樣一來,我們一共得到了20組FPR和TPR的值,将它們畫在ROC曲線的結果如下圖:
當我們将threshold設定為1和0時,分别可以得到ROC曲線上的(0,0)和(1,1)兩個點。将這些(FPR,TPR)對連接配接起來,就得到了ROC曲線。當threshold取值越多,ROC曲線越平滑。
其實,我們并不一定要得到每個測試樣本是正樣本的機率值,隻要得到這個分類器對該測試樣本的"評分值"即可(評分值并不一定在(0,1)區間)。評分越高,表示分類器越肯定地認為這個測試樣本是正樣本,而且同時使用各個評分值作為threshold。我認為将評分值轉化為機率更易于了解一些。
四、AUC
4.1 AUC 值的計算
AUC (Area Under Curve) 被定義為ROC曲線下的面積,顯然這個面積的數值不會大于1。又由于ROC曲線一般都處于y=x這條直線的上方,是以AUC的取值範圍一般在0.5和1之間。使用AUC值作為評價标準是因為很多時候ROC曲線并不能清晰的說明哪個分類器的效果更好,而作為一個數值,對應AUC更大的分類器效果更好。
AUC的計算有兩種方式,梯形法和ROC AUCH法,都是以逼近法求近似值,具體見wikipedia。
4.2 AUC 意味着什麼
那麼AUC值的含義是什麼呢?根據(Fawcett, 2006),AUC的值的含義是:
The AUC value is equivalent to the probability that a randomly chosen positive example is ranked higher than a randomly chosen negative example.
這句話有些繞,我嘗試解釋一下:首先AUC值是一個機率值,當你随機挑選一個正樣本以及一個負樣本,目前的分類算法根據計算得到的Score值将這個正樣本排在負樣本前面的機率就是AUC值。當然,AUC值越大,目前的分類算法越有可能将正樣本排在負樣本前面,即能夠更好的分類。
從AUC判斷分類器(預測模型)優劣的标準:
AUC = 1,是完美分類器,采用這個預測模型時,存在至少一個門檻值能得出完美預測。絕大多數預測的場合,不存在完美分類器。
0.5< AUC <1,優于随機猜測。這個分類器(模型)妥善設定門檻值的話,能有預測價值。
AUC = 0.5,跟随機猜測一樣(例:丢銅闆),模型沒有預測價值。
AUC <0.5,比随機猜測還差;但隻要總是反預測而行,就優于随機猜測。
簡單說:AUC值越大的分類器,正确率越高。
三種 AUC 值示例:
五、為什麼使用 ROC 曲線
既然已經這麼多評價标準,為什麼還要使用ROC和AUC呢?因為ROC曲線有個很好的特性:當測試集中的正負樣本的分布變化的時候,ROC曲線能夠保持不變。在實際的資料集中經常會出現類不平衡(class imbalance)現象,即負樣本比正樣本多很多(或者相反),而且測試資料中的正負樣本的分布也可能随着時間變化。下圖是ROC曲線和Precision-Recall曲線的對比:
為什麼還要使用ROC和AUC呢?因為ROC曲線有個很好的特性:當測試集中的正負樣本的分布變化的時候,ROC曲線能夠保持不變。在實際的資料集中經常會出現類不平衡(class imbalance)現象,即負樣本比正樣本多很多(或者相反),而且測試資料中的正負樣本的分布也可能随着時間變化。ROC和Precision-Recall
在上圖中,(a)和(c)為ROC曲線,(b)和(d)為Precision-Recall曲線。(a)和(b)展示的是分類其在原始測試集(正負樣本分布平衡)的結果,(c)和(d)是将測試集中負樣本的數量增加到原來的10倍後,分類器的結果。可以明顯的看出,ROC曲線基本保持原貌,而Precision-Recall曲線則變化較大。
六、 動手實驗
依然用我們最熟悉的Iris資料集,分析探索工具依然用我們的資料科學/分析利器SmartNoteBook。
Iris資料集是常用的分類實驗資料集,由Fisher, 1936收集整理。Iris也稱鸢尾花卉資料集,是一類多重變量分析的資料集。
資料集包含150個資料樣本,分為3類,每類50個資料,每個資料包含4個屬性。可通過花萼長度,花萼寬度,花瓣長度,花瓣寬度4個屬性預測鸢尾花卉屬于(Setosa,Versicolour,Virginica)三個種類中的哪一類。
資料導入和準備:
# 導入需要的包
import numpy as np
import matplotlib.pyplot as plt
from itertools import cycle
from sklearn import svm, datasets
from sklearn.metrics import roc_curve, auc
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import label_binarize
from sklearn.multiclass import OneVsRestClassifier
from sklearn.metrics import accuracy_score,precision_score,recall_score,f1_score
from numpy import interp
%matplotlib inline
# 擷取資料集,這裡我們友善起見隻導入兩種分類
iris = datasets.load_iris()
X = iris.data[50:150]
y = iris.target[50:150]
# 增加樣本記錄的數量(将數量翻6翻)
for i in range(6):
X=np.append(X,X,axis=0)
y=np.append(y,y,axis=0)
為資料集增加一些噪音:
random_state = np.random.RandomState(2022)
n_samples, n_features = X.shape
X = np.c_[X, random_state.randn(n_samples, 32 )]
for i in range(4):
X[:,i]=X[:,i]+ random_state.randn(1,n_samples )[0]
檢視資料集的形狀:
X.shape
(25600, 36)
标簽二值化:
y = label_binarize(y, classes=[0, 1])
n_classes = y.shape[1]
訓練模型并預測:
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.3,random_state=0)
classifier = OneVsRestClassifier(svm.SVC(kernel='linear', probability=True))
y_score = classifier.fit(X_train, y_train).decision_function(X_test)
y_pred = classifier.predict(X_test)
計算準确率、精确率、召回率、f1_score:
print ('accuracy is %s'% accuracy_score(y_test, y_pred))
print('precision is %s'% classifier.score(X_train, y_train))
print ('recall is %s'% recall_score(y_test, y_pred, average='macro'))
print ('f1-score is %s'% f1_score(y_test, y_pred, average='macro') )
accuracy is 0.7516927083333333
precision is 0.7500558035714285
recall is 0.7516944913982669
f1-score is 0.7516926704446416
計算并展示混淆矩陣:
# 計算混淆矩陣
from sklearn import metrics
iris_confusion_matrix = metrics.confusion_matrix(y_test,y_pred)
iris_confusion_matrix
# 直覺展示混淆矩陣
from pyecharts import options as opts
from pyecharts.charts import HeatMap
x=['versicolor','virginica']
y=['virginica','versicolor']
i=0
value=[]
for m in iris_confusion_matrix:
j=0
for v in m:
value.append([i,1-j,int(v)])
j=j+1
i=i+1
value
c = (
HeatMap()
.add_xaxis(x)
.add_yaxis(
"",
y,
value,
label_opts=opts.LabelOpts(is_show=True, position="inside"),
)
.set_global_opts(
xaxis_opts=opts.AxisOpts(position='top',name="預測值",name_gap = 35,name_location = 'center'),
yaxis_opts=opts.AxisOpts(name="真實值",name_gap = 35,name_location = 'center',axislabel_opts=opts.LabelOpts(rotate=90)),
title_opts=opts.TitleOpts(title="混淆矩陣"),
visualmap_opts=opts.VisualMapOpts(is_show=False,
min_ = 0,
max_ = 5000,
range_color = ['#0d243b','#053b70'],
)
)
)
c.render_notebook()
繪制ROC曲線:
fpr = dict()
tpr = dict()
roc_auc = dict()
fpr, tpr, _ = roc_curve(y_test, y_score)
roc_auc = auc(fpr, tpr)
plt.figure(dpi=100,figsize=(8,6))
plt.plot(fpr, tpr, color=color, lw=1.2)
plt.plot([0, 1], [0, 1], 'k--', lw=1.2)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend(loc="lower right")
plt.show()
《新語資料故事彙,數說新語》 科普資料科學、講述資料故事,深層次挖掘資料價值。歡迎各位朋友投稿!
微信号|SnbDataStory
《新語資料故事彙,數說新語》