1. 程式人生 > >SVM的一些學習心得及案例(Python程式碼)實現

SVM的一些學習心得及案例(Python程式碼)實現

1、基本概念

向量的內積即一個向量在另一個向量上的投影乘上被投影向量的模,上圖不管是a投影在b上,還是b投影在a上,其結果是一樣的,原理參照 B站上

ab = (a1e1 + a2e2)∙(b1e1 + b2e2)

           = a1b1e1e1 + a1b2e1e2 

              + a2b1e2e1 + a2b2e2e2

           = a1b1 + a2b2

=aTb

對於一個超平面,其方程為 wTx + b = 0 (二維的超平面就是線,而線的方程為ax + by + c = 0 ),

假設A、B兩點在wTx + b = 0上


那麼向量 w 垂直於這個超平面。

2、線性可分支援向量機


假設對於如圖所示的訓練集,我們怎麼去尋找它的超平面呢?

無數條直線可以表示為wTx(i)+ b,我們要做的就是在這麼多條的直線中找到一條比較好的超平面

因此首先需要求出所有樣本點到直線的距離d=|wTx(i)+ b| / ||w||,而如果我們定義實心點為正例+1,空心點為負例-1

由於 g(x(i)) = sign(wTx(i) + b),那麼當

  • wTx(i) + b > 0,將其分為正例,y(i) = 1

  • wTx(i) + b < 0,將其分為反例,y(i) = -1

  • 根據上面兩種情況,關係式 

    y(i)(wTx(i) + b) > 0 永遠成立

d可寫為d=y(i)(wTx(i)+ b) / ||w|| 即可以把絕對值去掉。

1)需所有的樣本點到直線的距離最短 min  y(i)(wTx(i)+ b) / ||w||        (保證 直線中找到一條比較好的超平面)

2)  在1)的前提下,選出一條最大值max min  y(i)(wTx(i)+ b) / ||w||      (保證間隔最大)

目標函式為

現在有個問題,當 w 和 b 變成它們原來 0.01 倍或者 1000 倍時,wTx + b = 0 代表的是同樣的超平面,展示如下:

wTx + b = 0

0.01wTx + 0.01b = 0

1000wTx + 1000b = 0

即我們在後面解出唯一的解時,可以縮放權重w和偏差b的比例.


證:

最終目標函式變為:


上面連等式第一步是因為最大化一個正函式就是最小化它的倒數;第二步是用了 ||w|| 的定義;第三步純粹是為了之後求導數容易,而且最小化一個函式跟最小化它的一半是完全等價的。

在 SVM 問題中,我們不但希望要最大化 margin,還希望每個點都有分類正確,因為我們要解決下面優化問題


到此問題已經非常簡單了,目標函式是個二次凸函式,非常適合做優化;但是限制條件裡面有 min 出現,給優化問題造成了難度。因此我們將這一個帶 min 的限制條件轉換成 m 個“更鬆”的限制條件,如下


由限制條件可知,該問題是找一個超平面,線性分割所有點並使它們完全分類正確

這種超平面稱為線性硬分隔支撐向量機 (hard-margin SVM)

簡單的例子

二維問題來求解上面的原始問題


根據這個四個點展開限制條件得到

根據 (i) 和 (iii) 解得 w1 ≥ 1,根據 (ii) 和 (iii) 解得 w2 ≤ -1,這意味著目標函式


最小值在 w= 1 和 w2 = -1 時得到,很容易解得 b = -1。最優分割超平面在下圖展示:


對那些剛好滿足限制條件的點,他們到超平面的距離都等於 1/||w||。這些點也都在灰色緩衝帶的邊界上,稱為支撐向量 (support vector),顧名思義,這些向量支撐著緩衝帶,防止它繼續向外展開。

軟間隔 SVM 原始問題

硬間隔 SVM 要求所有得資料都要分類正確,在此前提下再最小化wTw,但是現實中這種事情很少發生 (即沒有這樣一個完美的資料讓你所有分類正確)。那麼你要放棄這個問題,還是要試試另外一種方法,即軟間隔 SVM?

軟間隔 SVM 就是為了緩解“找不到完美分類資料”的問題,它會容忍一些錯誤的發生,將發生錯誤的情況加入到目標函式之中,希望能得到一個錯分類情況越少越好的結果。為了能一目瞭然發現硬間隔和軟間隔 SVM 原始問題之間的相似和不同之處 (紅色標示),將它們的類比形式展示在下表:


由上發現硬間隔和軟間隔 SVM 的區別就是後者多了 ξ 和 C,引數ξ是衡量資料犯了多大的錯誤,而不是資料犯了幾個錯誤。為了簡化令uy(i)(wTx(i) + b)

  • 當 ξi= 0 時,該點沒有違規而且分類正確,因為ui≥ 1,該點離分隔線距離大於等於 margin

  • 當 0 <ξ≤ 1 時,該點違規了但還是分類正確,因為ui大於“一個小於1”的正數,該點離分隔線距離小於 margin

  • ξ> 1 時,該點違規了並分類錯誤,因為ui大於一個負數 (ui可能小於0),我們知道只有ui> 0 是分類正確

上述討論情況在下圖中展示


總結來說,用 鬆弛變數ξ 來記錄違規資料距離邊界的距離,並將這個距離納入到最佳化的標準裡面。但是我們不希望 ξ 太大,因為這意味著有某個資料分類錯的太離譜,因此需要用 C 來懲罰太大的ξ。引數 C 控制“到底要多大的邊界”還是“更加在意違反邊界的情形越少越好”。(調參會用到)

  • 越大的 C 代表,寧可邊界窄一點,也要違規 (甚至出錯) 資料少點

  • 越小的 C 代表,寧可邊界寬一點,即便犧牲分類精度也無所謂

iris資料SVM例項

部分資料


程式碼:

import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
from sklearn import svm
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score


if __name__ == "__main__":
iris_feature = '花萼長度', '花萼寬度', '花瓣長度', '花瓣寬度'
path = 'E:\\machine learning\\code\\11.RandomForest\\iris.data'  # 資料檔案路徑
data = pd.read_csv(path, header=None)
    x, y = data[[0, 1]], pd.Categorical(data[4]).codes
    #xiris.data裡的第一二列,yiris.data裡的第5列;pd.Categorical對花的類別進行編碼
x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=1, train_size=0.6)

    # 分類器
# clf = svm.SVC(C=0.1, kernel='linear', decision_function_shape='ovr')
    #ovr   one vs rest
clf = svm.SVC(C=0.8, kernel='rbf', gamma=20, decision_function_shape='ovr')
    clf.fit(x_train, y_train.ravel())

random_state:是隨機數的種子。

  隨機數種子:其實就是該組隨機數的編號,在需要重複試驗的時候,保證得到一組一樣的隨機數。比如你每次都填1,其他引數一樣的情況下你得到的隨機陣列是一樣的。但填0或不填,每次都會不一樣。隨機數的產生取決於種子,隨機數和種子之間的關係遵從以下兩個規則:種子不同,產生不同的隨機數;種子相同,即使例項不同也產生相同的隨機數。

kernel='linear'時,為線性核,C越大分類效果越好,但有可能會過擬合(defaul C=1)。