【Scikit-Learn 中文文檔】支持向量機 - 監督學習 - 用戶指南 | ApacheCN

中文文檔: http://sklearn.apachecn.org/cn/0.19.0/modules/svm.html

英文文檔: http://sklearn.apachecn.org/en/0.19.0/modules/svm.html

官方文檔: http://scikit-learn.org/0.19/

GitHub: https://github.com/apachecn/scikit-learn-doc-zh(覺得不錯麻煩給個 Star,我們一直在努力)

貢獻者: https://github.com/apachecn/scikit-learn-doc-zh#貢獻者

關於我們: http://www.apachecn.org/organization/209.html




1.4. 支持向量機

支持向量機 (SVMs) 可用於以下監督學習算法 分類迴歸 and 異常檢測.

支持向量機的優勢在於:

  • 在高維空間中非常高效.
  • 即使在數據維度比樣本數量大的情況下仍然有效.
  • 在決策函數(稱爲支持向量)中使用訓練集的子集,因此它也是高效利用內存的.
  • 通用性: 不同的核函數 核函數 與特定的決策函數一一對應.常見的 kernel 已

經提供,也可以指定定製的內核.

支持向量機的缺點包括:

  • 如果特徵數量比樣本數量大得多,在選擇核函數 核函數 時要避免過擬合,

而且正則化項是非常重要的.

  • 支持向量機不直接提供概率估計,這些都是使用昂貴的五次交叉驗算計算的. (詳情見 Scores and probabilities, 在下文中).

在 scikit-learn 中,支持向量機提供 dense(numpy.ndarray ,可以通過 numpy.asarray 進行轉換) 和 sparse (任何 scipy.sparse) 樣例向量作爲輸出.然而,要使用支持向量機來對 sparse 數據作預測,它必須已經擬合這樣的數據.使用 C 代碼的 numpy.ndarray(dense) 或者帶有 dtype=float64 的 scipy.sparse.csr_matrix (sparse) 來優化性能.

1.4.1. 分類

SVCNuSVC 和 LinearSVC 能在數據集中實現多元分類.

../_images/sphx_glr_plot_iris_0012.png

SVC 和 NuSVC 是相似的方法, 但是接受稍許不同的參數設置並且有不同的數學方程(在這部分看 數學公式). 另一方面, LinearSVC 是另一個實現線性核函數的支持向量分類. 記住 LinearSVC 不接受關鍵詞 kernel, 因爲它被假設爲線性的. 它也缺少一些 SVC 和 NuSVC 的成員(members) 比如 support_ .

和其他分類器一樣, SVCNuSVC 和 LinearSVC 將兩個數組作爲輸入: [n_samples, n_features] 大小的數組 X 作爲訓練樣本, [n_samples] 大小的數組 y 作爲類別標籤(字符串或者整數):

>>>
>>> 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='ovr', 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])

SVMs 決策函數取決於訓練集的一些子集, 稱作支持向量. 這些支持向量的部分特性可以在 support_vectors_support_ 和 n_support 找到:

>>>
>>> # 獲得支持向量
>>> clf.support_vectors_
array([[ 0.,  0.],
       [ 1.,  1.]])
>>> # 獲得支持向量的索引get indices of support vectors
>>> clf.support_ 
array([0, 1]...)
>>> # 爲每一個類別獲得支持向量的數量
>>> clf.n_support_ 
array([1, 1]...)

1.4.1.1. 多元分類

SVC 和 NuSVC 爲多元分類實現了 “one-against-one” 的方法 (Knerr et al., 1990) 如果 n_class 是類別的數量, 那麼 n_class * (n_class - 1) / 2 分類器被重構, 而且每一個從兩個類別中訓練數據. 爲了給其他分類器提供一致的交互, decision_function_shape 選項允許聚合 “one-against-one” 分類器的結果成 (n_samples, n_classes) 的大小到決策函數:

