Scikit-learn 支持向量機算法庫總結與簡單實踐

        前兩篇我們簡單的探討了SVM的原理,趁熱我們來進行一些簡單實踐操作。磨刀不誤砍柴工,先來認識下scikit-learn中集成的SVM算法庫。scikit-learn中SVM的算法庫分爲兩類,一類是分類的算法庫,包括SVC, NuSVC,和LinearSVC 3個類。另一類是迴歸算法庫,包括SVR, NuSVR,和LinearSVR 3個類。本篇我們先探討下SVM分類算法庫的使用。

1)scikit-learn SVM分類庫概述
        SVM分類算法庫,包括SVC, NuSVC,和LinearSVC 3個類。SVC是基於libsvm實現,支持各種核函數,訓練時間複雜度爲O(m2×n)O(m3×n)O(m^2\times n)-O(m^3\times n),當樣本量特別大時訓練比較費時間;LinearSVC是基於liblinear實現,支持損失函數和正則的選擇,只能處理線性可分問題,訓練時間複雜度爲O(m×n)O(m\times n),訓練速度比SVC要快很多,特別在樣本量特別大的時候;NuSVC和SVC非常相似,只是NuSVC可以通過超參數Nu控制支持向量的百分比,使用的場景非常少,我們就不做討論了。

2)LinearSVC常用參數
        LinearSVC類官方API:class sklearn.svm.LinearSVC(penalty=’l2’, loss=’squared_hinge’, dual=True, tol=0.0001, C=1.0, multi_class=’ovr’, fit_intercept=True, intercept_scaling=1, class_weight=None, verbose=0, random_state=None, max_iter=1000)[source]。下面介紹LinearSVC中我們經常會調整的一些參數:

  • C,懲罰係數,默認爲1
            該參數就是我們在第一篇SVM中講到的軟間隔分類,用來權衡目標函數和鬆弛因子的超參數λ\lambda。C值越大,支持向量的間隔越小,對錯誤的樣本容忍度越小,泛化能力越小,因此當模型出現過擬合時,可以適當的降低C值。C值一般使用交叉驗證方式進行選擇。

  • loss,損失函數參數,默認爲‘squared_hinge’
            LinearSVC獨有,可以選擇‘squared_hinge’或者 ‘hinge’。‘hinge’損失,即爲第一篇SVM中講到的hinge損失,‘squared_hinge’爲hinge損失的平方。通常我們會使用‘hinge’。

  • penalty,正則參數,默認l2l2正則
            LinearSVC獨有,可以選擇l1‘l1’或者l2‘l2’。如果我們需要產生稀疏化的係數,可以選L1L1正則化。通常,保持默認設置。

  • dual,是否對偶優化參數,默認爲True
            LinearSVC獨有,優化目標函數是以原始形式還是採用拉格朗日對偶形式。當樣本量比特徵數多,此時採用對偶形式計算量較大,推薦dual設置爲False。通常,將dual設置成False。

  • class_weight, 樣本權重參數,默認爲None
            當樣本存在不平衡的情況下,需要設置該參數。 這裏可以自己指定各個樣本的權重,或者用‘balanced’,如果使用‘balanced’ ,則算法會自己計算權重,樣本量少的類別所對應的樣本權重會高。

  • multi_class,多分類決策參數,默認’ovr’
            LinearSVC獨有,可以選擇 ‘ovr’ 或者 ‘crammer_singer’ 。'ovr’的分類原則是將待分類中的某一類當作正類,其他全部歸爲負類,分別求得到每個類別作爲正類時的概率,取概率最高的那個類別爲最後的分類結果;‘crammer_singer’ 是優化所有類別的聯合目標,準確性提升不明顯,但計算量提升較高。通常,保持默認設置。

