1. 程式人生 > >機器學習筆記(八)震驚!支援向量機(SVM)居然是這種機

機器學習筆記(八)震驚!支援向量機(SVM)居然是這種機

今天想說的呢是SVM支援向量機(support vector machine),我覺得這個演算法它初始出發的想法真的是非常符合人性,特徵空間上間隔最大的分類器,你隨便問一個人分開空間上的兩坨點最佳的平面是什麼,他的直覺也會告訴他是介於兩坨之間然後比較中間的那個位置,如果不說人話,那就是SVM。

對於SVM呢,主要分為以下幾種情況。

1 線性可分SVM

2 線性SVM

3 非線性SVM

針對每一個概念和它應用的情況,接下來我們詳細討論,首先引入幾個概念。

第一,  線性可分。

對於兩類樣本,總存在著這樣若干個超平面(wx+b)可以把兩類完全正確的分開,那我們就稱這個資料是線性可分的。退化到二維空間上來說,就是可以用若干條直線將兩類資料完全正確地分開,那麼這個樣本就稱為線性可分的。

第二,  函式間隔。

想必大家高中都學過,點(x1,y1)到直線Ax+By+C的距離是|Ax1+By1+C|/sqrt(A^2+B^2),推廣到高維空間上就是樣本x到超平面wx+b=0的距離是|wx+b|/||w||。假如樣本分為正負兩類分別用+1-1表示,那麼如果分類正確的話y(wx+b)=|wx+b|,所以我們y(wx+b)這個值既能表明我們分類是否正確,還能通過距離的遠近表明分類正確的確信度,所以我們把它定義為函式間隔。

第三,  幾何間隔。

上面已經提到了函式間隔的概念,但有一個問題就是,對於超平面而言,只要w和b成比例的變化,那麼超平面是不變的,但這樣的話函式間隔就發生了變化。因此函式間隔我們是可以控制它的範圍的,用它除一個w的二次模,就能得到一個定值,我們把y(wx+b) /||w||定義為幾何間隔,分類正確時就表明樣本到超平面的距離。

好的,有了以上這些概念我們就可以進一步探討SVM了。

===================================================================

線性可分SVM:

對於線性可分的資料而言,我們自然有無數個超平面用於劃分分類,但對每一種分類方式,其最小的幾何間隔可求,當這個最小几何間隔最大的時候,上面也說了,其實意味著劃分正確的確信度最高,是我們尋求的最優解。

所以,優化目標就變成了


求最小的那一項裡就是我們的函式間隔,函式間隔有什麼性質?可控可變乖巧聽話,所以我們令所有樣本的函式間隔都大於等於1,這樣後面一項就變成1了,那麼優化目標就變成


考慮到1/||w||和1/2||w||^2等價,可以把優化問題變成一個帶約束的最小化問題,利用拉格朗日乘子法,構建拉格朗日函式


求這個函式的最大值,由於alpha始終大於等於0,所以對於函式間隔不是1的點而言,其對應的alpha一定等於0才能取到最大值,因此我們就有了拉格朗日函式的最大值就是第一項,我們想優化的目標函式,因此優化目標變成了


這裡根據拉格朗日對偶性(可以參考李航博士的《統計學習方法》,但其實也只是給出了定理,並沒有給出證明,所以這點還是有點暈)將這個極小極大問題轉換成極大極小問題,也就是先對w,b求最小值,再求對alpha的最大值。極小問題就轉化成求偏導為0,也就是


有了這兩個等式,我們再把他們回代到拉格朗日函式當中,有


現在拉格朗日函式中需要優化的引數變成了alpha一個,現在只要求得了alpha的最佳值就解決了我們一開始的優化問題,也就是最後需要我們做的工作就是


實際的應用中,當我們解決了上述最優問題之後,我們再回過來求w,b的最優值。W的值很明顯,根據上面求導所得的公式進行計算就成,但b的取值怎麼求呢?這需要我們回到夢開始的地方,一開始我們就做了一個約束,要求對所有的樣本函式間隔都大於等於1,一會兒就要用到這個。首先,alpha不可能全為0,假如alpha全為0則w也為0,我們知道樣本有正負兩類,這樣y(wx+b)=yb不能保證始終大於1,所以必有不等於0的alpha,而對於不等於0的alpha對應的函式間隔必然為1能保證拉格朗日函式的極大值與我們一開始的優化目標等價,所以這裡借的到了一個有關b的等式了,藉此便可以求得b的最價值,具體如下


講到這裡,問題已經解決了,一開始尋找的最佳分離超平面就這樣求得。

就這樣結束了是不是有點怪,哪兒不對呢?支援向量機支援向量機,你倒是告訴我支援向量是啥啊!!!我們來觀察一下上面這個式子,alpha中大部分都是0的,只在少數函式間隔為1的樣本處不為0,那麼這樣的話w,b的取值就只和這些樣本有關,其他的樣本根本沒有地位啊,為了突出這些樣本與眾不同的地位,我們把它們稱為支援向量,超平面的選擇之和他們有關~

===================================================================

線性SVM:

