Sklearn(v3)——SVM理论(4)
二分類SVC中的樣本不均衡問題:重要參數class_weight
對于分類問題,永遠都逃不過的一個痛點就是樣本不均衡問題。樣本不均衡是指在一組數據集中,標簽的一類天生?占有很大的比例,但我們有著捕捉出某種特定的分類的需求的狀況。比如,我們現在要對潛在犯罪者和普通人進行分類,潛在犯罪者占總人口的比例是相當低的,也許只有2%左右,98%的人都是普通人,而我們的目標是要捕獲出潛在犯罪者。這樣的標簽分布會帶來許多問題。
首先,分類模型天生會傾向于多數的類,讓多數類更容易被判斷正確,少數類被犧牲掉。因為對于模型而言,樣本量越大的標簽可以學習的信息越多,算法就會更加依賴于從多數類中學到的信息來進行判斷。如果我們希望捕獲少數類,模型就會失敗。??其次,模型評估指標會失去意義。這種分類狀況下,即便模型什么也不做,全把所有人都當成不會犯罪的人,準確率也能非常高,這使得模型評估指標accuracy變得毫無意義,根本無法達到我們的“要識別出會犯罪的人”的建模目的。
所以現在,我們首先要讓算法意識到數據的標簽是不均衡的,通過施加一些懲罰或者改變樣本本身,來讓模型向著捕獲少數類的方向建模。然后,我們要改進我們的模型評估指標,使用更加針對于少數類的指標來優化模型。
要解決第一個問題,我們在邏輯回歸中已經介紹了一些基本方法,比如上采樣下采樣。但這些采樣方法會增加樣本的總數,對于支持向量機這個樣本總是對計算速度影響巨大的算法來說,我們完全不想輕易地增加樣本數量。況且,支持向量機中地決策僅僅決策邊界的影響,而決策邊界又僅僅受到參數C和支持向量的影響,單純地增加樣本數量不僅會增加計算時間,可能還會增加無數對決策邊界無影響的樣本點。因此在支持向量機中,我們要大力依賴我們調節樣本均衡的參數:SVC類中的class_weight和接口?t中可以設定的sample_weight。
在邏輯回歸中,參數class_weight默認None,此模式表示假設數據集中的所有標簽是均衡的,即自動認為標簽的比例是1:1。所以當樣本不均衡的時候,我們可以使用形如{"標簽的值1":權重1,"標簽的值2":權重2}的字典來輸入真實的樣本標簽比例,來讓算法意識到樣本是不平衡的。或者使用”balanced“模式,直接使用n_samples/(n_classes?* np.bincount(y))作為權重,可以比較好地修正我們的樣本不均衡情況。
但在SVM中,我們的分類判斷是基于決策邊界的,而最終決定究竟使用怎樣的支持向量和決策邊界的參數是參數C,所以所有的樣本均衡都是通過參數C來調整的。
SVC的參數:class_weight
可輸入字典或者"balanced”,可不填,默認None對SVC,將類i的參數C設置為class_weight?[i]?* C。如果沒有給出具體的class_weight,則所有類都被假設為占有相同的權重1,模型會根據數據原本的狀況去訓練。如果希望改善樣本不均衡狀況,請輸入形如{"標簽的值1":權重1,"標簽的值2":權重2}的字典,則參數C將會自動被設為:標簽的值1的C:權重1?* C,標簽的值2的C:權重2*C。
或者,可以使用“balanced”模式,這個模式使用y的值自動調整與輸入數據中的類頻率成反比的權重為n_samples/(n_classes?* np.bincount(y))
SVC的接口?t的參數:sample_weight
數組,結構為?(n_samples,?),必須對應輸入?t中的特征矩陣的每個樣本
每個樣本在?t時的權重,讓權重?*?每個樣本對應的C值來迫使分類器強調設定的權重更大的樣本。通常,較大的權重加在少數類的樣本上,以迫使模型向著少數類的方向建模
通常來說,這兩個參數我們只選取一個來設置。如果我們同時設置了兩個參數,則C會同時受到兩個參數的影響,?即?class_weight中設定的權重?*?sample_weight中設定的權重?*?C。
我們接下來就來看看如何使用這個參數。
首先,我們來自建一組樣本不平衡的數據集。我們在這組數據集上建兩個SVC模型,一個設置有class_weight參數,一個不設置class_weight參數。我們對兩個模型分別進行評估并畫出他們的決策邊界,以此來觀察class_weight帶來的效果。
import numpy as np import matplotlib.pyplot as plt from sklearn import svm from sklearn.datasets import make_blobsclass_1 = 500 #類別1有500個樣本 class_2 = 50 #類別2只有50個 centers = [[0.0, 0.0], [2.0, 2.0]] #設定兩個類別的中心 clusters_std = [1.5, 0.5] #設定兩個類別的方差,通常來說,樣本量比較大的類別會更加松散 X, y = make_blobs(n_samples=[class_1, class_2], centers=centers, cluster_std=clusters_std, random_state=0, shuffle=False)#看看數據集長什么樣 plt.scatter(X[:, 0], X[:, 1], c=y, cmap="rainbow",s=10) #其中紅色點是少數類,紫色點是多數類 #不設定class_weight clf = svm.SVC(kernel='linear', C=1.0) clf.fit(X, y)#設定class_weight wclf = svm.SVC(kernel='linear', class_weight={1: 10}) wclf.fit(X, y)#給兩個模型分別打分看看,這個分數是accuracy準確度 print(clf.score(X,y)) wclf.score(X,y)結果:?
0.9418181818181818 0.9127272727272727?繪制兩個模型下數據的決策邊界
#首先要有數據分布 plt.figure(figsize=(6,5)) plt.scatter(X[:,0], X[:,1], c=y, cmap="rainbow",s=10) ax = plt.gca() #獲取當前的子圖,如果不存在,則創建新的子圖 #繪制決策邊界的第一步:要有網格xlim = ax.get_xlim() ylim = ax.get_ylim()xx = np.linspace(xlim[0], xlim[1], 30) yy = np.linspace(ylim[0], ylim[1], 30) YY, XX = np.meshgrid(yy, xx) xy = np.vstack([XX.ravel(), YY.ravel()]).T#第二步:找出我們的樣本點到決策邊界的距離 Z_clf = clf.decision_function(xy).reshape(XX.shape) a = ax.contour(XX, YY, Z_clf, colors='black', levels=[0], alpha=0.5, linestyles=['-'])Z_wclf = wclf.decision_function(xy).reshape(XX.shape) b = ax.contour(XX, YY, Z_wclf, colors='red', levels=[0], alpha=0.5, linestyles=['-'])#第三步:畫圖例 plt.legend([a.collections[0], b.collections[0]], ["non weighted" , "weighted"],loc="upper right") plt.show()可以看出,從準確率的角度來看,不做樣本平衡的時候準確率反而更高,做了樣本平衡準確率反而變低了,這是因?為做了樣本平衡后,為了要更有效地捕捉出少數類,模型誤傷了許多多數類樣本,而多數類被分錯的樣本數量?>?少數類被分類正確的樣本數量,使得模型整體的精確性下降。現在,如果我們的目的是模型整體的準確率,那我們就要拒絕樣本平衡,使用class_weight被設置之前的模型。
然而在現實中,我們往往都在追求捕捉少數類,因為在很多情況下,將少數類判斷錯的代價是巨大的。比如我們之前提到的,判斷潛在犯罪者和普通人的例子,如果我們沒有能夠識別出潛在犯罪者,那么這些人就可能去危害社會,造成惡劣影響,但如果我們把普通人錯認為是潛在犯罪者,我們也許只是需要增加一些監控和人為甄別的成本。所以對我們來說,我們寧愿把普通人判錯,也不想放過任何一個潛在犯罪者。我們希望不惜一切代價來捕獲少數類,或者希望捕捉出盡量多的少數類,那我們就必須使用class_weight設置后的模型。
SVC的模型評估指標
從上一節的例子中可以看出,如果我們的目標是希望盡量捕獲少數類,那準確率這個模型評估逐漸失效,所以我們需要新的模型評估指標來幫助我們。如果簡單來看,其實我們只需要查看模型在少數類上的準確率就好了,只要能夠將少數類盡量捕捉出來,就能夠達到我們的目的。
但此時,新問題又出現了,我們對多數類判斷錯誤后,會需要人工甄別或者更多的業務上的措施來一一排除我們判斷錯誤的多數類,這種行為往往伴隨著很高的成本。比如銀行在判斷”一個申請信用卡的客戶是否會出現違約行為“的時候,如果一個客戶被判斷為”會違約“,這個客戶的信用卡申請就會被駁回,如果為了捕捉出”會違約“的人,大量地將”不會違約“的客戶判斷為”會違約“的客戶,就會有許多無辜的客戶的申請被駁回。信用卡對銀行來說意味著利息收入,而拒絕了許多本來不會違約的客戶,對銀行來說就是巨大的損失。同理,大眾在召回不符合歐盟標準的汽車時,如果為了找到所有不符合標準的汽車,而將一堆本來符合標準了的汽車召回,這個成本是不可估量的。
也就是說,單純地追求捕捉出少數類,就會成本太高,而不顧及少數類,又會無法達成模型的效果。所以在現實中,我們往往在尋找捕獲少數類的能力和將多數類判錯后需要付出的成本的平衡。如果一個模型在能夠盡量捕獲少?數類的情況下,還能夠盡量對多數類判斷正確,則這個模型就非常優秀了。為了評估這樣的能力,我們將引入新的模型評估指標:混淆矩陣和ROC曲線來幫助我們。
混淆矩陣(Confusion?Matrix)
混淆矩陣是二分類問題的多維衡量指標體系,在樣本不平衡時極其有用。在混淆矩陣中,我們將少數類認為是正例,多數類認為是負例。在決策樹,隨機森林這些普通的分類算法里,即是說少數類是1,多數類是0。在SVM里,就是說少數類是1,多數類是-1。普通的混淆矩陣,一般使用{0,1}來表示。混淆矩陣陣如其名,十分容易讓人混淆,在許多教材中,混淆矩陣中各種各樣的名稱和定義讓大家難以理解難以記憶。我為大家找出了一種簡化的方式來顯示標準二分類的混淆矩陣,如圖所示:?
混淆矩陣中,永遠是真實值在前,預測值在后。其實可以很容易看出,11和00的對角線就是全部預測正確的,01和10的對角線就是全部預測錯誤的。基于混淆矩陣,我們有六個不同的模型評估指標,這些評估指標的范圍都在[0,1]之間,所有以11和00為分子的指標都是越接近1越好,所以以01和10為分子的指標都是越接近0越好。對于所有的指標,我們用橙色表示分母,用綠色表示分子,則我們有:?
準確率
#對于沒有class_weight,沒有做樣本平衡的灰色決策邊界來說: print((y[y == clf.predict(X)] == 1).sum()/(clf.predict(X) == 1).sum()) #對于有class_weight,做了樣本平衡的紅色決策邊界來說: (y[y == wclf.predict(X)] == 1).sum()/(wclf.predict(X) == 1).sum()結果:
0.7142857142857143 0.5102040816326531精確度也叫查準率,也就是決策邊界上方的所有點中紅色點所占的比例
可以看出,做了樣本平衡之后,精確度是下降的。因為很明顯,樣本平衡之后,有更多的多數類紫色點被我們誤傷了。精確度可以幫助我們判斷,是否每一次對少數類的預測都精確,所以又被稱為”查準率“。在現實的樣本不平衡
例子中,當每一次將多數類判斷錯誤的成本非常高昂的時候(比如大眾召回車輛的例子),我們會追求高精確度。 精確度越低,我們對多數類的判斷就會越錯誤。當然了,如果我們的目標是不計一切代價捕獲少數類,那我們并不在意精確度。(在意多數類是否判斷正確)召回率
召回率Recall,又被稱為敏感度(sensitivity),真正率,查全率,表示所有真實為1的樣本中,被我們預測正確的樣本所占的比例。在支持向量機中,召回率可以被表示為,決策邊界上方的所有紅色點占全部樣本中的紅色點的比例。召回率越高,代表我們盡量捕捉出了越多的少數類,召回率越低,代表我們沒有捕捉出足夠的少數類。 #所有predict為1的點 / 全部為1的點的比例 #對于沒有class_weight,沒有做樣本平衡的灰色決策邊界來說: print((y[y == clf.predict(X)] == 1).sum()/(y == 1).sum())#對于有class_weight,做了樣本平衡的紅色決策邊界來說: (y[y == wclf.predict(X)] == 1).sum()/(y == 1).sum() 0.6 1.0如果我們希望不計一切代價,找出少數類(比如找出潛在犯罪者的例子),那我們就會追求高召回率,相反如果我們的目標不是盡量捕獲少數類,那我們就不需要在意召回率。
注意召回率和精確度的分子是相同的(都是11),只是分母不同。而召回率和精確度是此消彼長的,兩者之間的平?衡代表了捕捉少數類的需求和盡量不要誤傷多數類的需求的平衡。究竟要偏向于哪一方,取決于我們的業務需求:究竟是誤傷多數類的成本更高,還是無法捕捉少數類的代價更高。
F1分數
為了同時兼顧精確度和召回率,我們創造了兩者的調和平均數作為考量兩者平衡的綜合性指標,稱之為F1?measure。兩個數之間的調和平均傾向于靠近兩個數中比較小的那一個數,因此我們追求盡量高的F1?measure,?能夠保證我們的精確度和召回率都比較高。F1?measure在[0,1]之間分布,越接近1越好。
假負率(False Negative Rate),它等于 1 - Recall。
特異度和假正率
#所有被正確預測為0的樣本 / 所有的0樣本 #對于沒有class_weight,沒有做樣本平衡的灰色決策邊界來說: print((y[y == clf.predict(X)] == 0).sum()/(y == 0).sum())#對于有class_weight,做了樣本平衡的紅色決策邊界來說: (y[y == wclf.predict(X)] == 0).sum()/(y == 0).sum()結果:
0.976 0.904混淆矩陣
sklearn當中提供了大量的類來幫助我們了解和使用混淆矩陣。
基于混淆矩陣,我們學習了總共六個指標:準確率Accuracy,精確度Precision,召回率Recall,精確度和召回度的平衡指標F?measure,特異度Speci?city,以及假正率FPR。其中,假正率有一個非常重要的應用:我們在追求較高的Recall的時候,Precision會下降,就是說隨著更多的少數類被捕捉出來,會有更多的多數類被判斷錯誤,但我們很好奇,隨著Recall的逐漸增加,模型將多數類判斷錯誤的能力如何變化呢?
我們希望理解,我每判斷正確一個少數類,就有多少個多數類會被判斷錯誤。假正率正好可以幫助我們衡量這個能力的變化。相對的,Precision無法判斷這些判斷錯誤的多數類在全部多數類中究竟占多大的比例,所以無法在提升Recall的過程中也顧及到模型整體的Accuracy。因此,我們可以使用Recall和FPR之間的平衡,來替代Recall和Precision之間的平衡,讓我們衡量模型在盡量捕捉少數類的時候,誤傷多數類的情況如何變化,這就是我們的ROC曲線衡量的平衡。
ROC曲線,全稱The?Receiver Operating?Characteristic Curve,譯為受試者操作特性曲線。這是一條以不同閾值下的假正率FPR為橫坐標,不同閾值下的召回率Recall為縱坐標的曲線。讓我們先從概率和閾值開始講起。
class_1_ = 7 class_2_ = 4 centers_ = [[0.0, 0.0], [1,1]] clusters_std = [0.5, 1] X_, y_ = make_blobs(n_samples=[class_1_, class_2_], centers=centers_, cluster_std=clusters_std , random_state=0, shuffle=False) plt.scatter(X_[:, 0], X_[:, 1], c=y_, cmap="rainbow",s=30)?
from sklearn.linear_model import LogisticRegression as LogiR clf_lo = LogiR().fit(X_,y_)prob = clf_lo.predict_proba(X_)#將樣本和概率放到一個DataFrame中 import pandas as pd prob = pd.DataFrame(prob) prob.columns = ["0","1"]prob #手動調節閾值,來改變我們的模型效果 for i in range(prob.shape[0]):if prob.loc[i,"1"] > 0.5:prob.loc[i,"pred"] = 1else:prob.loc[i,"pred"] = 0 prob["y_true"] = y_ prob = prob.sort_values(by="1",ascending=False) prob from sklearn.metrics import confusion_matrix as CM, precision_score as P, recall_score as Rprint(CM(prob.loc[:,"y_true"],prob.loc[:,"pred"],labels=[1,0])) #1是少數類(寫前面)0是多數類 #試試看手動計算Precision和Recall? print(P(prob.loc[:,"y_true"],prob.loc[:,"pred"],labels=[1,0])) R(prob.loc[:,"y_true"],prob.loc[:,"pred"],labels=[1,0]) [[2 2][0 7]] 1.0 0.5 for i in range(prob.shape[0]):if prob.loc[i,"1"] > 0.4:prob.loc[i,"pred"] = 1 else:prob.loc[i,"pred"] = 0print(CM(prob.loc[:,"y_true"],prob.loc[:,"pred"],labels=[1,0])) print(P(prob.loc[:,"y_true"],prob.loc[:,"pred"],labels=[1,0])) print(R(prob.loc[:,"y_true"],prob.loc[:,"pred"],labels=[1,0])) [[2 2][1 6]] 0.6666666666666666 0.5可見,在不同閾值下,我們的模型評估指標會發生變化,我們正利用這一點來觀察Recall和FPR之間如何互相影響。??但是注意,并不是升高閾值,就一定能夠增加或者減少Recall,一切要根據數據的實際分布來進行判斷。而要體現閾值的影響,首先必須的得到分類器在少數類下的預測概率。對于邏輯回歸這樣天生生成似然的算法和樸素貝葉斯這樣就是在計算概率的算法,自然非常容易得到概率,但對于一些其他的分類算法,比如決策樹,比如SVM,?他們的分類方式和概率并不相關。那在他們身上,我們就無法畫ROC曲線了嗎?并非如此。
決策樹有葉子節點,一個葉子節點上可能包含著不同類的樣本。假設一個樣本被包含在葉子節點a中,節點a包含10?個樣本,其中6個為1,4個為0,則1這個正類在這個葉子節點中的出現概率就是60%,類別0在這個葉子節點中的出現概率就是40%。對于所有在這個葉子節點中的樣本而言,節點上的1和0出現的概率,就是這個樣本對應的取到1和0的概率,大家可以去自己驗證一下。但是思考一個問題,由于決策樹可以被畫得很深,在足夠深的情況下,決策樹的每個葉子節點上可能都不包含多個類別的標簽了,可能一片葉子中只有唯一的一個標簽,即葉子節點的不純度為0,此時此刻,對于每個樣本而言,他們所對應的“概率”就是0或者1了。這個時候,我們就無法調節閾值來調???節我們的Recall和FPR了。對于隨機森林,也是如此。
所以,如果我們有概率需求,我們還是會優先追求邏輯回歸或者樸素貝葉斯。不過其實,SVM也可以生成概率,我們一起來看看,它是怎么做的。
SVM概率預測:重要參數probability,接口predict_proba以及decision_function
我們在畫等高線,也就是決策邊界的時候曾經使用SVC的接口decision_function,它返回我們輸入的特征矩陣中每個樣本到劃分數據集的超平面的距離。我們在SVM中利用超平面來判斷我們的樣本,本質上來說,當兩個點的距離是相同的符號的時候,越遠離超平面的樣本點歸屬于某個標簽類的概率就很大。比如說,一個距離超平面0.1的點,和一個距離超平面100的點,明顯是距離為0.1的點更有可能是負類別的點混入了邊界。同理,一個距離超平面距離為-0.1的點,和一個離超平面距離為-100的點,明顯是-100的點的標簽更有可能是負類。所以,到超平面的距離一定程度上反應了樣本歸屬于某個標簽類的可能性。??接口decision_function返回的值也因此被我們認為是SVM?中的置信度(con?dence)。
值得注意的是,在二分類過程中,??decision_function只會生成一列距離,樣本的類別由距離的符號來判斷,但是?predict_proba會生成兩個類別分別對應的概率。SVM也可以生成概率,所以我們可以使用和邏輯回歸同樣的方式來在SVM上設定和調節我們的閾值。
毋庸置疑,Platt縮放中涉及的交叉驗證對于大型數據集來說非常昂貴,計算會非常緩慢。另外,由于Platt縮放的理論原因,在二分類過程中,有可能出現predict_proba返回的概率小于0.5,但樣本依舊被標記為正類的情況出現,?畢竟支持向量機本身并不依賴于概率來完成自己的分類。如果我們的確需要置信度分數,但不一定非要是概率形式的話,那建議可以將probability設置為False,使用decision_function這個接口而不是predict_proba。
繪制SVM的ROC曲線?
#開始繪圖 recall = [] FPR = []probrange = np.linspace(clf_proba.predict_proba(X)[:,1].min(),clf_proba.predict_proba(X)[:,1].max(),num=50,endpoint=False)from sklearn.metrics import confusion_matrix as CM, recall_score as R import matplotlib.pyplot as plot for i in probrange:y_predict = []for j in range(X.shape[0]):if clf_proba.predict_proba(X)[j,1] > i:y_predict.append(1)else:y_predict.append(0)cm = CM(y,y_predict,labels=[1,0])recall.append(cm[0,0]/cm[0,:].sum())FPR.append(cm[1,0]/cm[1,:].sum()) recall.sort() FPR.sort()plt.plot(FPR,recall,c="red") plt.plot(probrange+0.05,probrange+0.05,c="black",linestyle="--") plt.show()現在我們就畫出了ROC曲線了,那我們如何理解這條曲線呢?先來回憶一下,我們建立ROC曲線的根本目的是找尋Recall和FPR之間的平衡,讓我們能夠衡量模型在盡量捕捉少數類的時候,誤傷多數類的情況會如何變化。橫坐標是FPR,代表著模型將多數類判斷錯誤的能力,縱坐標Recall,代表著模型捕捉少數類的能力,所以ROC曲線代表著,隨著Recall的不斷增加,FPR如何增加。我們希望隨著Recall的不斷提升,FPR增加得越慢越好,這說明我們可 以盡量高效地捕捉出少數類,而不會將很多地多數類判斷錯誤。所以,我們希望看到的圖像是,縱坐標急速上升,?橫坐標緩慢增長,也就是在整個圖像左上方的一條弧線。這代表模型的效果很不錯,擁有較好的捕獲少數類的能力。
中間的虛線代表著,當recall增加1%,我們的FPR也增加1%,也就是說,我們每捕捉出一個少數類,就會有一個多數類被判錯,這種情況下,模型的效果就不好,這種模型捕獲少數類的結果,會讓許多多數類被誤傷,從而增加我們的成本。ROC曲線通常都是凸型的。對于一條凸型ROC曲線來說,曲線越靠近左上角越好,越往下越糟糕,曲線如果在虛線的下方,則證明模型完全無法使用。但是它也有可能是一條凹形的ROC曲線。對于一條凹型ROC曲線來說,應該越靠近右下角越好,凹形曲線代表模型的預測結果與真實情況完全相反,那也不算非常糟糕,只要我們手動將模型的結果逆轉,就可以得到一條左上方的弧線了。最糟糕的就是,無論曲線是凹形還是凸型,曲線位于圖像中間,和虛線非??拷?#xff0c;那我們拿它無能為力。
好了,現在我們有了這條曲線,我們的確知道模型的效果還算是不錯了。但依然非常摸棱兩可,有沒有具體的數字來幫助我們理解ROC曲線和模型的效果呢?的確存在,這個數字就叫做AUC面積,它代表了ROC曲線下方的面積,這個面積越大,代表ROC曲線越接近左上角,模型就越好。AUC面積的計算比較繁瑣,因此,我們使用sklearn來幫助我們。接下來我們來看看,在sklearn當中,如何繪制我們的ROC曲線,找出我們的的AUC面積。
利用ROC曲線找出最佳閾值
在sklearn中,我們有幫助我們計算ROC曲線的橫坐標假正率FPR,縱坐標Recall和對應的閾值的類sklearn.metrics.roc_curve。同時有幫助我們計算AUC面積的類sklearn.metrics.roc_auc_score。在一些比較老舊的sklearn版本中,我們使用sklearn.metrics.auc這個類來計算AUC面積,但這個類即將在0.22版本中被放棄,因此建議大家都使用roc_auc_score,來看看我們的這兩個類:
置信度,概率作為y_score都可?
from sklearn.metrics import roc_curveFPR, recall, thresholds = roc_curve(y,clf_proba.decision_function(X), pos_label=1)print(FPR) print(recall) print(thresholds)結果:
[0. 0. 0.006 0.006 0.008 0.008 0.01 0.01 0.014 0.014 0.018 0.0180.022 0.022 0.024 0.024 0.028 0.028 0.03 0.03 0.032 0.032 0.036 0.0360.04 0.04 0.042 0.042 0.044 0.044 0.05 0.05 0.054 0.054 0.058 0.0580.066 0.066 0.072 0.072 0.074 0.074 0.086 0.086 1. ][0. 0.02 0.02 0.06 0.06 0.16 0.16 0.2 0.2 0.22 0.22 0.36 0.36 0.420.42 0.6 0.6 0.62 0.62 0.64 0.64 0.68 0.68 0.7 0.7 0.74 0.74 0.760.76 0.82 0.82 0.84 0.84 0.86 0.86 0.88 0.88 0.92 0.92 0.94 0.94 0.960.96 1. 1. ][ 3.18236076 2.18236076 1.48676267 1.35964325 1.339208171.14038015 1.13383091 1.00003406 0.85085628 0.844764390.78571364 0.60568093 0.5389064 0.46718521 0.443960460.03907036 -0.07011269 -0.10668727 -0.1258212 -0.13845693-0.14034183 -0.16790648 -0.2040958 -0.22137683 -0.24381463-0.26762451 -0.34446784 -0.3467975 -0.39182241 -0.40676459-0.4589064 -0.46310299 -0.49195707 -0.5088941 -0.53560561-0.55152081 -0.62628865 -0.67580418 -0.78127198 -0.79874442-0.88438995 -0.91257798 -1.01417607 -1.08601917 -10.31959605] from sklearn.metrics import roc_auc_score as AUC area = AUC(y,clf_proba.decision_function(X)) area結果:
0.9696400000000001 plt.figure() plt.plot(FPR, recall, color='red',label='ROC curve (area = %0.2f)' % area) plt.plot([0, 1], [0, 1], color='black', linestyle='--') plt.xlim([-0.05, 1.05]) plt.ylim([-0.05, 1.05]) plt.xlabel('False Positive Rate') plt.ylabel('Recall') plt.title('Receiver operating characteristic example') plt.legend(loc="lower right") plt.show()?結果:
現在,有了ROC曲線,了解了模型的分類效力,以及面對樣本不均衡問題時的效力,那我們如何求解我們最佳的閾值呢?我們想要了解,什么樣的狀況下我們的模型的效果才是最好的。回到我們對ROC曲線的理解來:ROC曲線反應的是recall增加的時候FPR如何變化,也就是當模型捕獲少數類的能力變強的時候,會誤傷多數類的情況是否嚴重。我們的希望是,模型在捕獲少數類的能力變強的時候,盡量不誤傷多數類,也就是說,隨著recall的變大,FPR?的大小越小越好。所以我們希望找到的最有點,其實是Recall和FPR差距最大的點。這個點,又叫做約登指數。
maxindex = (recall - FPR).tolist().index(max(recall - FPR)) print(thresholds[maxindex])#我們可以在圖像上來看看這個點在哪里 plt.scatter(FPR[maxindex],recall[maxindex],c="black",s=30)#把上述代碼放入這段代碼中: plt.figure() plt.plot(FPR, recall, color='red',label='ROC curve (area = %0.2f)' % area) plt.plot([0, 1], [0, 1], color='black', linestyle='--') plt.scatter(FPR[maxindex],recall[maxindex],c="black",s=30) plt.xlim([-0.05, 1.05]) plt.ylim([-0.05, 1.05]) plt.xlabel('False Positive Rate') plt.ylabel('Recall') plt.title('Receiver operating characteristic example') plt.legend(loc="lower right")結果:
最佳閾值就這樣選取出來了,由于現在我們是使用decision_function來畫ROC曲線,所以我們選擇出來的最佳閾值其實是最佳距離。如果我們使用的是概率,我們選取的最佳閾值就會使一個概率值了。只要我們讓這個距離/概率以上的點,都為正類,讓這個距離/概率以下的點都為負類,模型就是最好的:即能夠捕捉出少數類,又能夠盡量不誤傷多數類,整體的精確性和對少數類的捕捉都得到了保證。
而從找出的最優閾值點來看,這個點,其實是圖像上離左上角最近的點,離中間的虛線最遠的點,也是ROC曲線的轉折點。如果沒有時間進行計算,或者橫坐標比較清晰的時候,我們就可以觀察轉折點來找到我們的最佳閾值。
到這里為止,SVC的模型評估指標就介紹完畢了。但是,SVC的樣本不均衡問題還可以有很多的探索。另外,我們還可以使用KS曲線,或者收益曲線(pro?t?chart)來選擇我們的閾值,都是和ROC曲線類似的用法。大家若有余力,可以自己深入研究一下。模型評估指標,還有很多深奧的地方。
總結
以上是生活随笔為你收集整理的Sklearn(v3)——SVM理论(4)的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: Sklearn(v3)——SVM理论(3
- 下一篇: Sklearn(v3)——朴素贝叶斯(1
