1. 程式人生 > >SVM sklearn python實現小示例

SVM sklearn python實現小示例

示例說明

本示例是一個簡單的試驗,甚至連資料集都不用額外準備,旨在加深對SVM和核函式的理解,並看看如何利用 scikit-learn 中的svm,
編譯環境是 jupyter notebook, 可以通過安裝 Anaconda,匯入 scikit-learn 庫可以很容易實現,github示例程式碼。本例中變沒有用外部資料集,而是隨機生成的點,大家在理解演算法和 scikit-learn 熟練使用後,可以嘗試匯入有具體意義的資料集,看看SVM的效果。

概述

SVM_demo_with_sklearn.ipynb程式碼中主要分為兩個部分
* 線性 SVM 分類器
* SVM 與核函式

Section 1: 線性 SVM 分類器

首先匯入依賴包

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import seaborn; 
from sklearn.linear_model import LinearRegression
from scipy import stats
import pylab as pl
seaborn.set()

支援向量機是解決分類和迴歸問題非常強大的有監督學習演算法。簡單說來,linear的SVM做的事情就是在不同類別的“資料團”之間劃上一條線,對線性可分集,總能找到使樣本正確劃分的分介面,而且有無窮多個,哪個是最優? 必須尋找一種最優的分界準則,SVM試圖找到一條最健壯的線,什麼叫做最健壯的線?其實就是離2類樣本點最遠的線。

from sklearn.datasets.samples_generator import make_blobs
X, y = make_blobs(n_samples=50, centers=2,
                  random_state=0, cluster_std=0.60)

xfit = np.linspace(-1, 3.5)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='spring')

# 其實隨意給定3組引數,就可以畫出3條不同的直線,但它們都可以把圖上的2類樣本點分隔開
for m, b, d in [(1
, 0.65, 0.33), (0.5, 1.6, 0.55), (-0.2, 2.9, 0.2)]: yfit = m * xfit + b plt.plot(xfit, yfit, '-k') plt.fill_between(xfit, yfit - d, yfit + d, edgecolor='none', color='#AAAAAA', alpha=0.4) plt.xlim(-1, 3.5);
from sklearn.svm import SVC
clf = SVC(kernel='linear')
clf.fit(X, y)

def plot_svc_decision_function(clf, ax=None):
    """Plot the decision function for a 2D SVC"""
    if ax is None:
        ax = plt.gca()
    x = np.linspace(plt.xlim()[0], plt.xlim()[1], 30)
    y = np.linspace(plt.ylim()[0], plt.ylim()[1], 30)
    Y, X = np.meshgrid(y, x)
    P = np.zeros_like(X)
    for i, xi in enumerate(x):
        for j, yj in enumerate(y):
            P[i, j] = clf.decision_function([xi, yj])
    # plot the margins
    ax.contour(X, Y, P, colors='k',
               levels=[-1, 0, 1], alpha=0.5,
               linestyles=['--', '-', '--'])
  • 分隔超平面:上述將資料集分割開來的直線叫做分隔超平面。
  • 超平面:如果資料集是N維的,那麼就需要N-1維的某物件來對資料進行分割。該物件叫做超平面,也就是分類的決策邊界。
  • 間隔:一個點到分割面的距離,稱為點相對於分割面的距離。資料集中所有的點到分割面的最小間隔的2倍,稱為分類器或資料集的間隔。
  • 最大間隔:SVM分類器是要找最大的資料集間隔。
  • 支援向量:離分割超平面最近的那些點

sklearn的SVM裡面會有一個屬性support_vectors_,標示“支援向量”,也就是樣本點裡離超平面最近的點,組成的。
咱們來畫個圖,把超平面和支援向量都畫出來。

plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='spring')
plot_svc_decision_function(clf)
plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1],
            s=200, facecolors='none');

可以用IPython的 interact 函式來看看樣本點的分佈,會怎麼樣影響超平面:

from IPython.html.widgets import interact

def plot_svm(N=100):
    X, y = make_blobs(n_samples=200, centers=2,
                      random_state=0, cluster_std=0.60)
    X = X[:N]
    y = y[:N]
    clf = SVC(kernel='linear')
    clf.fit(X, y)
    plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='spring')
    plt.xlim(-1, 4)
    plt.ylim(-1, 6)
    plot_svc_decision_function(clf, plt.gca())
    plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1],
                s=200, facecolors='none')

interact(plot_svm, N=[10, 200], kernel='linear');

Section 2: SVM 與 核函式

對於非線性可切分的資料集,要做分割,就要藉助於核函數了簡單一點說呢,核函式可以看做對原始特徵的一個對映函式,
不過SVM不會傻乎乎對原始樣本點做對映,它有更巧妙的方式來保證這個過程的高效性。
下面有一個例子,你可以看到,線性的kernel(線性的SVM)對於這種非線性可切分的資料集,是無能為力的。

from sklearn.datasets.samples_generator import make_circles
X, y = make_circles(100, factor=.1, noise=.1)

clf = SVC(kernel='linear').fit(X, y)

plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='spring')
plot_svc_decision_function(clf);

然後強大的高斯核/radial basis function就可以大顯身手了:

r = np.exp(-(X[:, 0] ** 2 + X[:, 1] ** 2))

from mpl_toolkits import mplot3d

def plot_3D(elev=30, azim=30):
    ax = plt.subplot(projection='3d')
    ax.scatter3D(X[:, 0], X[:, 1], r, c=y, s=50, cmap='spring')
    ax.view_init(elev=elev, azim=azim)
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('r')

interact(plot_3D, elev=[-90, 90], azip=(-180, 180));

你在上面的圖上也可以看到,原本在2維空間無法切分的2類點,對映到3維空間以後,可以由一個平面輕鬆地切開了。
而帶rbf核的SVM就能幫你做到這一點:

clf = SVC(kernel='rbf')
clf.fit(X, y)

plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='spring')
plot_svc_decision_function(clf)
plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1],
            s=200, facecolors='none');

關於SVM的總結:

  • 非線性對映是SVM方法的理論基礎,SVM利用內積核函式代替向高維空間的非線性對映;
  • 對特徵空間劃分的最優超平面是SVM的目標,最大化分類邊際的思想是SVM方法的核心;
  • 支援向量是SVM的訓練結果,在SVM分類決策中起決定作用的是支援向量。因此,模型需要儲存空間小,演算法魯棒性強;
  • 無任何前提假設,不涉及概率測度;
  • SVM演算法對大規模訓練樣本難以實施
  • 用SVM解決多分類問題存在困難,經典的支援向量機演算法只給出了二類分類的演算法,而在資料探勘的實際應用中,一般要解決多類的分類問題。可以通過多個二類支援向量機的組合來解決。主要有一對多組合模式、一對一組合模式和SVM決策樹;再就是通過構造多個分類器的組合來解決。主要原理是克服SVM固有的缺點,結合其他演算法的優勢,解決多類問題的分類精度。如:與粗集理論結合,形成一種優勢互補的多類問題的組合分類器。
  • SVM是O(n^3)的時間複雜度。在sklearn裡,LinearSVC是可擴充套件的(也就是對海量資料也可以支援得不錯), 對特別大的資料集SVC就略微有點尷尬了。不過對於特別大的資料集,你倒是可以試試取樣一些樣本出來,然後用rbf核的SVC來做做分類。

依賴的 packages

  • matplotlib
  • pylab
  • numpy
  • seaborn

歡迎關注