>>>
>>> X = [[0], [1], [2], [3]]
>>> Y = [0, 1, 2, 3]
>>> clf = svm.SVC(decision_function_shape='ovo')
>>> clf.fit(X, Y) 
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
    decision_function_shape='ovo', degree=3, gamma='auto', kernel='rbf',
    max_iter=-1, probability=False, random_state=None, shrinking=True,
    tol=0.001, verbose=False)
>>> dec = clf.decision_function([[1]])
>>> dec.shape[1] # 4 classes: 4*3/2 = 6
6
>>> clf.decision_function_shape = "ovr"
>>> dec = clf.decision_function([[1]])
>>> dec.shape[1] # 4 classes
4

另一方面, LinearSVC 實現 “one-vs-the-rest” 多類別策略, 從而訓練 n 類別的模型. 如果只有兩類, 只訓練一個模型.:

>>>
>>> lin_clf = svm.LinearSVC()
>>> lin_clf.fit(X, Y) 
LinearSVC(C=1.0, class_weight=None, dual=True, fit_intercept=True,
     intercept_scaling=1, loss='squared_hinge', max_iter=1000,
     multi_class='ovr', penalty='l2', random_state=None, tol=0.0001,
     verbose=0)
>>> dec = lin_clf.decision_function([[1]])
>>> dec.shape[1]
4

參見 數學公式 查看決策函數的完整描述.

記住 LinearSVC 也實現了可選擇的多類別策略, 通過使用選項 multi_class='crammer_singer', 所謂的多元 SVM 由 Crammer 和 Singer 明確表達. 這個方法是一致的, 對於 one-vs-rest 是不正確的. 實際上, one-vs-rest 分類通常受到青睞, 因爲結果大多數是相似的, 但是運行時間卻顯著減少.

對於 “one-vs-rest” LinearSVC, 屬性 coef_ 和 intercept_ 分別具有 [n_class, n_features] 和 [n_class] 尺寸. 係數的每一行符合 n_class 的許多 one-vs-rest 分類器之一, 並且就以這一類的順序與攔截器(intercepts)相似.

至於 one-vs-one SVC, 屬性特徵的佈局(layout)有少多些複雜. 考慮到有一種線性核函數, coef_ 和 intercept_ 的佈局(layout)與上文描述成 LinearSVC 相似, 除了 coef_ 的形狀 [n_class * (n_class - 1) / 2, n_features], 與許多二元的分類器相似. 0到n的類別順序是 “0 vs 1”, “0 vs 2” , … “0 vs n”, “1 vs 2”, “1 vs 3”, “1 vs n”, … “n-1 vs n”.

dual_coef_ 的 shape 是 [n_class-1, n_SV], 這個結構有些難以理解. 對應於支持向量的列與 n_class * (n_class - 1) / 2“one-vs-one” 分類器相關. 每一個支持向量用於 n_class - 1 分類器中.對於這些分類器,每一行的 n_class - 1 條目對應於對偶係數(dual coefficients).

通過這個例子更容易說明:

考慮一個三類的問題,類0有三個支持向量 v^{0}_0, v^{1}_0, v^{2}_0 而類 1 和 2 分別有 如下兩個支持向量 v^{0}_1, v^{1}_1 and v^{0}_2, v^{1}_2.對於每個支持 向量 v^{j}_i, 有兩個對偶係數.在類別 i 和 k \alpha^{j}_{i,k} 中, 我們將支持向量的係數記錄爲 v^{j}_i 那麼 dual_coef_ 可以表示爲:

\alpha^{0}_{0,1} \alpha^{0}_{0,2} Coefficients for SVs of class 0
\alpha^{1}_{0,1} \alpha^{1}_{0,2}
\alpha^{2}_{0,1} \alpha^{2}_{0,2}
\alpha^{0}_{1,0} \alpha^{0}_{1,2} Coefficients for SVs of class 1
\alpha^{1}_{1,0} \alpha^{1}_{1,2}
\alpha^{0}_{2,0} \alpha^{0}_{2,1} Coefficients for SVs of class 2
\alpha^{1}_{2,0} \alpha^{1}_{2,1}

1.4.1.2. 得分和概率

