1. 程式人生 > >機器學習基礎-8.分類演算法的評價

機器學習基礎-8.分類演算法的評價

一、分類演算法評價指標

1.分類準確度的問題

分類演算法如果用分類準確度來衡量好壞將會存在問題。例如一個癌症預測系統,輸入體檢資訊,可以判斷是否有癌症,預測準確度可以達到99.9%,看起來預測系統還可以,但是如果癌症的產生概率只有0.1%,那麼系統只要預測所有人都是健康的就可以達到99.9%的準確率,因此雖然準確率很高,但是預測系統實際上沒有發揮什麼作用。更加極端的如果癌症概率只有0.01%,那麼預測所有人都是健康的概率是99.99%,比預測系統的結果還要好。因此可以得到結論:在存在極度偏斜的資料中,應用分類準確度來評價分類演算法的好壞是遠遠不夠的。

2.混淆矩陣

對於二分類問題。可以得到如下的混淆矩陣。


通過混淆矩陣可以得到精準率和召回率,用這兩個指標評價分類演算法將會有更好的效果。

3.精準率和召回率


之所以使用1的分類來計算精準率是因為,在實際生活中,1代表著受關注的物件,例如:癌症預測系統中,1就代表著患癌症,40%意味著,系統做出100次病人患有癌症的預測結論,其中有40%結論是準確的。


召回率意味著如果有10個癌症患者,將會有8個被預測到。

現在假設有10000個人,預測所有的人都是健康的,假設有10個患病,則有如下的混淆矩陣。


對於準確率:9990/10000=99.9%。對於精準率:0/0沒有意義。對於召回率:0/10=0。可以看出模型對於預測疾病其實並不好。

4.sklearn程式碼實現

由於計算邏輯比較簡單,所以直接給出sklearn中封裝好的實現。

import numpy as np
from sklearn import datasets

digits = datasets.load_digits()
x = digits.data
y = digits.target.copy()

y[digits.target==9]=1 #這裡將資料弄成明顯的傾斜資料
y[digits.target!=9]=0

from sklearn.model_selection import train_test_split

x_train,x_test,y_train,y_test = train_test_split(x,y,random_state=666)

from sklearn.linear_model import LogisticRegression

log_reg = LogisticRegression()

log_reg.fit(x_train,y_train)
log_reg.score(x_test,y_test) #0.9755555555555555
y_log_predict = log_reg.predict(x_test)

from sklearn.metrics import confusion_matrix
confusion_matrix(y_test,y_log_predict)
from sklearn.metrics import precision_score #sklearn中的精準率
precision_score(y_test,y_log_predict)
from sklearn.metrics import recall_score    #sklearn中的召回率
recall_score(y_test,y_log_predict)

5.對精準率和召回率的分析

對於一個模型得到了精準率和召回率,那麼應該如何通過這兩個指標對模型進行評價,又或者是一個模型經過調參後,得到不同的精準率和召回率,應該選取哪個引數對應的精準率和召回率才好。這個需要根據不同的場景進行選擇。

例如:對於股票預測,更多的應該是關注精準率,假設關注股票上升的情況,高精準率意味著TP值高(正確地預測到股票會升),這個時候可以幫助人們調整投資,增加收入,如果這一指標低,就以為FP值高(錯誤地認為股票會升),也就是說股票其實是降的,而預測成升了,這將會使使用者虧錢。而召回率低只是意味著在股票上升的情況中,對幾個股票上升的情況沒有被預測到,這對於投資者來說也是可以接受的,畢竟沒有虧錢,因此低召回率對使用者影響不是很大。

例如:對於疾病預測領域,更多的應該關注召回率,因為高召回率意味著能夠更多地將得病的病人預測出來,這個對於患病者非常重要。而精準率低意味著錯誤地預測病人患病,而這個時候只要被預測患病的人再去檢查一下即可,實際上是可以接受的,因此低精準率對使用者影響不大。

而某些情況可能需要同時考慮到兩個指標,以達到一個均衡。這個時候就需要F1 score。這個稱為精準率和召回率的調和平均值。可以發現只有兩個值都比較高的時候,F1才會比較高。

from sklearn.metrics import f1_score
f1_score(y_test,y_log_predict)

二、精準率和召回率

1.精準率和召回率的矛盾

實際中,要想同時獲得高的精準率和召回率是很難的,有可能就不能實現。


