核支持向量機SVM的應用


核支持向量機(kernelized support vector machine)(通常簡稱爲SVM),可以同時用於分類和迴歸,在sklearn中爲SVC和SVR。背後數學比較複雜,可參見《統計學習基礎》。

from sklearn.svm import SVC
svm = SVC(kernel='rbf', C=10, gamma=0.1).fit(X, y)

1. 核技巧

線性模型在低維空間中可能非常受限,因爲線和平面的靈活性有限。有一種方法可以讓線性模型更加靈活,就是添加更多的特徵——舉個例子,添加輸入特徵的交互項或多項式。

向數據表示中添加非線性特徵,可以讓線性模型變得更強大。但是,通常來說我們並不知道要添加哪些特徵,而且添加許多特徵(比如100 維特徵空間所有可能的交互項)的計算開銷可能會很大。

幸運的是,有一種巧妙的數學技巧,讓我們可以在更高維空間中學習分類器,而不用實際計算可能非常大的新的數據表示。這種技巧叫作核技巧(kernel trick),它的原理是直接計算擴展特徵表示中數據點之間的距離(更準確地說是內積),而不用實際對擴展進行計算。

對於支持向量機,將數據映射到更高維空間中有兩種常用的方法:

  1. 多項式核,在一定階數內計算原始特徵所有可能的多項式(比如feature12 * feature2 5);
  2. 徑向基函數(radial basis function,RBF)核,也叫高斯核。高斯核有點難以解釋,因爲它對應無限維的特徵空間。一種對高斯核的解釋是它考慮所有階數的所有可能的多項式,但階數越高,特徵的重要性越小。

2. 理解SVM

在訓練過程中,SVM 學習每個訓練數據點對於表示兩個類別之間的決策邊界的重要性。

通常只有一部分訓練數據點對於定義決策邊界來說很重要:位於類別之間邊界上的那些點。這些點叫作支持向量(support vector),支持向量機正是由此得名。

想要對新樣本點進行預測,需要測量它與每個支持向量之間的距離。分類決策是基於它與支持向量之間的距離以及在訓練過程中學到的支持向量重要性(保存在SVC 的dual_coef_屬性中)來做出的。

數據點之間的距離由高斯核給出:

krbf(x1,x2)=exp(γx1x22)k_{rbf}(x_{1},x_{2})=exp(-\gamma||x_{1}-x_{2}||^{2})

這裏x1x_{1}x2x_{2} 是數據點,x1x2‖x_{1} - x_{2}‖ 表示歐氏距離,γgammaγ(gamma)是控制高斯核寬度的參數。

3. 調參

  1. gamma 參數:控制高斯核的寬度。決定點與點之間“靠近”是指多大的距離。gamma 較小,說明高斯核的半徑較大,許多點都被看作比較靠近。表示決策邊界變化很慢,生成的是複雜度較低的模型,而大的gamma 值則會生成更爲複雜的模型。
  2. C 參數:正則化參數,與線性模型中用到的類似。它限制每個點的重要性(或者更確切地說,每個點的dual_coef_)。與線性模型相同,C 值很小,說明模型非常受限,每個數據點的影響範圍都有限。

4. 應用乳腺癌數據集-分類-RBF核SVM

  1. 導入包與數據集
from sklearn.svm import SVC  # 從svm模塊中導入用於分類的
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
import matplotlib as mpl
import matplotlib.pyplot as plt

cancer = load_breast_cancer()
X_train,X_test,y_train,y_test = train_test_split(cancer.data,cancer.target,random_state=0)
  1. 構建SVM分類器,需顯式指定gamma是’auto’ or ‘scale’
svc = SVC(gamma='auto')   # 構建SVM分類器,需顯式指定gamma是'auto' or 'scale'
svc.fit(X_train,y_train)

print("Accuracy on training set: {:.2f}".format(svc.score(X_train, y_train)))  # 1.0
print("Accuracy on test set: {:.2f}".format(svc.score(X_test, y_test)))  # 0.63

gamma原來默認是auto,gamma = 1 / (n_features)將被棄用。
新版本需要顯式指定’auto’ or ‘scale’。
scale的gamma使用1 / (n_features * X.var())

svc = SVC(gamma='scale')   # 構建SVM分類器,需顯式指定gamma是'auto' or 'scale'
svc.fit(X_train,y_train)

print("Accuracy on training set: {:.2f}".format(svc.score(X_train, y_train)))  # 0.90
print("Accuracy on test set: {:.2f}".format(svc.score(X_test, y_test))) # 0.94

可以看出gamma是auto時模型過擬合,當gamma是scale時模型精度提高,這可能跟數據縮放有關。
分析:第一種的模型測試集精度原小於訓練集,存在嚴重過擬合。由於SVM對參數設定和數據縮放十分敏感,要求所有特徵有相似的變化範圍,所以需要數據預處理。

  1. 查看數據集的每個特徵的取值範圍
# 查看一個二維結構每行或每列的最小值,沿0軸向即沿行的方向,就是列的最小值
X_train.min(axis=0)  
## 畫圖表示最值範圍
plt.plot(X_train.min(axis=0),'o',label='min')
plt.plot(X_train.max(axis=0),'^',label='max')
plt.xlabel('Feature index')
plt.ylabel('Feature magnitude')
plt.legend()
plt.yscale('log')  # 設置y軸尺度爲對數座標