3)SVC常用參數
        SVC類官方API:class sklearn.svm.SVC(C=1.0, kernel=’rbf’, degree=3, gamma=’auto_deprecated’, coef0=0.0, shrinking=True, probability=False, tol=0.001, cache_size=200, class_weight=None, verbose=False, max_iter=-1, decision_function_shape=’ovr’, random_state=None)[source]

  • kernel,核函數參數,默認值爲‘rbf’
    該參數是爲算法指定核函數的類型,SVC獨有參數。可選的核函數有:
                   linear核函數K(xi,xj)=xixjK(x_i,x_j)=x_i\cdot x_j'
                  poly核函數K(xi,xj)=(γxixj+c)dK(x_i,x_j)=(\gamma x_i\cdot x_j'+c)^d
                  rbf核函數K(xi,xj)=exp(γxixj2)K(x_i,x_j)=exp(-\gamma ||x_i-x_j ||^2)
                  Sigmoid核函數K(xi,xj)=tanh(γxixj+c)K(x_i,x_j)=tanh(\gamma x_i\cdot x_j +c)
    ‘precomputed’選項,需要計算出所有的訓練集和測試集的樣本的核矩陣,K(x,z)直接在覈矩陣中找對應的位置的值,矩陣大小爲(n,n)(n,n)。核函數的選擇,需要結合實際經驗和數據情況。

  • C,懲罰係數,默認爲1
    同LinearSVC參數C

  • gamma,核函數參數,默認爲‘auto_deprecated’
    SVC獨有參數,核函數爲‘rbf’, ‘poly’ and ‘sigmoid’才需要調整該參數,分別對應核函數公式中的γ\gamma。當取參數‘auto_deprecated’,γ=1nfeatures\gamma =\frac{1}{n_{features}}γ\gamma的作用和參數C類似,當模型出現過擬合時,減小γ值,當模型欠擬合,增大γ值。通常情況下,使用交叉驗證的方式選擇合適的γ\gamma值。

  • degree,核函數參數,默認爲3
    SVC獨有參數,當核函數爲’poly’時,該參數纔有效,對應多項式核函數的階數dd,默認爲3階多項式。階數越高,模型越容易出現過擬合。通常情況下,使用交叉驗證的方式選擇合適的dd值。

  • coef0,核函數參數,默認爲0
    SVC獨有參數,當核函數爲’poly’,'Sigmoid’時,該參數纔有效,對應核函數中的截距項cc。通常情況下,cc值保持默認設置。

  • decision_function_shape,分類決策參數,默認爲’ovr’
    SVC獨有參數,但和LinearSVC中的參數multi_class類似。可以選擇 ‘ovo’, ‘ovr’,默認‘ovr’。
    OvR(one ve rest)是指,無論多少分類,都看做二分類。即爲,對於第K類的分類決策,把所有第K類的樣本作爲正例,其他所有樣本都作爲負例,然後在上面做二元分類,得到第K類的分類結果。其他類以此類推分別得到屬於T個類別的概率,選擇概率最高的作爲最終的分類結果。
    OvO(one-vs-one)則是每次在所有的T類樣本里面選擇兩類樣T1類和T2類出來,把T1和T2樣本放在一起做二分類,選擇概率最高的作爲最終的分類結果,一共需要T(T-1)/2次分類。
    因此,OvR相對簡單,通常分類效果相對略差。而OvO分類相對精確,但分類速度沒有OvR快。在做多分類任務時,一般將該參數設置爲‘ovo’。

  • class_weight, 樣本權重參數,默認爲None
    同LinearSVC參數class_weight

  • cache_size,緩存大小參數,默認200M
    SVC獨有參數,設置模型緩存大小參數。通常在樣本量很大時,緩存大小會影響訓練速度,如果機器內存大,可以設置512MB甚至1024MB。

  • probability,是否輸出概率,默認爲‘False’
    SVC獨有參數,模型結果是否輸出概率,使用的sigmoid函數計算樣本概率。

4)SVM分類庫經驗總結

  • 我們先試着使用線性核(LinearSVC比SVC(kernel=‘linear’),快得多),特別是在特徵很多或者數據集很大的情況。假如數據集不是很大,你也可以試着使用高斯RBF核,通常情況下表現都不錯。如果你有空閒的時間和計算能力,你還可以使用交叉驗證和網格搜索來試驗其他的核函數,特別是有專門用於你的訓練集數據結構的核函數。
  • SVM算法對不同量綱的變量非常敏感,在進行模型訓練之前,需要做標準化處理(使用Scikit-Learn的StandardScaler)。
  • LinearSVC中,或者使用線性核的SVC,使用C=1或者較大的C,可能會導致模型無法收斂,陷入死循環。
  • SVC不適合處理過大的數據。
  • 核函數調參,使用grid_search和交叉驗證選擇最優超參數C,λC,\lambda

