Python機器學習之支持向量機

引言

SVM的基本概念

分隔超平面:將數據集分割開來的直線叫做分隔超平面。
超平面:如果數據集是N維的,那么就需要N-1維的某對象來對數據進行分割。該對象叫做超平面,也就是分類的決策邊界。
間隔:一個點到分割面的距離,稱為點相對于分割面的距離。
數據集中所有的點到分割面的最小間隔的2倍,稱為分類器或數據集的間隔。
最大間隔:SVM分類器是要找最大的數據集間隔。
支持向量:坐落在數據邊際的兩邊超平面上的點被稱為支持向量

一、支持向量機的直觀理解

import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
from sklearn.datasets import make_blobs

#創(chuàng)建50個點,分為兩類
X, y = make_blobs(n_samples=50, centers=2, random_state=6)

#創(chuàng)建一個線性內核的支持向量機
svm1 = svm.SVC(kernel='linear', C=1000)
svm1.fit(X, y)

#把數據點畫出來
plt.scatter(X[:, 0], X[:, 1], c=y, s=30, cmap=plt.cm.Paired)

#建立圖像坐標
ax = plt.gca()
xlim = ax.get_xlim() #返回坐標的上下限
ylim = ax.get_ylim()

#生成兩個等差數列
xx = np.linspace(xlim[0], xlim[1], 30)
yy = np.linspace(ylim[0], ylim[1], 30)
XX, YY = np.meshgrid(xx, yy)
xy = np.vstack([XX.ravel(), YY.ravel()]).T
Z = svm1.decision_function(xy).reshape(XX.shape) #計算樣本點到分割超平面的函數距離

#把分類的決定邊界畫出來
ax.contour(XX, YY, Z, colors='k', levels=[-1, 0, 1], alpha=0.5, linestyles=['--', '-', '--']) #畫出等高線圖
ax.scatter(svm1.support_vectors_[:, 0], svm1.support_vectors_[:, 1], s=100, linewidth=1, facecolors='none') #support_vectors_ 所有的支持向量
plt.show()

如圖所示,分類器兩側有兩條虛線,壓在虛線上的點,就是支持向量。本例子采用的方法是“最大間隔超平面”,指的是說中間這條實線(在高維數據中是一個超平面),和所有支持向量之間的距離,都是最大的。


7.1SVM_linear.png

修改SVM 的內核,換成RBF,即修改以下代碼:

#創(chuàng)建一個線性內核的支持向量機
svm1 = svm.SVC(kernel='rbf', C=1000)
svm1.fit(X, y)

如圖所示,


7.1SVM_rbf.png

注釋1:

函數原型:matplotlib.pyplot.gca()

