SVM-支持向量機(一)線性SVM分類


SVM-支持向量機

SVM(Support Vector Machine)-支持向量機,是一個功能非常強大的機器學習模型,可以處理線性與非線性的分類、回歸,甚至是異常檢測。它也是機器學習中非常熱門的算法之一,特別適用於復雜的分類問題,並且數據集為小型、或中型的數據集。

這章我們會解釋SVM里的核心概念、原理以及如何使用。

 

線性SVM分類

我們首先介紹一下SVM里最基本的原理。這里先看一張圖:

這個是Iris數據集中的部分數據,可以看到這兩個類別可以由一條直線很簡單地直接分開(也可以說它們是線性可分)。左邊的圖上畫出了3個可能的線性分類器的決策邊界,其中綠色的最差,因為它無法將兩個類別區分開來。另外兩個看起來在訓練集上表現良好,但是它們的決策邊界與數據離的太近,所以如果有新數據引入的話,模型可能不會在新數據集上表現良好。再看看右邊的圖,實線代表的是一個SVM分類器的決策邊界。這條線不僅將兩個類別區分了開來,同時它還與(離此決策邊界)最近的訓練數據條目離的足夠遠。大家可以把SVM分類器看成一個:在兩個類別之間,能有多寬就有多寬的大馬路(這大馬路就是右圖的兩條平行虛線)。這個稱為 large margin classification(大間距分類)。

可以看到的是,在數據集中新增加的訓練數據在“馬路外側”的話,則不會對決策邊界產生任何影響,決策邊界完全僅由“馬路線”(右圖虛線)上的數據決定。這些決策邊界上的數據實例稱為支持向量(support vectors),如右圖中的兩個圓。

需要注意的是,SVM對特征的取值范圍非常敏感,如下圖所示:在左邊的圖中,縱坐標的取值范圍要遠大於橫坐標的取值范圍,所以“最寬的馬路”非常接近水平線。在做了特征縮放(feature scaling)后,例如使用 sk-learn的StrandardScaler,決策邊界便看起來正常的多了(如下右圖)。

 

軟間隔分類(Soft Margin Classification

如果我們嚴格地要求所有點都不在街道上並且被正確的分類,則這個稱為硬間隔分類(hard margin classification)。硬間隔分類中有兩個主要問題,第一,這個僅在線性可分的情況下適用;第二,它對異常點非常敏感。如下圖所示,在左邊的圖中,如果存在這種異常點,則無法找到一個硬間隔(hard margin)。在右邊的圖中,如果存在這種類型的異常點,則最終的決策邊界與我們之前的決策邊界會有很大的差異,並且它的泛化性能可能並不太好。

 

為了避免這些情況,我們需要用一個更靈活的模型。所以我們的目標是:在“保持街道足夠寬”與限制“間隔侵犯”(margin violations,意思是說數據條目最終在街道中間,或者甚至是在錯誤的一邊)之間找到一個良好的平衡。這個稱為軟間隔分類(soft margin classification)。

在sk-learn SVM 類中,我們可以通過c參數控制這個平衡。較小的c值會使得街道更寬,但是間隔侵犯(margin violation)會更多。下圖是兩個軟間隔SVM分類器在同一個非線性可分的數據集上的決策邊界與間隔:

 

在左邊的圖中,使用的是一個較小的c值,可以看到間隔非常大,但是很多實例都在街道上。在右邊的圖中,使用的是一個較大的c值,所以分類器作用后的間隔侵犯(margin violation)較少,但是間隔也比較小。不過從整體來看,第一個分類器的泛化性能看起來會更好(在訓練集上的預測僅有少部分預測錯誤,因為雖然有margin violation,但是實際上大部分的margin violation還是在它們所屬的決策邊界那邊)。

這里需要提示大家的是:如果SVM出現了過擬合,則可以嘗試通過降低c的值來進行正則化。

下面是一個示例代碼,加載iris 數據集,對特征進行縮放,然后訓練一個線性SVM模型(使用LinearSVC 類,指定C=1以及hinge 損失函數)用於檢測Iris-Virginica flowers。模型的結果就是上圖中C=1時的圖:

import numpy as np
from sklearn import datasets
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC

iris = datasets.load_iris()
X = iris['data'][:, (2,3)] # petal length, petal width
y = (iris['target'] == 2).astype(np.float64) # Iris-Virginica

svm_clf = Pipeline([
    ("scaler", StandardScaler()),
    ("linear_svc", LinearSVC(C=1, loss="hinge")),
])
svm_clf.fit(X, y)

 

然后使用訓練好的模型做預測:

svm_clf.predict([[5.5, 1.7]])
>array([1.])

 

上面的代碼也可以進行改寫,也可以用SVC類,使用SVC(kernel="linear", C=1)。但是它的速度會慢很多,特別是訓練集非常大時,所以並不推薦這種用法。另外的一種用法是使用SGDClassifier類,SGDClassifier(loss="hinge", alpha=1/(m*C))。這樣會使用隨機梯度下降訓練一個線性SVM分類器。它的收斂不如LinearSVC類快,但是在處理非常大的數據集時(無法全部放入內存的規模)非常適用,或者是處理在線分類任務(online classification)時也比較適用。

LinearSVC類會對偏置項(bias term)正則,所以我們應該先通過減去訓練集的平均數,讓訓練集集居中。如果使用了StandardScaler處理數據,則這個會自動完成。另一方面,必須要確保設置loss的超參數為hinge,因為它不是默認的值。最后,為了性能更好,我們應該設置dual超參數為False,除非數據集中的特征數比訓練數據條目還要多。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM