ml課程:SVM相關(含程式碼實現)
以下是我的學習筆記,以及總結,如有錯誤之處請不吝賜教。
本文主要介紹svm的創始人Vapnik‘s如何一步一步構建出這個經典演算法模型的,同時也可以給我們以後演算法之路提供一個思路,即使你對優化等數學方法不熟悉,依然可以創造出很好的演算法。
下svm關鍵的幾個idea:
KEY IDEA 1:支援向量機最關鍵的一個假設是我們在分類過程中,最重要的是找到一個決策邊界,而且我們希望這個決策邊界泛化能力是最好的,而svm則是找到一條widest street way,這條街是由支援向量所構成的。我們假設支援向量所在點與原點構成的向量為,與決策邊界垂直的方向法向量為,支援向量到決策邊界的距離表示為b,那麼我們就用這三個值表示出他們的關係:
KEY IDEA 2:我們假設這條street的寬度為1,那麼僅針對訓練集有 :
其中:取值為0的即為支援向量。
KEY IDEA 3:那麼我們如何使得這條street越寬越好呢?這條街的寬度可以表示為:,分別將代入,可以得到:,,得到:
因此我們只需要求得,即,即:
s.t.
KEY IDEA 4:將其代入拉格朗日多項式得到:
分別對和b求導得到:
分別令其等於0,求得:
,
代入原式:
SVM另一種理解:假設一個函式叫做合頁損失函式(hinge loss):
合頁損失的函式影象如下所示:
SMO演算法(sequential minimal optimization):
首先介紹座標上升法:這個方法的思想是固定其他引數變數,先求其中一個變數的最大值。
SMO演算法則是在座標上升法之上改進一下,每次選擇兩個變數進行優化(兩個變數其實等價於一個變數):
演算法流程:(具體流程參考李航的《統計學習方法》P126-130頁)
核心程式碼:
def smoSimple(dataMatIn, classLabels, C, toler, maxIter):
dataMatrix = mat(dataMatIn); labelMat = mat(classLabels).transpose()
b = 0; m,n = shape(dataMatrix)
alphas = mat(zeros((m,1)))
iter = 0
while (iter < maxIter):
alphaPairsChanged = 0
for i in range(m):
fXi = float(multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[i,:].T)) + b
Ei = fXi - float(labelMat[i])#if checks if an example violates KKT conditions
if ((labelMat[i]*Ei < -toler) and (alphas[i] < C)) or ((labelMat[i]*Ei > toler) and (alphas[i] > 0)):
j = selectJrand(i,m)
fXj = float(multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[j,:].T)) + b
Ej = fXj - float(labelMat[j])
alphaIold = alphas[i].copy(); alphaJold = alphas[j].copy();
if (labelMat[i] != labelMat[j]):
L = max(0, alphas[j] - alphas[i])
H = min(C, C + alphas[j] - alphas[i])
else:
L = max(0, alphas[j] + alphas[i] - C)
H = min(C, alphas[j] + alphas[i])
if L==H: print("L==H"); continue
eta = 2.0 * dataMatrix[i,:]*dataMatrix[j,:].T - dataMatrix[i,:]*dataMatrix[i,:].T - dataMatrix[j,:]*dataMatrix[j,:].T
if eta >= 0: print("eta>=0"); continue
alphas[j] -= labelMat[j]*(Ei - Ej)/eta
alphas[j] = clipAlpha(alphas[j],H,L)
if (abs(alphas[j] - alphaJold) < 0.00001): print("j not moving enough"); continue
alphas[i] += labelMat[j]*labelMat[i]*(alphaJold - alphas[j])#update i by the same amount as j
#the update is in the oppostie direction
b1 = b - Ei- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[i,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[i,:]*dataMatrix[j,:].T
b2 = b - Ej- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[j,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[j,:]*dataMatrix[j,:].T
if (0 < alphas[i]) and (C > alphas[i]): b = b1
elif (0 < alphas[j]) and (C > alphas[j]): b = b2
else: b = (b1 + b2)/2.0
alphaPairsChanged += 1
print("iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged))
if (alphaPairsChanged == 0): iter += 1
else: iter = 0
print("iteration number: %d" % iter)
return b,alphas
軟間隔分類器:當資料線性不可分時,即使對映到高維空間並不能保證線性可分,如下圖所示:
而軟間隔分類器則是允許資料擁有小於1的幾何間隔,但是要受到懲罰:
代入拉格朗日函式得到:
從而得到新的對偶問題:
對比原來只是對做了更多約束,新約束下的SMO演算法如下圖:
核技法:
同時我們可以在求其支援向量時使用核函式,將很多線性不可分的情況,對映至高維空間,而不用求其對映函式,只需求:
多項式核函式:
對應對映函式:
加常數項的多項式核函式:
對應對映函式:
高斯核函式:
以上是幾個核函式的例子,那麼什麼樣的核是合法的呢?
Mercer定理:K是合法的核的充分必要條件是對於一個有限的資料集,對應的和矩陣都是半正定矩陣。關於半正定矩陣可自行百度。
以下是幾個常用的核函式:
通過以上的敘述,可以總結SVM有以下性質:
- 數學特性:凸優化問題,保證會有全域性最優解
- 模型特性:
- 可以處理高維資料
- 軟間隔降低過擬合
- 求解完成後只有少數資料起作用
- 靈活的選擇核函式
下次將介紹另一個經典演算法:EM演算法,未完,To be continue......