5)SVM算法庫調參實踐
        爲了更好的理解LinearSVC和SVC的超參數對模型的作用,我們下面結合一個具體的案例直觀的感受超參數C,λC,\lambda對分類效果的影響,希望對大家在調整SVM算法庫參數有一定的幫助。代碼和數據已上傳到我的Github

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

if __name__ == "__main__":
    data = pd.read_csv('bipartition.txt', sep='\t', header=None)
    x, y = data[[0, 1]], data[2]

    # 分類器
    clf_param = (('linear', 0.1), ('linear', 0.5), ('linear', 1), ('linear', 2),
                ('rbf', 1, 0.1), ('rbf', 1, 1), ('rbf', 1, 10), ('rbf', 1, 100),
                ('rbf', 5, 0.1), ('rbf', 5, 1), ('rbf', 5, 10), ('rbf', 5, 100))

    x1_min, x2_min = np.min(x, axis=0)
    x1_max, x2_max = np.max(x, axis=0)
    x1, x2 = np.mgrid[x1_min:x1_max:200j, x2_min:x2_max:200j]
    grid_test = np.stack((x1.flat, x2.flat), axis=1)

    cm_light = mpl.colors.ListedColormap(['#77E0A0', '#FFA0A0'])
    cm_dark = mpl.colors.ListedColormap(['g', 'r'])
    mpl.rcParams['font.sans-serif'] = ['SimHei']
    mpl.rcParams['axes.unicode_minus'] = False
    plt.figure(figsize=(13, 9), facecolor='w')
    for i, param in enumerate(clf_param):
        clf = svm.SVC(C=param[1], kernel=param[0])
        if param[0] == 'rbf':
            clf.gamma = param[2]
            title = '高斯核,C=%.1f,$\gamma$ =%.1f' % (param[1], param[2])
        else:
            title = '線性核,C=%.2f' % param[1]

        clf.fit(x, y)
        y_hat = clf.predict(x)
        print('準確率:', accuracy_score(y, y_hat))

        # 畫圖
        print(title)
        print('支撐向量的數目:', clf.n_support_)
        print('支撐向量的係數:', clf.dual_coef_)
        print('支撐向量:', clf.support_)
        plt.subplot(3, 4, i+1)
        grid_hat = clf.predict(grid_test)       # 預測分類值
        grid_hat = grid_hat.reshape(x1.shape)  # 使之與輸入的形狀相同
        plt.pcolormesh(x1, x2, grid_hat, cmap=cm_light, alpha=0.8)
        plt.scatter(x[0], x[1], c=y, edgecolors='k', s=40, cmap=cm_dark)      # 樣本的顯示
        plt.scatter(x.loc[clf.support_, 0], x.loc[clf.support_, 1], edgecolors='k', facecolors='none', s=100, marker='o')   # 支撐向量
        z = clf.decision_function(grid_test)
        print('clf.decision_function(x) = ', clf.decision_function(x))
        print('clf.predict(x) = ', clf.predict(x))
        z = z.reshape(x1.shape)
        plt.contour(x1, x2, z, colors=list('kbrbk'), linestyles=['--', '--', '-', '--', '--'],
                    linewidths=[1, 0.5, 1.5, 0.5, 1], levels=[-1, -0.5, 0, 0.5, 1])
        plt.xlim(x1_min, x1_max)
        plt.ylim(x2_min, x2_max)
        plt.title(title, fontsize=12)
    plt.suptitle('SVM不同參數的分類', fontsize=16)
    plt.tight_layout(1.4)
    plt.subplots_adjust(top=0.92)
    plt.show()

分類效果圖如下:
不同超參數的SVM算法分類效果圖

(歡迎轉載,轉載請註明出處)

上一篇:支持向量機(Support Vector Machine)原理總結(二)
下一篇:決策樹(Decision Tree)算法原理總結(一)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章