如圖所示,五角星為1,圓形為0。劃的豎線代表決策邊界。可以看到,當精準率提高時,召回率就下降,當召回率提高時,精準率就下降,二者是個矛盾。

那麼如何選擇決策邊界,使得模型能夠達到目標。

2.繪製精準率和召回率曲線

import numpy as np
from sklearn import datasets
import matplotlib.pyplot as plt

digits = datasets.load_digits()
x = digits.data
y = digits.target.copy()

y[digits.target==9]=1 #這裡將資料弄成明顯的傾斜資料
y[digits.target!=9]=0

from sklearn.model_selection import train_test_split

x_train,x_test,y_train,y_test = train_test_split(x,y,random_state=666)

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
log_reg = LogisticRegression()
log_reg.fit(x_train,y_train)
decision_score = log_reg.decision_function(x_test)

precisions = []
recalls = []

thresholds = np.arange(np.min(decision_score),np.max(decision_score),0.1)
for threshold in thresholds:
    y_predict = np.array(decision_score >= threshold,dtype='int')
    precisions.append(precision_score(y_test,y_predict))
    recalls.append(recall_score(y_test,y_predict))
plt.plot(thresholds,precisions,label="precision")
plt.plot(thresholds,recalls,label="recall")
plt.legend()
plt.show()


繪製precision和recall曲線。

plt.plot(precisions,recalls)
plt.show() #快速下降的點,可能就是比較平衡的點

3.sklearn中的precision和recall曲線繪製

from sklearn.metrics import precision_recall_curve
precisions,recalls,thresholds = precision_recall_curve(y_test,decision_score)
plt.plot(thresholds,precisions[:-1],label="precision")#這裡之所以將最後一列去掉,是因為thresholds維度比precision和recall少1
plt.plot(thresholds,recalls[:-1],label="recall")
plt.legend()
plt.show()

三、ROC

ROC:receive operation characteristic curve,描述的是TPR和FPR之間的關係。

TPR即召回率,FPR為FP/(TN+FP)。下面看看他們之間的關係。


可以看到FPR和TPR呈現相一致的關係,這個也容易理解。當召回率提高時,說明會盡量將1樣本都包含進去(豎線左移),而這個時候就會增加錯分的0樣本(更多的0被包含進去),因此TN減小,FP增大,必然導致FPR的增大。

from sklearn.metrics import roc_curve
fprs,tprs,thresholds=roc_curve(y_test,decision_score)
plt.plot(fprs,tprs)
plt.show()

容易理解,當FPR比較低時,TPR就比較高,這樣就會有比較好的模型,對應的曲線底下的面積也將會比較大,因此ROC底下的面積可以作為衡量分類演算法好壞的一個指標。

from sklearn.metrics import roc_auc_score #計算面積大小
roc_auc_score(y_test,decision_score) 

這個將會得到比較高的值,說明auc對於有偏資料並不是很敏感,auc一般用於比較兩個模型之間的好壞。

四、多分類評價

1.多分類問題中的混淆矩陣

import numpy as np
from sklearn import datasets
import matplotlib.pyplot as plt

digits = datasets.load_digits()
x = digits.data
y = digits.target.copy()

from sklearn.model_selection import train_test_split

x_train,x_test,y_train,y_test = train_test_split(x,y,random_state=666)

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score

log_reg = LogisticRegression()
log_reg.fit(x_train,y_train)
y_predict = log_reg.predict(x_test)

precision_score(y_test,y_predict,average='micro') #為了求出多分類的精準度和召回率,必須傳入引數average='micro'
from sklearn.metrics import confusion_matrix  #檢視多分類的混淆矩陣
confusion_matrix(y_test,y_predict)

其中對角線的代表該分類預測正確的數量,其他位置的值代表預測錯誤所對應的值。為了直觀,現在繪製出影象。

from sklearn.metrics import confusion_matrix
cfm = confusion_matrix(y_test,y_predict)
row_sums = np.sum(cfm,axis=1)#將每行相加,得到每行的樣本總數
err_matrix = cfm/row_sums
np.fill_diagonal(err_matrix,0)#將對角線的元素全部置為0
plt.matshow(err_matrix,cmap=plt.cm.gray) #越亮代表值越大,也就是錯分的越多
plt.show()

這裡可以看到1和8之間混淆地比較多。