SVC 方法的 decision_function 給每一個樣例每一個類別分值(scores)(或者在一個二元類中每一個樣例一個分值). 當構造器(constructor)選項 probability 設置爲 True 的時候, 類成員可能性評估開啓.(來自 predict_proba 和 predict_log_proba 方法) 在二元分類中,概率使用 Platt scaling 進行標準化: 在 SVM 分數上的邏輯迴歸,在訓練集上用額外的交叉驗證來擬合.在多類情況下,這可以擴展爲 per Wu et al.(2004)

不用說,對於大數據集來說,在 Platt scaling 中進行交叉驗證是一項昂貴的操作. 另外,可能性預測可能與 scores 不一致,因爲 scores 的 “argmax” 可能不是可能性的 argmax. (例如,在二元分類中,一個樣本可能被標記爲一個有可能性的類 predict <½ according to predict_proba.) Platt 的方法也有理論問題. 如果 confidence scores 必要,但是這些沒必要是可能性, 那麼建議設置 probability=False 並使用 decision_function 而不是 predict_proba.

1.4.1.3. 非均衡問題

這個問題期望給予某一類或某個別樣例能使用的關鍵詞 class_weight 和 sample_weight 提高權重(importance).

SVC (而不是 NuSVC) 在 fit 方法中生成了一個關鍵詞 class_weight. 它是形如 {class_label : value} 的字典, value 是浮點數大於 0 的值, 把類 class_label 的參數 C 設置爲 C * value.

../_images/sphx_glr_plot_separating_hyperplane_unbalanced_0011.png

SVCNuSVCSVRNuSVR 和 OneClassSVM 在 fit 方法中通過關鍵詞 sample_weight 爲單一樣例實現權重weights.與 class_weight 相似, 這些把第i個樣例的參數 C 換成 C * sample_weight[i].

../_images/sphx_glr_plot_weighted_samples_0011.png

1.4.2. 迴歸

支持向量分類的方法可以被擴展用作解決迴歸問題. 這個方法被稱作支持向量迴歸.

支持向量分類生成的模型(如前描述)只依賴於訓練集的子集,因爲構建模型的 cost function 不在乎邊緣之外的訓練點. 類似的,支持向量迴歸生成的模型只依賴於訓練集的子集, 因爲構建模型的 cost function 忽略任何接近於模型預測的訓練數據.

支持向量分類有三種不同的實現形式: SVRNuSVR 和 LinearSVR. 在只考慮線性核的情況下, LinearSVR 比 SVR 提供一個更快的實現形式, 然而比起 SVR 和 LinearSVRNuSVR 實現一個稍微不同的構思(formulation).細節參見 實現細節.

與分類的類別一樣, fit方法會調用參數向量 X, y, 只在 y 是浮點數而不是整數型.:

>>>
>>> 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.4.3. 密度估計, 異常(novelty)檢測

但類別的 SVM 用於異常檢測, 即給予一個樣例集, 它會檢測這個樣例集的 soft boundary 以便給新的數據點分類, 看它是否屬於這個樣例集. 生成的類稱作 OneClassSVM.

這種情況下, 因爲它屬於非監督學習的一類, 沒有類標籤, fit 方法只會考慮輸入數組X.

在章節 新奇和離羣點檢測 查看這個應用的更多細節.

../_images/sphx_glr_plot_oneclass_0011.png

1.4.4. 複雜度

支持向量機是個強大的工具,不過它的計算和存儲空間要求也會隨着要訓練向量的數目增加而快速增加。 SVM的核心是一個二次規劃問題(Quadratic Programming, QP),是將支持向量和訓練數據的其餘部分分離開來。 在實踐中(數據集相關),會根據 libsvm 的緩存有多效,在 O(n_{features} \times n_{samples}^2) 和 O(n_{features} \times n_{samples}^3) 之間基於 libsvm 的縮放操作纔會調用這個 QP 解析器。 如果數據是非常稀疏,那 n_{features} 就用樣本向量中非零特徵的平均數量去替換。

