介紹
准確率、召回率、精確度和F1分數是用來評估模型性能的指標。盡管這些術語聽起來很復雜,但它們的基本概念非常簡單。它們基於簡單的公式,很容易計算。
這篇文章將解釋以下每個術語:
- 為什么用它
- 公式
- 不用sklearn來計算
- 使用sklearn進行計算
在本教程結束時,我們將復習混淆矩陣以及如何呈現它們。文章的最后提供了谷歌colab筆記本的鏈接。
數據
假設我們正在對一封電子郵件進行分類,看它是不是垃圾郵件。
我們將有兩個數組,第一個數組將存儲實際值,而第二個數組將存儲預測值。這些預測值是從分類器模型中獲得的。模型的類型並不重要,我們感興趣的是模型所做的預測。
# 實際值
labels = [1, 0, 0, 1, 1, 1, 0, 1, 1, 1]
# 預測值
predictions = [0, 1, 1, 1, 1, 0, 1, 0, 1, 0]
0-郵件不是垃圾郵件(負)
1-電子郵件是垃圾郵件(正)
關鍵術語
真正例
當標簽為正且我們的預測值也為正時,就會發生這種情況。在我們的場景中,當電子郵件是垃圾郵件時,模型也將其分類為垃圾郵件。
TP = 0
for i in range(0,len(labels)):
if labels[i] == predictions[i] and labels[i] == 1:
TP+=1
print("True Positive: ", TP) # 3
假正例
這種情況發生在標簽為負但我們的模型預測為正的情況下。在我們的場景中,當電子郵件不是垃圾郵件,但模型將其分類為垃圾郵件時。
FP = 0
for i in range(0,len(labels)):
if labels[i] == 0 and predictions[i] == 1:
FP+=1
print("False Positive: ", FP) # 3
真反例
這類似於真正例,唯一的區別是標簽和預測值都是負。在我們的場景中,當電子郵件不是垃圾郵件時,模型也將其分類為非垃圾郵件。
TN = 0
for i in range(0,len(labels)):
if labels[i] == predictions[i] and labels[i] == 0:
TN+=1
print("True Negative: ", TN) # 0
假反例
這種情況發生在標簽為正但預測值為負的情況下。在某種程度上,與假正例相反。在我們的場景中,當電子郵件是垃圾郵件,但模型將其分類為非垃圾郵件。
FN = 0
for i in range(0,len(labels)):
if labels[i] == 1 and predictions[i] == 0:
FN+=1
print("False Negative: ", FN) # 4
正確預測
這種情況是標簽和預測值相同。在本例中,當模型將垃圾郵件分類為垃圾郵件,將非垃圾郵件分類為非垃圾郵件時。
也可以計算為真正例與真負例的總和。
ICP = 0
for i in range(0,len(labels)):
if labels[i] != predictions[i]:
ICP+=1
print("Incorrect Prediction: ", ICP)# 7
print(ICP == FP + FN) # True
不正確的預測
這種情況的條件是,標簽和預測值不相等。在我們的場景中,錯誤的預測是模型將垃圾郵件分類為非垃圾郵件,將非垃圾郵件分類為垃圾郵件。
錯誤預測也可以計算為假正例和假反例的總和。
ICP = 0
for i in range(0,len(labels)):
if labels[i] != predictions[i]:
ICP+=1
print("Incorrect Prediction: ", ICP)# 7
print(ICP == FP + FN) # True
准確率
准確率是正確的預測數與預測總數的比率。這是對模型最簡單的度量之一。我們必須力求我們的模型達到高准確率。如果一個模型具有較高的准確率,可以推斷出該模型在大多數情況下做出了正確的預測。
不使用Sklearn
accuracy = (TP + TN)/(TP + FP + TN + FN)
print(accuracy*100)
使用Sklearn
from sklearn.metrics import accuracy_score
print(accuracy_score(labels , predictions)*100)
召回率
准確率可能會誤導人
高准確率有時會使人產生誤解。考慮下面的場景:
labels = [0,0,0,0,1,0,0,1,0,0]
predictions = [0 ,0 ,0 ,0 ,0 , 0 ,0 ,0 ,0 ,0]
print(accuracy_score(labels , predictions)*100) # 80
與非垃圾郵件相比,垃圾郵件很少見。因此,label = 0的出現次數要高於label = 1的出現次數。在上面的代碼中,labels有8個非垃圾郵件和2個垃圾郵件。
如果模型總是將郵件分類為非垃圾郵件,那么准確率將達到80%。這是高度誤導,因為模型基本上無法檢測垃圾郵件。
計算召回率
召回率計算預測正例數與正例標簽總數的比率。
在上面的例子中,模型召回率為0,因為它有0個真正的正例。這告訴我們,模型在垃圾郵件上表現不佳,需要改進它。
不使用Sklearn
recall = (TP)/(TP+FN)
print(recall*100)
使用Sklearn
from sklearn.metrics import recall_score
print(recall_score(labels,predictions))
精確度
召回率可能具有誤導性的案例
高召回率也很容易誤導人。考慮當模型被調優為總是返回正值的預測時的情況。它基本上把所有的電子郵件都歸類為垃圾郵件。
labels = [0,0,0,0,1,0,0,1,0,0]
predictions = [1,1,1,1,1,1,1,1,1,1]
print(accuracy_score(labels , predictions)*100)
print(recall_score(labels , predictions)*100)
雖然上述情況的准確率較低(20%),但召回率較高(100%)。
計算精確度
精確度是預測正確的正例數與正預測總數的比率。
在上述情況下,精確度較低(20%),因為模型預測共10個正例,其中只有2個是正確的。這告訴我們,盡管召回率很高,而且模型在正面案例(即垃圾郵件)上表現很好,但在非垃圾郵件上表現很差。
我們的准確率和精確度相等的原因是,模型預測的是所有的正例結果。在現實世界中,模型可以正確地預測一些負面的情況,從而獲得更高的准確率。然而,精確度仍然保持不變,因為它只依賴於預測正確的正例數和正預測總數。
不使用Sklearn
precision = TP/(TP+FP)
print(precision)
使用Sklearn
from sklearn.metrics import precision_score
print(precision_score(labels,predictions)*100)
F1得分
F1得分取決於召回和精確度,它是這兩個值的調和平均值。
我們考慮調和平均值除以算術平均值,因為想要低召回率或精確度來產生低F1分數。在之前的例子中,召回率為100%,精確度為20%,算術平均值為60%,而調和平均值為33.33%。調和平均值更低,更有意義,因為我們知道模型很糟糕。
AM = (1 + 0.2)/2
HM = 2*(1*0.2)/(1+0.2)
print(AM)# 0.6
print(HM)# 0.333
不使用Sklearn
f1 = 2*(precision * recall)/(precision + recall)
print(f1)
使用Sklearn
from sklearn.metrics import f1_score
print(f1_score(labels, predictions))
混淆矩陣
混淆矩陣是一個表示真正例、假正例、真反例和假反例數的矩陣。
假設我們正在處理以下數據:
# 實際值
labels = [1, 0, 0, 1, 1, 1, 0, 1, 1, 1]
# 預測值
predictions = [0, 0, 1, 1, 1, 0, 1, 0, 1, 0]
使用sklearn計算混淆矩陣
from sklearn.metrics import confusion_matrix
confusion = confusion_matrix(labels, predictions)
FN = confusion[1][0]
TN = confusion[0][0]
TP = confusion[1][1]
FP = confusion[0][1][1]
你還可以傳遞一個normalize參數來對計算數據進行規范化。
以條形圖顯示混亂矩陣
plt.bar(['False Negative' , 'True Negative' , 'True Positive' , 'False Positive'],[FN,TN,TP,FP])
plt.show()
將混淆矩陣顯示為熱圖
import seaborn as sns
sns.heatmap(confusion , annot=True , xticklabels=['Negative' , 'Positive'] , yticklabels=['Negative' , 'Positive'])
plt.ylabel("Label")
plt.xlabel("Predicted")
plt.show()
使用pandas顯示混亂矩陣
import pandas as pd
data = {'Labels' : labels, 'Predictions': predictions}
df = pd.DataFrame(data, columns=['Labels','Predictions'])
confusion_matrix = pd.crosstab(df['Labels'], df['Predictions'], rownames=['Labels'], colnames=['Predictions'])
print (confusion_matrix)
使用Sklearn生成分類報告
from sklearn.metrics import classification_report
print(classification_report(labels,predictions))
下面是輸出:
結論
准確率本身並不能決定一個模型的好壞,但是准確率結合精確度、召回率和F1分數可以很好地說明模型的性能。