在這裏插入圖片描述
可以看出,不同的特徵具有不同的數量級,對核SVM有很大影響。

方法一:縮放每個特徵,使其都在同一範圍,常用歸一化到0-1之間,可用函數MinMaxSacler。

這裏先用人工實現歸一化。
原理:(每個特徵的數據-最小值)/該特徵的極差範圍,即小範圍/大範圍,所以每個數據都在0-1之間

## 對訓練集歸一化
min_on_training = X_train.min(axis=0)  # 計算各特徵的最小值,返回array
max_on_training = X_train.max(axis=0)
range_on_training = max_on_training-min_on_training  # 計算各特徵的極差
r2 = X_train.ptp(axis=0)  # numpy求極差

# (每個特徵的數據-最小值)/該特徵的極差範圍,即小範圍/大範圍,所以每個數據都在0-1之間
X_train_scaled = (X_train - min_on_training)/r2  # 不同維度之間算術運算,可能是廣播機制
print('min for each feature:\n{}'.format(X_train_scaled.min(axis=0)))
print('max for each feature:\n{}'.format(X_train_scaled.max(axis=0)))

在這裏插入圖片描述

## 對測試集歸一化:利用訓練集的最小值和範圍對測試集做相同的變換(詳見第3章)??爲什麼使用訓練集的?
X_test_scaled = (X_test - min_on_training) / range_on_training
print('min for each feature:\n{}'.format(X_test_scaled.min(axis=0)))
print('max for each feature:\n{}'.format(X_test_scaled.max(axis=0)))

在這裏插入圖片描述
歸一化後再使用SVM試試

svc = SVC(gamma='auto')   
svc.fit(X_train_scaled,y_train)  # y不需要變

print("Accuracy on training set: {:.3f}".format(svc.score(X_train_scaled, y_train)))  # 0.948
print("Accuracy on test set: {:.3f}".format(svc.score(X_test_scaled, y_test)))  # 0.951

可以看出,數據縮放後測試集精度大幅提高,並且現在比訓練集精度還高,說明模型處於欠擬合的狀態。可以增大C或gamma來擬合更復雜的模型。

增大C:

# 增大C=1000,顯著改進了模型
svc = SVC(gamma='auto',C=1000)   # 構建SVM分類器,需顯式指定gamma是'auto' or 'scale'
svc.fit(X_train_scaled,y_train)  # y不需要變

print("Accuracy on training set: {:.3f}".format(svc.score(X_train_scaled, y_train)))  # 0.988
print("Accuracy on test set: {:.3f}".format(svc.score(X_test_scaled, y_test)))  # 0.972

5. 優缺點與參數

  1. 優點:非常強大的模型,在低維數據和高維數據(即很少特徵和很多特徵)上表現都很好
  2. 缺點:不適合大數據,即過萬的樣本量,表現在運行時間和內存方面;
    缺點2:對數據預處理和調參敏感,數據預處理和模型調參需要非常小心。這也是爲什麼如今很多應用中用的都是基於樹的模型,比如隨機森林或梯度提升(需要很少的預處理,甚至不需要預處理)。
    缺點3:模型很難檢查,難以理解模型預測的原因也難以解釋。
  3. 關鍵參數:正則化參數C,核的選擇,核相關的參數,比如RBF需要的gamma(高斯核寬度的倒數)。gamma 和C 控制的都是模型複雜度,較大的值都對應更爲複雜的模型。因此,這兩個參數的設定通常是強烈相關的,應該同時調節。
  4. 總結:SVM仍然值得嘗試,尤其在所有特徵的測量單位相似且範圍也差不多時

6. some docstring

?plt.yscale  # 設置y軸尺度scale
plt.yscale(value, **kwargs)  
value : {"linear", "log", "symlog", "logit", ...}  # The axis scale type to apply.
?SVC
SVC(
    C=1.0,    # Penalty parameter C of the error term.對誤差項的懲罰參數
    kernel='rbf',  # RBF核,可選:'linear', 'poly', 'sigmoid', 'precomputed' or a callable.
    degree=3,
    # 核係數,默認auto,which uses 1 / n_features,
    gamma='auto_deprecated',  # 將被棄用,新版本需要指定'auto' or 'scale',scale的gamma使用1 / (n_features * X.var())
    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,
)

注1:C-SVM,基於libsvm,LIBSVM是臺灣大學林智仁教授等開發設計的一個簡單、易於使用和快速有效的SVM模式識別與迴歸的軟件包
LIBSVM 使用的一般步驟是:
1) 按照LIBSVM軟件包所要求的格式準備數據集;
2) 對數據進行簡單的縮放操作;
3) 考慮選用RBF 核函數;
4) 採用交叉驗證選擇最佳參數C與g ;
5) 採用最佳參數C與g 對整個訓練集進行訓練獲取支持向量機模型;
6) 利用獲取的模型進行測試與預測。

注2:可能不適合數以萬計的樣本,對於大數據集考慮使用:sklearn.linear_model.LinearSVCsklearn.linear_model.SGDClassifier`

——來自於《機器學習基礎》的實踐

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