獲得當前的Axes對象ax
參考:
《python matplotlib.pyplot.gca() 函數的作用(獲得當前的Axes對象【Get Current Axes】)》
matplotlib繪圖——再談axes和pyplot方法》
注釋2:
函數原型:sklearn.svm.svc(C=1.0, kernel='rbf', degree=3, gamma='auto',
coef0=0.0, shrinking=True, probability=False,
tol=1e-3, cache_size=200, class_weight=None,
verbose=False, max_iter=-1, decision_function_shape='ovr', random_state=None)
參數解釋
?C: float參數 默認值為1.0.
錯誤項的懲罰系數。C越大,即對分錯樣本的懲罰程度越大,因此在訓練樣本中準確率越高,但是泛化能力降低,也就是對測試數據的分類準確率降低。相反,減小C的話,容許訓練樣本中有一些誤分類錯誤樣本,泛化能力強。對于訓練樣本帶有噪聲的情況,一般采用后者,把訓練樣本集中錯誤分類的樣本作為噪聲。
?kernel: str參數 默認為‘rbf’.算法中采用的核函數類型,可選參數有:
??‘linear’:線性核函數
‘??poly’:多項式核函數
??‘rbf’:徑像核函數/高斯核
??‘sigmoid’:sigmod核函數
??‘precomputed’:核矩陣.precomputed表示自己提前計算好核函數矩陣,這時候算法內部就不再用核函數去計算核矩陣,而是直接用你給的核矩陣。
??還有一點需要說明,除了上面限定的核函數外,還可以給出自己定義的核函數,其實內部就是用你自己定義的核函數來計算核矩陣。
?degree: int型參數 默認為3.這個參數只對多項式核函數有用,是指多項式核函數的階數n
如果給的核函數參數是其他核函數,則會自動忽略該參數。
?gamma: float參數 默認為auto.核函數系數,只對‘rbf’,‘poly’,‘sigmod’有效。
如果gamma為auto,代表其值為樣本特征數的倒數,即1/n_features.
?coef0: float參數 默認為0.0.核函數中的獨立項,只有對‘poly’和‘sigmod’核函數有用,是指其中的參數c
?probability: bool參數 默認為False.是否啟用概率估計。 這必須在調用fit()之前啟用,并且會fit()方法速度變慢。
?shrinking: bool參數 默認為True.是否采用啟發(fā)式收縮方式
?tol: float參數 默認為1e^-3.svm停止訓練的誤差精度
?cache_size: float參數 默認為200.指定訓練所需要的內存,以MB為單位,默認為200MB。
?class_weight: 字典類型或者‘balance’字符串。默認為None.給每個類別分別設置不同的懲罰參數C,如果沒有給,則會給所有類別都給C=1,即前面參數指出的參數C.如果給定參數‘balance’,則使用y的值自動調整與輸入數據中的類頻率成反比的權重。
?verbose: bool參數 默認為False.是否啟用詳細輸出。 此設置利用libsvm中的每個進程運行時設置,如果啟用,可能無法在多線程上下文中正常工作。一般情況都設為False,不用管它。
?max_iter: int參數 默認為-1.最大迭代次數,如果為-1,表示不限制.
?random_state: int型參數 默認為None.偽隨機數發(fā)生器的種子,在混洗數據時用于概率估計。
屬性
?svc.n_support_:各類各有多少個支持向量
?svc.support_:各類的支持向量在訓練樣本中的索引
?svc.support_vectors_:各類所有的支持向量
參考:《SVM基本概要與sklearn.svm.svc 參數說明》
注釋3:
[《Python+Matplotlib畫contour圖》](https://finthon.com/python-matplotlib-contour/

二、不同核函數的SVM對比

說明:linearSVM是一種使用了線性內核的SVM算法,不過linearSVM不支持對核函數進行修改。
使用dataset的紅酒數據

#對比不同的SVM
from sklearn.datasets import load_wine
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm

#定義畫圖函數
def make_meshgrid(x, y, h= .02):
    x_min, x_max = x.min() - 1, x.max() - 1
    y_min, y_max = y.min() - 1, y.max() - 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                         np.arange(y_min, y_max, h))
    return xx, yy

#定義繪制等高線的函數
def plot_countours(ax, clf, xx, yy, **params):
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    out = ax.contourf(xx, yy, Z, **params)
    return out

#導入紅酒數據
wine = load_wine()
#選取前兩個特征
X = wine.data[:, :2]
y = wine.target

C = 1.0 #SVM正則化參數
models = (svm.SVC(kernel='linear', C=C),
          svm.LinearSVC(C=C),
          svm.SVC(kernel='rbf', gamma=0.7, C=C),
          svm.SVC(kernel='poly', degree=3, C=C))

models = (clf.fit(X, y) for clf in models)

#設置圖題
titles = ('SVC with linear kernel',
          'LinearSVC(linear kernal)',
          'SVC with RBF kernal',
          'SVC with polynomial(degree 3) kernal')

#設定子圖形的個數和排列方式
fig, sub = plt.subplots(2, 2)
plt.subplots_adjust(wspace=0.4, hspace=0.4) #wspace, hspace:子圖之間的橫向間距、縱向間距分別與子圖平均寬度、平均高度的比值。

#畫圖,使用上面自定義的畫 圖函數
X0, X1 = X[:, 0], X[:, 1]
xx, yy = make_meshgrid(X0, X1)

for clf, title, ax in zip(models, titles, sub.flatten()):
    plot_countours(ax, clf, xx, yy, cmap=plt.cm.plasma, alpha=0.8)
    ax.scatter(X0, X1, c=y, cmap=plt.cm.plasma, s=20, edgecolors='k')
    ax.set_xlim(xx.min(), xx.max())
    ax.set_ylim(yy.min(), yy.max())
    ax.set_xlabel('Feature 0')
    ax.set_ylabel('Feature 1')
    ax.set_xticks(())
    ax.set_yticks(())
    ax.set_title(title)
plt.show()

