1. 程式人生 > >機器學習:支援向量機(SVM)

機器學習:支援向量機(SVM)

1. 理論

  1. 概述:

    利用訓練集在特徵空間中求出一個分類超平面(w,b)把樣本切割開,依靠該超平面對新樣本進行分類。如果訓練集在當前的特徵空間中無法分割,則用核技術的對映函式把原特徵空間對映到高緯或者無窮維空間再切割。

  2. 基本概念:

    超平面:

    用(w,b)表示, w1*x1 + w2*x2 +...+ wn*xn = 0 表示在特徵空間中的一個平面。需要注意的是,一個平面可以對應多個(w,b)。
    

    函式距離(間隔):

    點到超平面的函式距離: y_i(w * x_i) 
    集合到超平面的函式距離: 集合中的點到超平面的函式距離的最小值
    

    幾何距離(間隔):

    點到超平面的幾何距離: 函式距離/||w||
    集合到超平面的幾何距離: 集合中的點到超平面的幾何距離的最小值
    
  3. 線性可分SVM

    線性SVM就是在訓練集中尋找一個幾何間隔最大的超平面(w,b)作為分類平面,轉化為如下最優化問題:

    linearSVM
    linearSVM

    其中gamma‘為訓練集到超平面的函式距離。但是,該問題求出的一個超平面可以有很多種(w, b)的表示形式。換句話說,存在無數個(w,b)滿足最優,但是這些(w, b)都表示一個超平面。因此需要加上如下約束:

    linearSVM

    該優化問題等價為如下形式:

    linearSVM
    linearSVM

    但是訓練集合一般都存在一定的噪聲,我們允許超平面將部分的點分類錯誤。加入鬆弛變數e和懲罰因子C, 就得到了最終形式:

    linearSVM
    linearSVM

    那個min優化目標函式就是SVM的風險函式,求解過程就是訓練過程。之後用最優化演算法求解該問題即可,一般使用拉格朗日乘子法,實現的時候SMO演算法求解。

  4. 非線性SVM於核函式

    絕大多數情況下訓練集無法線性可分,這個時候需要用某種對映把當前的特徵空間對映到高維的特徵空間中,在新特徵空間中就線性可分。

    核函式定義:

    設X是原特徵空間,H是新的高維或無限維的特徵空間,若存在一個從X到H的對映
    
        f(x): X->H
    
    使得對所有x,z屬於X,函式K(x,z)滿足:
    
        K(x,z) = f(x)f(z)  ( 這裡是內積 )
    
    則稱K(x,z) 為對映f的核函式。
    
    注意:核函式不是對映,不同的對映可以有相同的核函式。對於給定的核函式,其對映方式不唯一,我們只知道對映到了高維空間,但是具體對映無法得知。
    

    對映與核函式舉例:

    linearSVM

    linearSVM

    linearSVM

    linearSVM

    f1與f2這兩個從二維到不同維度的對映,有相同的核函式.

    常用的核函式:

    定義在歐式空間中: 多項式核函式、高斯核函式、
    
    歐式空間核離散資料都可以用: 字串核函式(常用於文字資訊分類)
    

2. 實現:

  1. 我的實現

    訓練過程為SMO演算法:

    https://github.com/autoliuweijie/MachineLearning/tree/master/SVM
    
  2. scikit-learn:

    簡單例子:

    >>> from sklearn import svm
    >>> X = [[0, 0], [1, 1]]
    >>> y = [0, 1]
    >>> clf = svm.SVC()
    >>> clf.fit(X, y)  
    SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
        decision_function_shape=None, degree=3, gamma='auto', kernel='rbf',
        max_iter=-1, probability=False, random_state=None, shrinking=True,
        tol=0.001, verbose=False)
    >>> clf.predict([[2., 2.]])
    array([1])
    

    在建立svm.SVC物件時常用的可選引數如下:

    C:為懲罰係數,預設為1.0
    kernel:為核函式,可選值為‘linear’, ‘polynomial’,‘rbf’,‘sigmoid’。也可以自定義核函式,具體參考官方手冊。
    class_weight:當出現unbalance問題時,這個引數可以用來設定類的權重。
    decision_function_shape='ovo':當進行多分類的時候,選擇多分類的策略,'ovo'表示'one against one', 'ovr'表示'one against rest'
    更多引數請看官方指南:http://scikit-learn.org/stable/modules/svm.html#svm
    

    如果想檢視支援向量是哪些:

    >>> # get support vectors
    >>> clf.support_vectors_
    array([[ 0.,  0.],
           [ 1.,  1.]])
    >>> # get indices of support vectors
    >>> clf.support_ 
    array([0, 1]...)
    >>> # get number of support vectors for each class
    >>> clf.n_support_ 
    array([1, 1]...)
    

    SVM還可以用與迴歸:

    >>> from sklearn import svm
    >>> X = [[0, 0], [2, 2]]
    >>> y = [0.5, 2.5]
    >>> clf = svm.SVR()
    >>> clf.fit(X, y) 
    SVR(C=1.0, cache_size=200, coef0=0.0, degree=3, epsilon=0.1, gamma='auto',
        kernel='rbf', max_iter=-1, shrinking=True, tol=0.001, verbose=False)
    >>> clf.predict([[1, 1]])
    array([ 1.5])
    

參考:

[1]《統計學習方法》 李航 2012年3月第一版
[2]《機器學習實戰》 Peter Harrington