另外請注意,在線性情況下,由 liblinear 操作的 LinearSVC 算法要比由它的 libsvm 對應的 SVC 更爲高效,並且它幾乎可以線性縮放到數百萬樣本或者特徵。

1.4.5. 使用訣竅

  • 避免數據複製: 對於 SVC, SVR, NuSVC 和 NuSVR, 如果數據是通過某些方法而不是用 C 有序的連續雙精度,那它先會調用底層的 C 命令再複製。 您可以通過檢查它的 flags 屬性,來確定給定的 numpy 數組是不是 C 連續的。

    對於 LinearSVC (和 LogisticRegression) 的任何輸入,都會以 numpy 數組形式,被複制和轉換爲 用 liblinear 內部稀疏數據去表達(雙精度浮點型 float 和非零部分的 int32 索引)。 如果您想要一個適合大規模的線性分類器,又不打算複製一個密集的 C-contiguous 雙精度 numpy 數組作爲輸入, 那我們建議您去使用 SGDClassifier 類作爲替代。目標函數可以配置爲和 LinearSVC 模型差不多相同的。

  • 內核的緩存大小: 在大規模問題上,對於 SVCSVRnuSVC 和 NuSVR, 內核緩存的大小會特別影響到運行時間。如果您有足夠可用的 RAM,不妨把它的 緩存大小 設得比默認的 200(MB) 要高,例如爲 500(MB) 或者 1000(MB)。

  • 懲罰係數C的設置:在合理的情況下, C 的默認選擇爲 1 。如果您有很多混雜的觀察數據, 您應該要去調小它。 C 越小,就能更好地去正規化估計。

  • 支持向量機算法本身不是用來擴大不變性,所以 我們強烈建議您去擴大數據量. 舉個例子,對於輸入向量 X, 規整它的每個數值範圍爲 [0, 1] 或 [-1, +1] ,或者標準化它的爲均值爲0方差爲1的數據分佈。請注意, 相同的縮放標準必須要應用到所有的測試向量,從而獲得有意義的結果。 請參考章節 預處理數據 ,那裏會提供到更多關於縮放和規整。

  • 在 NuSVC/OneClassSVM/NuSVR 內的參數 nu , 近似是訓練誤差和支持向量的比值。

  • 在 SVC, ,如果分類器的數據不均衡(就是說,很多正例很少負例),設置 class_weight='balanced' 與/或嘗試不同的懲罰係數 C 。

  • 在擬合模型時,底層 LinearSVC 操作使用了隨機數生成器去選擇特徵。 所以不要感到意外,對於相同的數據輸入,也會略有不同的輸出結果。如果這個發生了, 嘗試用更小的 tol 參數。

  • 使用由 LinearSVC(loss='l2', penalty='l1', dual=False) 提供的 L1 懲罰去產生稀疏解,也就是說,特徵權重的子集不同於零,這樣做有助於決策函數。 隨着增加 C 會產生一個更復雜的模型(要做更多的特徵選擇)。可以使用 l1_min_c 去計算 C 的數值,去產生一個”null” 模型(所有的權重等於零)。

1.4.6. 核函數