講完線性可分SVM有什麼感覺,是不是世界太美好了?實際情況中,往往遇到的是線性不可分的資料,更過分的是,如果有叛徒混在另外一類的附近,但確實又線性可分,這樣求得的分離超平面泛化能力嚴重不足。

所以,怎麼辦呢?既然不能線性可分,不能嚴格滿足函式間隔大於等於1,那我們就給它放寬條件,每個樣本給一個鬆弛變數xi,當然這個xi也不能過分,我們需要在優化目標里加上關於它的懲罰項,所以新的優化目標就變成了


到了這裡還記得怎麼辦嗎?和線性可分SVM一模一樣,只不過約束條件變成了兩個,構建拉格朗日函式


下面怎麼來的,拉格朗日函式的極大值和原始優化目標一致,再利用對偶性,把極小極大問題轉換成極大極小問題。那麼第一步就是求關於w,b,xi的函式極小值,這個時候求導大法好,得到


好的,再回代看看拉格朗日函式變成啥


哎呀,結果和線性可分SVM一模一樣啊,那麼最後我們的優化目標就變成了


當然根據後面三個約束條件可以得到alpha和beta的範圍是0到C。

實際情況中根據上式求得最優的alpha,求w依然很輕鬆,根據求導那兒的公式就可以求得,那麼b呢,根據線性可分SVM的思路,我們是根據一開始給定函式間隔那個式子做的,但是,但是!現在情況不一樣了啊,現在多了一個鬆弛因子xi,怎麼辦呢?什麼情況下xi為0呢,就是beta不為0的情況,那也就是alpha介於0和C的時候,我們就可以利用函式間隔為1求得b的值,但是這裡選取不同的alpha會得到不同的結果,實際情況往往選所有點的均值,其形式和線性可分SVM一樣


那這種情況下的支撐向量是怎麼定義的呢,首先alpha為0的先排除掉,這些都是沒地位的點。然後alpha介於0到C的,xi必為0,因此他們是函式間隔為1的樣本點,那麼alpha為C的呢,xi可以不為0,如果xi小於1,就是位於函式間隔為1的超平面和分離超平面之間正確分類的點,如果xi為0,則剛好落在分割超平面上,如果xi大於0,則是誤分類的點,這幾種樣本就是線性SVM的支援向量。

===================================================================

非線性SVM。

這個不知道大家還記不記得,線上性迴歸裡面我提到過一件事兒,就是雖然它叫線性迴歸,但並不表示它只能是一個超平面,我們可以通過特徵的組合,來達曲面的效果。那對與SVM其實也一樣,我們可以通過一個變換,把原空間的資料對映到一個新的特徵空間中,原先也許是線性不可分的兩類樣本點到了新的特徵空間,變得線性可分了,這樣就可以利用線性可分SVM的辦法來解決分類問題。

最常見一個例子莫過於,二維空間上,兩個圓環,內環是一類,外環是一類,那在二維空間上你怎麼也不能線性分開吧,但是通過變換(x^2,y^2)就可以把內環的資料對映到靠近原點的第一象限空間內,而外環則是更遠處,進而變成線性可分的問題。

我想這個概念大家還是很容易接受的吧,主要因為也是很自然而然的一種想法。然後想提一下的就是核技巧,所謂kernel trick就是說我不直接定義這個對映的規則,而是直接給出核函式,這樣的好處是不會限制對映的方式,因為同一個核函式可以對應若干種對映的方式。

然後關於非線性SVM的公式推導,其實和上面兩種情況如出一撤,只是把本來x的內積改成了核函式,我就不去寫了。

最後的最後,發現一個問題,我上面辛辛苦苦求得了w和b,得到了最佳分離超平面,但忘了給出我們最後的分類器了,其實就是加一個符號函式而已,哈哈哈,如下

===================================================================

好了,理論部分可算講完了,碼字真累,我們再擼一小段程式碼結束吧。老樣子,還是鳶尾花資料,用SVM分一下看看,其實和前面其他的演算法的呼叫真是一模一樣,重點其實還是調參,回頭專門寫幾篇講調參的好了,這裡就講一下調包和用的過程吧。

mport numpy as np
from sklearn import svm
from sklearn.model_selection import train_test_split
from sklearn import datasets

iris=datasets.load_iris()
x=iris.data[:,:2]
y=iris.target
x_train, x_test, y_train, y_test = train_test_split(x, y, train_size=0.7, random_state=1)

model=svm.SVC(C=1, kernel='linear', decision_function_shape='ovr')
model.fit(x_train,y_train)

y_hat=model.predict(x_test)
print '訓練集上的正確率為%2f%%'%( model.score(x_train, y_train)*100)
print '測試集上的正確率為%2f%%'%( model.score(x_test, y_test)*100)

輸出為

訓練集上的正確率為83.809524%

測試集上的正確率為77.777778%

好啦,這就是SVM的內容,希望有幫到你,反正我是覺得推導的過程怎麼說呢,很符合我們的思維,所以感覺很順,中間除了一些數學上的知識還是很容易理解完全的。

抓住週末的小尾巴啊,還有半天啊哈哈哈~