從圖中可以看出來:
1.LinearSVC 和線性內核的 SVC 得到的結果非常近似。但仍有差別,原因之一是,LinearSVC對 L2范數進行優(yōu)化,而線性內核的SVC是對L1范數進行優(yōu)化;
2.RBF 內核的 SVC 和 polynomial 內核的 SVC 分類器的決定邊界不是線性的,更加彈性。決定他們形狀的,是它們的參數。polynomial 內核的 SVC中,起決定作用的參數是 degree 和 正則化參數 C,上述代碼中使用的 degree是3 ,也就是對原始數據集的特征乘3次方操作。RBF 內核的 SVC中起決定作用的是正則化參數 C 和參數 gamma。


7.2SVM_diff.png

注釋1:

《Python tips: 什么是 *args 和 **kwargs?》

注釋2:

np.r_是按列連接兩個矩陣,就是把兩矩陣上下相加,要求列數相等。
np.c_是按行連接兩個矩陣,就是把兩矩陣左右相加,要求行數相等

三、支持向量機的gamma參數調節(jié)

仍舊使用紅酒數據,調節(jié)gamma 參數值,查看對 RBF 內核的 SVC有什么影響。

#調節(jié)gamma 參數值,查看對 RBF 內核的 SVC有什么影響
from sklearn.datasets import load_wine
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm

#定義畫圖函數
def make_meshgrid(x, y, h= .02):
    x_min, x_max = x.min() - 1, x.max() - 1
    y_min, y_max = y.min() - 1, y.max() - 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                         np.arange(y_min, y_max, h))
    return xx, yy

#定義繪制等高線的函數
def plot_countours(ax, clf, xx, yy, **params):
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    out = ax.contourf(xx, yy, Z, **params)
    return out

#導入紅酒數據
wine = load_wine()
#選取前兩個特征
X = wine.data[:, :2]
y = wine.target

C = 1.0 #SVM正則化參數
models = (svm.SVC(kernel='rbf', gamma=0.1, C=C),
          svm.SVC(kernel='rbf', gamma=1, C=C),
          svm.SVC(kernel='rbf', gamma=10, C=C))

models = (clf.fit(X, y) for clf in models)

#設置圖題
titles = ('gamma = 0.1',
          'gamma = 1',
          'gamma = 10')

#設定子圖形的個數和排列方式
fig, sub = plt.subplots(1, 3, figsize = (10, 3))

#畫圖,使用上面自定義的畫 圖函數
X0, X1 = X[:, 0], X[:, 1]
xx, yy = make_meshgrid(X0, X1)

for clf, title, ax in zip(models, titles, sub.flatten()):
    plot_countours(ax, clf, xx, yy, cmap=plt.cm.plasma, alpha=0.8)
    ax.scatter(X0, X1, c=y, cmap=plt.cm.plasma, s=20, edgecolors='k')
    ax.set_xlim(xx.min(), xx.max())
    ax.set_ylim(yy.min(), yy.max())
    ax.set_xlabel('Feature 0')
    ax.set_ylabel('Feature 1')
    ax.set_xticks(())
    ax.set_yticks(())
    ax.set_title(title)
plt.show()

從圖中可以看出來:
1.gamma值越小,RBF內核的直徑越大,有更多的點被圈入決策邊界中,決策邊界也越平滑
2.隨著gamma參數的增加,模型更傾向于把每一個點都放到相應的決策邊界中,模型的復雜度也相應提高了
3.gamma值越小,模型更傾向于欠擬合;gamma 值越大,模型更傾向于欠擬合
4.正則化參數C,越小,模型越受限,即單個數據點對模型的影響越??;C 越大,每個數據點對模型的影響就越大,模型就會更加復雜


7.3RBF_gamma.png

四、支持向量機的優(yōu)勢與不足

優(yōu)勢:

  • 1.可以在數據特征很少的情況下生成非常復雜的決定邊界。即 SVM 應對高維數據集和低維數據集都可,但前提是數據規(guī)模不太大
  • 2.數據樣本特征的測度比較接近。例如圖像識別領域,或者樣本特征數和樣本數比較接近的時候,SVM 游刃有余。
    參數
    不足:
  • 1.樣本數量超過10W 的話,SVM會非常耗費時間和內存。
  • 2.對于數據預處理和參數的調節(jié)要求很高。

SVM 算法中,有3個重要參數調節(jié):

  • 1.核函數的選擇
  • 2.核函數的參數,例如 RBF 的 gamma 值,用來調節(jié)內核寬度,gamma 值和 C 值一起控制模型的復雜度,數值越大模型越復雜,往往需要一起調節(jié)。
  • 3.正則化參數 C
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容