核函數 可以是以下任何形式::

  • 線性: \langle x, x'\rangle.
  • 多項式: (\gamma \langle x, x'\rangle + r)^dd 是關鍵詞 degreer 指定 coef0
  • rbf: \exp(-\gamma \|x-x'\|^2)\gamma 是關鍵詞 gamma, 必須大於 0。
  • sigmoid (\tanh(\gamma \langle x,x'\rangle + r)), 其中 r 指定 coef0

初始化時,不同內核由不同的函數名調用:

>>>
>>> linear_svc = svm.SVC(kernel='linear')
>>> linear_svc.kernel
'linear'
>>> rbf_svc = svm.SVC(kernel='rbf')
>>> rbf_svc.kernel
'rbf'

1.4.6.1. 自定義核

您可以自定義自己的核,通過使用python函數作爲內核或者通過預計算 Gram 矩陣。

自定義內核的分類器和別的分類器一樣,除了下面這幾點:

  • 空間 support_vectors_ 現在不是空的, 只有支持向量的索引被存儲在 support_
  • 請把 fit() 模型中的第一個參數的引用(不是副本)存儲爲將來的引用。 如果在 fit() 和 predict() 之間有數組發生改變,您將會碰到意料外的結果。

1.4.6.1.1. 使用 python 函數作爲內核

在構造時,您同樣可以通過一個函數傳遞到關鍵詞 kernel ,來使用您自己定義的內核。

您的內核必須要以兩個矩陣作爲參數,大小分別是 (n_samples_1, n_features)(n_samples_2, n_features) 和返回一個內核矩陣,shape 是 (n_samples_1, n_samples_2).

以下代碼定義一個線性核,和構造一個使用該內核的分類器例子:

>>>
>>> import numpy as np
>>> from sklearn import svm
>>> def my_kernel(X, Y):
...     return np.dot(X, Y.T)
...
>>> clf = svm.SVC(kernel=my_kernel)

1.4.6.1.2. 使用 Gram 矩陣

在適應算法中,設置 kernel='precomputed' 和把 X 替換爲 Gram 矩陣。 此時,必須要提供在 所有 訓練矢量和測試矢量中的內核值。

>>>
>>> import numpy as np
>>> from sklearn import svm
>>> X = np.array([[0, 0], [1, 1]])
>>> y = [0, 1]
>>> clf = svm.SVC(kernel='precomputed')
>>> # 線性內核計算
>>> gram = np.dot(X, X.T)
>>> clf.fit(gram, y) 
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
    decision_function_shape='ovr', degree=3, gamma='auto',
    kernel='precomputed', max_iter=-1, probability=False,
    random_state=None, shrinking=True, tol=0.001, verbose=False)
>>> # 預測訓練樣本
>>> clf.predict(gram)
array([0, 1])

1.4.6.1.3. RBF 內核參數

當用 徑向基 (RBF) 內核去訓練 SVM,有兩個參數必須要去考慮: C 懲罰係數和 gamma 。參數 C , 通用在所有 SVM 內核,與決策表面的簡單性相抗衡,可以對訓練樣本的誤分類進行有價轉換。 較小的 C 會使決策表面更平滑,同時較高的 C 旨在正確地分類所有訓練樣本。 Gamma 定義了單一 訓練樣本能起到多大的影響。較大的 gamma 會更讓其他樣本受到影響。

選擇合適的 C 和 gamma ,對SVM的性能起到很關鍵的作用。建議一點是 使用  sklearn.model_selection.GridSearchCV與 C 和 gamma 相隔 成倍差距從而選擇到好的數值。

1.4.7. 數學公式

支持向量機在高維度或無窮維度空間中,構建一個超平面或者一系列的超平面,可以用於分類、迴歸或者別的任務。 直觀地看,藉助超平面去實現一個好的分割, 能在任意類別中使最爲接近的訓練數據點具有最大的間隔距離(即所 謂的函數餘量),這樣做是因爲通常更大的餘量能有更低的分類器泛化誤差。

../_images/sphx_glr_plot_separating_hyperplane_0011.png

1.4.7.1. SVC

在兩類中,給定訓練向量 x_i \in \mathbb{R}^p, i=1,…, n, 和一個向量 y \in \{1, -1\}^n, SVC能解決 如下主要問題:

\min_ {w, b, \zeta} \frac{1}{2} w^T w + C \sum_{i=1}^{n} \zeta_i\textrm {subject to } & y_i (w^T \phi (x_i) + b) \geq 1 - \zeta_i,\\& \zeta_i \geq 0, i=1, ..., n

它的對偶是

\min_{\alpha} \frac{1}{2} \alpha^T Q \alpha - e^T \alpha\textrm {subject to } & y^T \alpha = 0\\& 0 \leq \alpha_i \leq C, i=1, ..., n

其中 e 是所有的向量, C > 0 是上界,Q 是一個 n 由 n 個半正定矩陣, 而 Q_{ij} \equiv y_i y_j K(x_i, x_j) ,其中 K(x_i, x_j) = \phi (x_i)^T \phi (x_j) 是內核。所以訓練向量是通過函數 \phi,間接反映到一個更高維度的(無窮的)空間。

決策函數是:

\operatorname{sgn}(\sum_{i=1}^n y_i \alpha_i K(x_i, x) + \rho)

注意:

雖然這些SVM模型是從 libsvm 和 liblinear 中派生出來,使用了 C 作爲調整參數,但是大多數的 攻擊使用了 alpha。兩個模型的正則化量之間的精確等價,取決於模型優化的準確目標函數。舉 個例子,當使用的估計器是 sklearn.linear_model.Ridge 做迴歸時,他們之間的相關性是 C = \frac{1}{alpha}

這些參數能通過成員 dual_coef_、 support_vectors_ 、 intercept_ 去訪問,這些成員分別控制了輸出 y_i \alpha_i、支持向量和無關項 \rho :

參考文獻:

1.4.7.2. NuSVC

我們引入一個新的參數 \nu 來控制支持向量的數量和訓練誤差。參數 \nu \in (0,1] 是訓練誤差分數的上限和支持向量分數的下限。

可以看出, \nu-SVC 公式是 C-SVC 的再參數化,所以數學上是等效的。

1.4.7.3. SVR

給定訓練向量 x_i \in \mathbb{R}^p, i=1,…, n,向量 y \in \mathbb{R}^n \varepsilon-SVR 能解決以下的主要問題:

\min_ {w, b, \zeta, \zeta^*} \frac{1}{2} w^T w + C \sum_{i=1}^{n} (\zeta_i + \zeta_i^*)\textrm {subject to } & y_i - w^T \phi (x_i) - b \leq \varepsilon + \zeta_i,\\                      & w^T \phi (x_i) + b - y_i \leq \varepsilon + \zeta_i^*,\\                      & \zeta_i, \zeta_i^* \geq 0, i=1, ..., n

它的對偶是

\min_{\alpha, \alpha^*} \frac{1}{2} (\alpha - \alpha^*)^T Q (\alpha - \alpha^*) + \varepsilon e^T (\alpha + \alpha^*) - y^T (\alpha - \alpha^*)\textrm {subject to } & e^T (\alpha - \alpha^*) = 0\\& 0 \leq \alpha_i, \alpha_i^* \leq C, i=1, ..., n

其中 e 是所有的向量, C > 0 是上界,Q 是一個 n 由 n 個半正定矩陣, 而 Q_{ij} \equiv K(x_i, x_j) = \phi (x_i)^T \phi (x_j) 是內核。 所以訓練向量是通過函數 \phi,間接反映到一個更高維度的(無窮的)空間。

決策函數是:

\sum_{i=1}^n (\alpha_i - \alpha_i^*) K(x_i, x) + \rho

這些參數能通過成員 dual_coef_、 support_vectors_ 、 intercept_ 去訪問,這些 成員分別控制了不同的 \alpha_i - \alpha_i^*、支持向量和無關項 \rho

參考文獻:

1.4.8. 實現細節

在底層裏,我們使用 libsvm 和 liblinear 去處理所有的計算。這些庫都使用了 C 和 Cython 去包裝。

參考文獻:

有關實現的描述和使用算法的細節,請參考




中文文檔: http://sklearn.apachecn.org/cn/0.19.0/tutorial/basic/tutorial.html

英文文檔: http://sklearn.apachecn.org/en/0.19.0/tutorial/basic/tutorial.html

官方文檔: http://scikit-learn.org/0.19/

GitHub: https://github.com/apachecn/scikit-learn-doc-zh(覺得不錯麻煩給個 Star,我們一直在努力)

貢獻者: https://github.com/apachecn/scikit-learn-doc-zh#貢獻者

關於我們: http://www.apachecn.org/organization/209.html

有興趣的大佬們也可以和我們一起來維護,持續更新中 。。。

機器學習交流羣: 629470233


發佈了34 篇原創文章 · 獲贊 5 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章