SVM的一些學習心得及案例(Python程式碼)實現
1、基本概念
向量的內積即一個向量在另一個向量上的投影乘上被投影向量的模,上圖不管是a投影在b上,還是b投影在a上,其結果是一樣的,原理參照 B站上
a∙b = (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
-
根據上面兩種情況,關係式
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,這意味著目標函式
最小值在 w1 =
1 和 w2 =
-1 時得到,很容易解得 b = -1。最優分割超平面在下圖展示:
對那些剛好滿足限制條件的點,他們到超平面的距離都等於
1/||w||。這些點也都在灰色緩衝帶的邊界上,稱為支撐向量
(support vector),顧名思義,這些向量支撐著緩衝帶,防止它繼續向外展開。
軟間隔
SVM 原始問題
硬間隔 SVM 要求所有得資料都要分類正確,在此前提下再最小化wTw,但是現實中這種事情很少發生 (即沒有這樣一個完美的資料讓你所有分類正確)。那麼你要放棄這個問題,還是要試試另外一種方法,即軟間隔 SVM?
軟間隔 SVM 就是為了緩解“找不到完美分類資料”的問題,它會容忍一些錯誤的發生,將發生錯誤的情況加入到目標函式之中,希望能得到一個錯分類情況越少越好的結果。為了能一目瞭然發現硬間隔和軟間隔 SVM 原始問題之間的相似和不同之處 (紅色標示),將它們的類比形式展示在下表:
由上發現硬間隔和軟間隔 SVM 的區別就是後者多了 ξ 和 C,引數ξ是衡量資料犯了多大的錯誤,而不是資料犯了幾個錯誤。為了簡化令ui = y(i)(wTx(i) + b):
-
當 ξi= 0 時,該點沒有違規而且分類正確,因為ui≥ 1,該點離分隔線距離大於等於 margin
-
當 0 <ξi ≤ 1 時,該點違規了但還是分類正確,因為ui大於“一個小於1”的正數,該點離分隔線距離小於 margin
-
當ξi > 1 時,該點違規了並分類錯誤,因為ui大於一個負數 (ui可能小於0),我們知道只有ui> 0 是分類正確
上述討論情況在下圖中展示
總結來說,用 鬆弛變數ξ 來記錄違規資料距離邊界的距離,並將這個距離納入到最佳化的標準裡面。但是我們不希望 ξ 太大,因為這意味著有某個資料分類錯的太離譜,因此需要用 C 來懲罰太大的ξ。引數 C 控制“到底要多大的邊界”還是“更加在意違反邊界的情形越少越好”。(調參會用到)
-
越大的 C 代表,寧可邊界窄一點,也要違規 (甚至出錯) 資料少點
-
越小的 C 代表,寧可邊界寬一點,即便犧牲分類精度也無所謂
部分資料
程式碼:
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 #即x為iris.data裡的第一二列,y為iris.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)。