前言
在上一篇文章中廊散,我們了解了k近鄰算法,也學習了KNN算法的流程剥汤,并且手動實現(xiàn)了python代碼和封裝颠放。
那么在得到了分類的結(jié)果之后,它的效果如何呢吭敢?預測的準不準確碰凶?
這里我們學習一些評估分類問題常用的指標
判斷模型好壞
訓練數(shù)據(jù)集和測試數(shù)據(jù)集
當我們訓練好一個模型之后,一般是不能直接拿到生產(chǎn)環(huán)境中直接使用的鹿驼,我們首先要考慮和評估這個模型準確度如何痒留。但是拿到真實環(huán)境中,數(shù)據(jù)是沒有標簽的蠢沿,我們沒有辦法驗證伸头,那么該這么辦呢?
既然是這樣舷蟀,那么我們可以將原始數(shù)據(jù)中的一部分作為訓練數(shù)據(jù)恤磷,另一部分作為測試數(shù)據(jù),訓練好模型之后野宜,使用測試數(shù)據(jù)進行驗證模型的好壞扫步。
那么如何對原始數(shù)據(jù)進行拆分呢?
有時候我們的數(shù)據(jù)可能是直接排序好的匈子,這樣的話河胎,直接拆分可能會導致測試數(shù)據(jù)的類型標簽形成了一定的規(guī)律,所以我們先對數(shù)據(jù)進行一個shuffle操作把數(shù)據(jù)打亂虎敦。
如果數(shù)據(jù)集的特征和標簽是在一起的游岳,那么可以直接shuffle之后再分解成特征和標簽。
如果特征和標簽不在一起其徙,可以使用下面的兩種方法解決這一問題:
1胚迫、將X和y合并為同一個矩陣,然后對矩陣進行shuffle唾那,之后再分解
2访锻、對y的索引進行亂序,根據(jù)索引確定與X的對應(yīng)關(guān)系,最后再通過亂序的索引進行賦值
(在后面的實現(xiàn)代碼中會給出具體代碼)
得到分割好的訓練集和測試集之后期犬,就可以應(yīng)用到KNN算法中去河哑。訓練集傳入fit函數(shù)中進行訓練,然后對測試集的特征集進行預測龟虎,得到預測的標簽集璃谨。再對預測的標簽集和實際測試集的標簽集進行對比∏沧埽可以得到預測正確的比例睬罗。
指標1-分類準確度accuracy
到這里我們就可以引入第一個指標的概念:accuracy(分類準確度)。上面的預測的標簽集中正確的比例就是分類的準確度
這里我們利用之前手寫的KNN算法整體實現(xiàn)一下數(shù)據(jù)切分和訓練得出分類準確度
使用得數(shù)據(jù)集是鳶尾花數(shù)據(jù)集旭斥,特征有4個容达,種類有三個標簽。
代碼實現(xiàn):
import numpy as np
from sklearn import datasets
import matplotlib.pyplot as plt
import collections
#定義一個將多維數(shù)據(jù)轉(zhuǎn)為一維數(shù)據(jù)的函數(shù)
def flatten(x):
result = []
for el in x:
if isinstance(x, collections.Iterable) and not isinstance(el, str) and not isinstance(el, float):
result.extend(flatten(el))
else:
result.append(el)
return result
iris = datasets.load_iris()
X = iris.data
y = iris.target
# 切分訓練集和測試集方法1
# 使用concatenate函數(shù)進行拼接垂券,因為傳入的矩陣必須具有相同的形狀花盐。
#因此需要對label進行reshape操作,reshape(-1,1)表示行數(shù)自動計算菇爪,1列算芯。axis=1表示縱向拼接。
tempConcat = np.concatenate((X, y.reshape(-1,1)), axis=1)
# 拼接好后凳宙,直接進行亂序操作
np.random.shuffle(tempConcat)
# 再將shuffle后的數(shù)組使用split方法拆分
shuffle_X,shuffle_y = np.split(tempConcat, [4], axis=1)
# 設(shè)置劃分的比例
test_ratio = 0.2
test_size = int(len(X) * test_ratio)
X_train = shuffle_X[test_size:]
y_train = shuffle_y[test_size:]
X_test = shuffle_X[:test_size]
y_test = shuffle_y[:test_size]
#轉(zhuǎn)化方法1 這里需要降維轉(zhuǎn)化是因為我們手寫的knn算法中需要這種數(shù)據(jù)格式 下面轉(zhuǎn)化2方法也是同理熙揍。
y_train = flatten(y_train)
y_train = np.array(y_train)
#轉(zhuǎn)化2
# y_train = y_train.tolist()
# y_train1=[]
# for y_ in y_train:
# y_train1.append(y_[0])
# y_train1= np.array(y_train1)
# print(y_train1)
# # 切分訓練集和測試集方法2
# # 將x長度這么多的數(shù),返回一個新的打亂順序的數(shù)組氏涩,
# #注意届囚,數(shù)組中的元素不是原來的數(shù)據(jù),而是混亂的索引
# shuffle_index = np.random.permutation(len(X))
# # 指定測試數(shù)據(jù)的比例
# test_ratio = 0.2
# test_size = int(len(X) * test_ratio)
# test_index = shuffle_index[:test_size]
# train_index = shuffle_index[test_size:]
# X_train = X[train_index]
# X_test = X[test_index]
# y_train = y[train_index]
# y_test = y[test_index]
# print(y_train)
%run myKnn/kNN.py
#from myKnn.kNN import kNNClassifier
knn_clf = kNNClassifier(k=3)
knn_clf.fit(X_train, y_train)
y_predict = knn_clf.predict(X_test)
print(y_predict)
print(np.array(flatten(y_test)))
# 兩個向量的比較是尖,返回一個布爾型向量意系,對這個布爾向量(faluse=1,true=0)sum饺汹,
true_sum=sum(y_predict ==np.array(flatten(y_test)))
accuracy=true_sum/len(y_test)
accuracy
結(jié)果:
[0. 2. 0. 1. 0. 1. 0. 2. 0. 1. 1. 1. 1. 2. 2. 1. 2. 1. 0. 2. 2. 0. 2. 2.
0. 2. 0. 1. 2. 0.]
[0. 2. 0. 1. 0. 1. 0. 2. 0. 1. 1. 1. 1. 2. 2. 1. 2. 1. 0. 2. 2. 0. 2. 1.
0. 2. 0. 1. 2. 0.]
0.9666666666666667
accuracy指標定義清洗蛔添、計算方法簡單,因此經(jīng)常被使用兜辞。但是只使用accuracy評價分類算法迎瞧,是有很大問題的。
比如弦疮,對于一個癌癥預測系統(tǒng)夹攒,,輸入檢查指標胁塞,判斷是否患有癌癥,預測準確度99.9%,那這個系統(tǒng)是好還是壞呢啸罢?
很顯然编检,如果癌癥的發(fā)生率是0.1%,那其實不使用任何機器學習算法扰才,只要系統(tǒng)預測所有人都健康允懂,就可以達到99.9%的準確度,也就是說對于極度偏斜(Skewed Data)的數(shù)據(jù)衩匣,只使用分類準確度是不能衡量的蕾总。
這就需要使用混淆矩陣(Confusion Matrix)做進一步分析。
混淆矩陣
我們來看經(jīng)典的混淆矩陣圖
針對一個二分類問題琅捏,將實例分成正類(postive)或者負類(negative)生百。但是實際中分類時,會出現(xiàn)四種情況:
(1)真正類(True Positive , TP):被模型預測為正類的正樣本
(2)假正類(False Positive , FP):被模型預測為正類的負樣本
(3)假負類(False Negative , FN):被模型預測為負類的正樣本
(4)真負類(True Negative , TN):被模型預測為負類的負樣本
列聯(lián)表如下柄延,1代表正類蚀浆,0代表負類:
現(xiàn)在假設(shè)有1萬人進行預測,填入混淆矩陣如下:
對于1萬個人中搜吧,有9978個人本身并沒有癌癥市俊,我們的算法也判斷他沒有癌癥;有12個人本身沒有癌癥滤奈,但是我們的算法卻錯誤地預測他有癌癥摆昧;有2個人確實有癌癥,但我們算法預測他沒有癌癥蜒程;有8個人確實有癌癥绅你,而且我們也預測對了。
因為混淆矩陣表達的信息比簡單的分類準確度更全面搞糕,因此可以通過混淆矩陣得到一些有效的指標
指標2-精準率和召回率
根據(jù)混淆矩陣可以求得指標:
精準率:precision = TP/(TP+FP) 勇吊,即精準率為8/(8+12)=40%。所謂的精準率是:分母為所有預測為1的個數(shù)窍仰,分子是其中預測對了的個數(shù)汉规,即預測值為1,且預測對了的比例驹吮。
為什么管它叫精準率呢针史?在有偏的數(shù)據(jù)中,我們通常更關(guān)注值為1的特征碟狞,比如“患病”啄枕,比如“有風險”。在100次結(jié)果為患病的預測族沃,平均有40次預測是對的频祝。即精準率為我們關(guān)注的那個事件泌参,預測的有多準。
召回率:recall = TP/(TP+FN)常空,即召回率為8/(8+2)=80%沽一。所謂召回率是:所有真實值為1的數(shù)據(jù)中,預測對了的個數(shù)漓糙。每當有100個癌癥患者铣缠,算法可以成功的預測出8個 。也就是我們關(guān)注的那個事件真實的發(fā)生情況下昆禽,我們成功預測的比例是多少蝗蛙。
那么為什么需要精準率和召回率呢?還是下面的這個例子醉鳖,有10000個人捡硅,混淆矩陣如下:
如果我們粗暴的認為所有人都是健康的,那算法的準確率是99.78%辐棒,但這是毫無意義的病曾。如果算精準率則是40%,召回率是80%漾根。
更關(guān)注哪個呢泰涂?
精準率(查準率):預測值為1,且預測對了的比例辐怕,即:我們關(guān)注的那個事件逼蒙,預測的有多準。
召回率(查全率):所有真實值為1的數(shù)據(jù)中寄疏,預測對了的個數(shù)是牢,即:我們關(guān)注的那個事件真實的發(fā)生情況下,我們成功預測的比例是多少陕截。
有時候驳棱,對于一個算法而言,精準率和召回率沒有達到同時高或者低农曲,這時候我們需要根據(jù)場景而定來取舍依賴的指標社搅。
比如我們做了一個股票預測系統(tǒng),未來股票是??還是??這樣一個二分類問題乳规。很顯然“漲”才是我們關(guān)注的焦點形葬,那么我們肯定希望:系統(tǒng)預測上漲的股票中,真正上漲的比例越大越好暮的,這就是希望查準率高笙以。那么我們是否關(guān)注查全率呢?在大盤中有太多的真實上漲股票冻辩,雖然我們漏掉了一些上升周期猖腕,但是我們沒有買進拆祈,也就沒有損失。但是如果查準率不高谈息,預測上漲的結(jié)果下跌了缘屹,那就是實實在在的虧錢了凛剥。所以在這個場景中侠仇,查準率更重要。
當然也有追求召回率的場景犁珠,在醫(yī)療領(lǐng)域做疾病診斷逻炊,如果召回率低,意味著本來有一個病人得病了犁享,但是沒有正確預測出來余素,病情就惡化了。我們希望盡可能地將所有有病的患者都預測出來炊昆,而不是在看在預測有病的樣例中有多準桨吊。
但是,在實際業(yè)務(wù)場景中凤巨,也有很多沒有這么明顯的選擇视乐。那么在同時需要關(guān)注精準率和召回率,如何在兩個指標中取得平衡呢敢茁?在這種情況下佑淀,我們使用一種新的指標:F1 Score。
指標2-二者兼顧 F1 Score
如果要我們綜合精準率和召回率這兩個指標彰檬,我們可能會想到取平均值這樣的方法伸刃。F1 Score的思想也差不多:
F1 Score 是精準率和召回率的調(diào)和平均值。
指標3-ROC曲線和AUC
在了解ROC曲線之前宛蚓,先了解三個概念:分類閾值激捏、TPR和FPR
分類閾值
分類閾值,即設(shè)置判斷樣本為正例的閾值thr
如果某個邏輯回歸模型對某封電子郵件進行預測時返回的概率為 0.9995凄吏,則表示該模型預測這封郵件非吃毒耍可能是垃圾郵件闰蛔。相反,在同一個邏輯回歸模型中預測分數(shù)為 0.0003 的另一封電子郵件很可能不是垃圾郵件图柏⌒蛄可如果某封電子郵件的預測分數(shù)為 0.6 呢?為了將邏輯回歸值映射到二元類別蚤吹,您必須指定分類閾值(也稱為判定閾值)例诀。如果值高于該閾值,則表示“垃圾郵件”裁着;如果值低于該閾值繁涂,則表示“非垃圾郵件”。人們往往會認為分類閾值應(yīng)始終為 0.5二驰,但閾值取決于具體問題扔罪,因此您必須對其進行調(diào)整。
TPR和FPR
借助之前的圖我們看一下:
TPR:預測為1桶雀,且預測對了的數(shù)量矿酵,占真實值為1的數(shù)據(jù)百分比。很好理解矗积,就是召回率全肮。
TPR = recall = TP/(TP+FN)
FPR:預測為1,但預測錯了的數(shù)量漠魏,占真實值不為1的數(shù)據(jù)百分比倔矾。與TPR相對應(yīng),F(xiàn)PR除以真實值為0的這一行所有的數(shù)字和 柱锹。
ROC曲線
ROC曲線(Receiver Operation Characteristic Cureve)哪自,描述TPR和FPR之間的關(guān)系。x軸是FPR禁熏,y軸是TPR
假設(shè)采用邏輯回歸分類器壤巷,其給出針對每個實例為正類的概率,那么通過設(shè)定一個閾值如0.6瞧毙,概率大于等于0.6的為正類胧华,小于0.6的為負類。對應(yīng)的就可以算出一組(FPR,TPR),在平面中得到對應(yīng)坐標點宙彪。隨著閾值的逐漸減小矩动,越來越多的實例被劃分為正類,但是這些正類中同樣也摻雜著真正的負實例释漆,即TPR和FPR會同時增大悲没。閾值最大時,對應(yīng)坐標點為(0,0)男图,閾值最小時示姿,對應(yīng)坐標點(1,1)甜橱。
如下面這幅圖,(a)圖中實線為ROC曲線栈戳,線上每個點對應(yīng)一個閾值岂傲。
我們已經(jīng)知道,TPR就是所有正例中子檀,有多少被正確地判定為正镊掖;FPR是所有負例中,有多少被錯誤地判定為正命锄。 分類閾值取不同值堰乔,TPR和FPR的計算結(jié)果也不同,最理想情況下脐恩,我們希望所有正例 & 負例 都被成功預測 TPR=1,F(xiàn)PR=0侦讨,即 所有的正例預測值 > 所有的負例預測值驶冒,此時閾值取最小正例預測值與最大負例預測值之間的值即可。
TPR越大越好韵卤,F(xiàn)PR越小越好骗污,但這兩個指標通常是矛盾的。為了增大TPR沈条,可以預測更多的樣本為正例需忿,與此同時也增加了更多負例被誤判為正例的情況。
AUC
一般在ROC曲線中蜡歹,我們關(guān)注是曲線下面的面積屋厘, 稱為AUC(Area Under Curve)。這個AUC是橫軸范圍(0,1 )月而,縱軸是(0,1)所以總面積是小于1的汗洒。
ROC和AUC的主要應(yīng)用:比較兩個模型哪個好?主要通過AUC能夠直觀看出來父款。
ROC曲線下方由梯形組成溢谤,矩形可以看成特征的梯形。因此憨攒,AUC的面積可以這樣算:(上底+下底)* 高 / 2世杀,曲線下面的面積可以由多個梯形面積疊加得到。AUC越大肝集,分類器分類效果越好瞻坝。
AUC = 1,是完美分類器包晰,采用這個預測模型時湿镀,不管設(shè)定什么閾值都能得出完美預測炕吸。絕大多數(shù)預測的場合,不存在完美分類器勉痴。
0.5 < AUC < 1赫模,優(yōu)于隨機猜測。這個分類器(模型)妥善設(shè)定閾值的話蒸矛,能有預測價值瀑罗。
AUC = 0.5,跟隨機猜測一樣雏掠,模型沒有預測價值斩祭。
AUC < 0.5,比隨機猜測還差乡话;但只要總是反預測而行摧玫,就優(yōu)于隨機猜測。
以下示例三種AUC值(曲線下面積)
為什么我們使用ROC和AUC呢
既然已經(jīng)這么多評價標準绑青,為什么還要使用ROC和AUC呢诬像?因為ROC曲線有個很好的特性:當測試集中的正負樣本的分布變化的時候,ROC曲線能夠保持不變闸婴。在實際的數(shù)據(jù)集中經(jīng)常會出現(xiàn)類不平衡(class imbalance)現(xiàn)象坏挠,即負樣本比正樣本多很多(或者相反),而且測試數(shù)據(jù)中的正負樣本的分布也可能隨著時間變化邪乍。
總結(jié)
這一節(jié)我們了解了各種評價分類模型好壞的指標降狠,具體使用哪一種,是依據(jù)應(yīng)用場景而定