本篇主要內(nèi)容:SVM解決非線性可分,Kernel Function
添加多項(xiàng)式特征解決非線性可分問(wèn)題
上篇我們介紹了SVM是如何生成線性決策邊界解決線性可分或近似線性可分問(wèn)題的,本篇將介紹SVM如何解決線性不可分問(wèn)題。來(lái)看這樣的一個(gè)數(shù)據(jù)集:
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
X, y = datasets.make_moons(noise=0.15,random_state=666)
plt.scatter(X[y==0,0],X[y==0,1])
plt.scatter(X[y==1,0],X[y==1,1])
plt.show()

這是sklearn的datasets中的moon數(shù)據(jù),這里給它加入了一定的噪音,顯然這是一個(gè)線性不可分?jǐn)?shù)據(jù)。在Logostic回歸中,為了得到非線性決策邊界,我們?yōu)閿?shù)據(jù)加入了多項(xiàng)式特征,同樣的思想,我們也可以在使用SVM時(shí)加入多項(xiàng)式特征,這樣就可以解決一些非線性可分問(wèn)題。針對(duì)上面的例子:
from sklearn.preprocessing import PolynomialFeatures,StandardScaler
from sklearn.svm import LinearSVC
from sklearn.pipeline import Pipeline
def PolynomialSVC(degree,C=1.0):
return Pipeline([
('poly',PolynomialFeatures(degree=degree)),
('std_scaler',StandardScaler()),
('linearSVC',LinearSVC(C=C))
])
poly_svc = PolynomialSVC(degree=3)
poly_svc.fit(X,y)
這里將所有過(guò)程封裝了一個(gè)Pipeline。使用它創(chuàng)建一個(gè)SVM分類器,給數(shù)據(jù)添加3次冪多項(xiàng)式特征,訓(xùn)練該分類器,并繪制決策邊界:
plot_decision_boundary(poly_svc,axis=[-1.5,2.5,-1.0,1.5])
plt.scatter(X[y==0,0],X[y==0,1])
plt.scatter(X[y==1,0],X[y==1,1])
plt.show()

可以看到?jīng)Q策邊界已經(jīng)是非線性的了,并且對(duì)于圖中的兩類樣本也很好地進(jìn)行了分類。
核函數(shù)(Kernel Function)
SVM本質(zhì)上就是求解一個(gè)二次規(guī)劃問(wèn)題,不過(guò)一般我們并不直接求解:
而是求解它的對(duì)偶問(wèn)題(具體求解翻閱機(jī)器學(xué)習(xí)或運(yùn)籌學(xué)教材),在它的對(duì)偶問(wèn)題中,會(huì)遇到不同特征向量的內(nèi)積:

如果要解決線性不可分問(wèn)題,還需要SVM通過(guò)一個(gè)非線性變換 φ( x) ,將輸入的低維特征映射到高維特征空間,特征空間的維數(shù)可能非常高。考慮到真正求解SVM的最優(yōu)化問(wèn)題的時(shí)候,往往只會(huì)用到兩個(gè)高維特征空間特征的內(nèi)積,如果SVM的求解只用到內(nèi)積運(yùn)算,而在低維輸入空間又存在某個(gè)函數(shù) K(x, x′) ,它恰好等于在高維空間中這個(gè)內(nèi)積,即K( x, x′) =<φ( x)?φ( x′) > 。那么SVM就不用計(jì)算復(fù)雜的非線性變換,而由這個(gè)函數(shù) K(x, x′) 直接得到非線性變換的內(nèi)積,大大簡(jiǎn)化了計(jì)算。這樣的函數(shù) K(x, x′) 就被稱為核函數(shù)。
以一個(gè)例子來(lái)展示一下核函數(shù)的效果,假設(shè)現(xiàn)在有兩個(gè)二維空間中的數(shù)據(jù)點(diǎn)x=(x1,x2)和y=(y1,y2),考慮下面這個(gè)二元函數(shù):
于是,
發(fā)現(xiàn)最后結(jié)果恰好是兩個(gè)向量的內(nèi)積,而且兩個(gè)向量分別是二維空間數(shù)據(jù)點(diǎn)x和y在5維空間中的映射!想到剛才核函數(shù)的定義,我們很容易知道,K(x,y)就是一個(gè)核函數(shù)。它給出了一個(gè)二維的表達(dá)式,使得x,y代入即可求值,而不再需要先把x,y映射成5維空間中的向量p,q再求內(nèi)積,這樣大大簡(jiǎn)化了運(yùn)算。
sklearn中常用的核函數(shù):

通過(guò)在SVM中使用這些核函數(shù)可以將原本線性不可分的數(shù)據(jù)映射到高維特征空間后變的線性可分。
sklearn中的RBF核
RBF(Radial Basis Function)中文叫徑向基函數(shù),其實(shí)就是Gauss核函數(shù):
它可以將特征映射到無(wú)窮維空間,其中的是一個(gè)超參數(shù),
越大表示模型復(fù)雜度越高,相應(yīng)的也就越容易出現(xiàn)過(guò)擬合,實(shí)際中要通過(guò)調(diào)參得到最好的
。下面在moon數(shù)據(jù)集上使用Gauss核函數(shù):
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.pipeline import Pipeline
def RBFKernelSVC(gamma=1.0):
return Pipeline([
('std_scaler',StandardScaler()),
('svc',SVC(kernel='rbf',gamma=gamma))
])
接下來(lái)訓(xùn)練一個(gè)使用RBF核的SVM,此時(shí)默認(rèn)是1,并繪制決策邊界:
svc = RBFKernelSVC(gamma=1.0)
svc.fit(x,y)
plot_decision_boundary(svc,axis=[-1.5,2.5,-1.0,1.5])
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.show()
決策邊界:

可以看到時(shí)模型的效果還是不錯(cuò)的。
再來(lái)看一下的情況:
svc100 = RBFKernelSVC(gamma=100)#過(guò)擬合
svc100.fit(x,y)
plot_decision_boundary(svc100,axis=[-1.5,2.5,-1.0,1.5])
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.show()
決策邊界:

此時(shí)明顯出現(xiàn)了過(guò)擬合。
可以繼續(xù)測(cè)試,當(dāng)時(shí)會(huì)出現(xiàn)欠擬合,這里不再展示。
在sklearn中可以很方便地調(diào)用它提供的核函數(shù),當(dāng)然也可以自己編寫核函數(shù),在符合sklearn接口的情況下以下能夠無(wú)縫銜接。