您可能聽說過所謂的核心技巧,這是一種支援向量機(SVMs)處理非線性資料的小技巧。這個想法是將資料對映到一個高維空間,在這個空間中資料變成線性,然後應用一個簡單的線性支援向量機。聽起來很複雜,但操作起來確實如此。儘管理解該演算法的工作原理可能比較困難,但理解它們試圖實現的目標卻相當容易。往下讀,自然就會明白了!
當資料是線性可分的:線性支援向量機
支援向量機是如何工作的呢?支援向量機可用於分類和迴歸任務,但是在本文中,我們將主要關注前者。讓我們首先考慮具有線性可分的兩個類的資料。我們將建立兩個獨立的點團,並使用scikit-learn對它們擬合成一個線性支援向量機。注意,我們在擬合模型之前對資料進行了標準化,因為支援向量機對特徵的尺度很敏感。
X, y = make_blobs(n_samples=100, centers=2, n_features=2, random_state=42)
pipe = make_pipeline(StandardScaler(), LinearSVC(C=1, loss="hinge"))
pipe.fit(X, y)
plot_svm(pipe, X)
customplot_svm()函式的輸出將在下面看到,它由相當多的matplotlib程式碼組成。
線性支援向量機
有許多行可以完美地將這兩個類分開,確切地說,有無窮多行。SVM擬合的直線的特殊之處在於,它是兩個虛線標記的直線之間的中間線,並且這條線距離兩個類之間的距離近似相等。這樣,支援向量機的決策線(標記為實黑線)離兩個類的距離越遠越好,保證了模型能很好地泛化到新的例子。
用紅色圈出的直線邊界上的觀測稱為支援向量,因為它們確定直線的位置。如果我們增加一些這條直線外的觀察,它不會改變位置。
注:這是一個硬邊分類的例子,這意味著不允許觀察到邊界。或者,我們可以做一個軟邊界分類:允許對頻段進行一些加寬。這會減小異常值的影響,並且可以由LinearSVC()中的引數C控制:例如,我們原本將其設定為1,隨後減少到0.1,將會導致更寬的直線,但其中會有一些觀察值。不管怎樣,這和我們的內容沒有什麼關係。
現實生活中的大多數資料集都不是線性可分的。讓我們看看線性SVM是如何處理月亮形狀的資料的。
X, y = make_moons(n_samples=100, noise=0.1, random_state=42)
pipe = make_pipeline(StandardScaler(), LinearSVC(C=1, loss="hinge"))
pipe.fit(X, y)
plot_svm(pipe, X)
對於線性不可分資料使用線性支援向量機根本不起作用。
這看起來不太好,讓我們想想該怎麼處理這樣的資料。
將資料對映到更高維度
在我們討論支援向量機核心和它們的作用之前,讓我們先看看它們利用的一個思想:在高維空間中,資料變得線性可分的可能性更大。
下面兩幅圖清楚地說明了這一點。當我們只有一個特徵x1時,我們不能用一條線把資料分開。加上另一個特徵x2,等於x1的平方時,分離這兩個類變得容易。
增加另一個特性使得資料可以線性分離。
支援向量機的核心到底是什麼?
那麼,核心技巧是關於什麼的呢?這只是一種向資料新增更多特性、希望使其線性可分的智慧方法。因為新增它們將使模型時間複雜度增加,創作者利用一些神奇的數學特性(不在本文的範圍),使我們能夠獲得相同的結果而模型執行速度並沒有變慢。
兩種常見的核是多項式核和高斯徑向基函式(RBF)核。它們新增的特性的型別不同,讓我們來看看它們的功能!
多項式核新增的多項式特徵
創造更多特徵的一種方法是在一定程度上使用它們的多項式組合。例如,有兩個特徵A和B, 2次多項式將產生6個特徵:1(任何特徵都為0次冪),A, B, A², B²和AB。我們可以手動使用scikit-learn庫的PolynomialFeatures()很容易地新增這些功能:
X, y = make_moons(n_samples=100, noise=0.1, random_state=42)
pipe = make_pipeline(StandardScaler(),
PolynomialFeatures(degree=3),
LinearSVC(C=5))
pipe.fit(X, y)
plot_svm(pipe, X)
或者我們可以簡單地使用多項式核:
X, y = make_moons(n_samples=100, noise=0.1, random_state=42)
pipe = make_pipeline(StandardScaler(), SVC(kernel="poly", degree=3, C=5, coef0=1))
pipe.fit(X, y)
plot_svm(pipe, X)
您可以自己驗證兩個實現生成兩個大致相同的圖形,有點像這樣:
用多項式核判定邊界。
使用核心的好處是,您可以調整核的屬性,從而增加資料在這個高維空間中線性可分的可能性,而不會降低模型的速度。
對於我們的月亮資料,很明顯,從散點圖可以看出3次多項式是足夠的。但是,對於更復雜的資料集,可能需要使用更高的次數。這時核心技巧的威力可以更好地體現出來。
基於高斯RBF核的相似性特徵
另一種向資料新增更多特徵的方法是使用所謂的相似特徵。相似特性度量現有特性的值與地標的距離。讓我們實際一點:我們有一個只有一個特徵的資料集,x1。我們想要建立兩個相似特徵,所以我們選擇兩個標準,即從我們的單一特徵中選擇參考值。比如-1和1。然後,對於每個x1的值,我們計算它與第一個地標的距離。這是我們新的相似性特徵,x2。然後我們做同樣的事情,比較x1和第二個參考值來得到x3。現在我們甚至不需要原始的特性x1!這兩個新的相似特徵使我們的資料很容易分離。
相似特徵使資料線性可分。
那麼,如何計算每次目標點到參考值的距離呢?一個普遍的選擇是使用高斯徑向基函式RBF。定義為:
其中x是我們最初的特徵,而引數γ是0.3。
例如,在我們唯一的原始特徵上,第一次觀察的得分為-3。我們計算x2=exp(-0.3 *(3 -(1))²)≈0.30,x3=exp(-0.3 *(3 -(1))²)≈0.01。這是右圖最下面的兩點。
在上面的例子中,我們幸運地選擇了兩個恰巧執行良好的參考。在實踐中,一個特徵可能需要很多參考,這意味著許多新的相似特徵。這將大大降低支援向量機的速度——除非我們使用核心技巧!與多項式核類似,RBF核允許我們獲得完全相同的結果,就好像我們在原始特徵的每個值上都添加了一個參考,實現過程而不需要我們去做。讓我們在月亮形狀的資料上試試。
X, y = make_moons(n_samples=100, noise=0.1, random_state=42)
pipe = make_pipeline(StandardScaler(), SVC(kernel="rbf", gamma=0.3, C=5))
pipe.fit(X, y)
plot_svm(pipe, X)
利用RBF核函式確定邊界,γ=0.3
決策邊界看起來相當不錯,但是您可能已經注意到一些分類錯誤的示例。我們可以透過調整引數γ的方式來解決這個問題,它作為一個正則化器——越小則決策邊界越平滑,這可以防止過擬合。然而,在本例中,我們似乎還沒有完全匹配,所以我們將γ增加到0.5。
利用RBF核函式確定邊界,γ=0.3
現在所有的特徵都正確分類了!
總結
支援向量機透過尋找離資料儘可能遠的線性決策邊界來進行分類。它們線上性可分離資料方面工作得很好,但在其他方面則經常失敗。
為了使非線性資料線性可分(從而方便支援向量機),我們可以給資料新增更多的特徵,因為在高維空間中,資料線性可分的機率會增加。
兩種常用的新特徵型別是現有特徵的多項式組合(多項式特徵)和從參考計算的距離,即一些參考值(相似特徵)。
實際上,新增它們可能會降低模型的速度。
核心技巧策略利用一些數學屬性來提供相同的結果並有效提高模型速度,就像我們添加了一些額外的特性,而速度上沒有新增它們一樣。
多項式核和RBF核可以分別新增多項式特徵和相似度特徵。
引用
Geron A., 2019, 2nd edition, Hands-On Machine Learning with Scikit-Learn and TensorFlow: Concepts, Tools, and Techniques to Build Intelligent Systems
感謝閱讀!我希望你學到一些有用的東西,這將提高你的專案水平
作者:Michał Oleszak
本文程式碼:https://github.com/MichalOleszak/KnowledgeBank/blob/master/blog_posts/svm_kernels/svm_kernels.ipynb)
deephub翻譯組:孟翔傑