1. 程式人生 > >支援向量機演算法的實現和應用(Python3超詳細的原始碼實現+圖介紹)

支援向量機演算法的實現和應用(Python3超詳細的原始碼實現+圖介紹)

支援向量機演算法的實現和應用,因為自己推到過SVM,建議自己推到一遍, 這裡不對SVM原理做詳細的說明。

原理公式推到推薦看:https://blog.csdn.net/jcjx0315/article/details/61929439

#!/usr/bin/env python
# encoding: utf-8
"""
@Company:華中科技大學電氣學院聚變與等離子研究所
@version: V1.0
@author: Victor
@contact: [email protected]  2018--2020
@software: PyCharm
@file: SVM.py
@time: 2018/11/25 12:48
@Desc:支援向量機演算法的實現和應用,因為自己推到過SVM,建議自己推到一遍,
       這裡不對SVM原理做詳細的說明。
"""
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

##使用seaborn plotting 的預設引數
import seaborn as sns;sns.set()

'''支援向量機的基本原理:將低維不可分的資料問題經過核
函式轉化為高維可分,再找到超平面進行分開'''


###隨機一些資料,並可視化出來便於觀看
from sklearn.datasets.samples_generator import make_blobs

##自己定義資料集的結構,引數 n_samples:一共多少樣本點;centers:分為多少簇;
##                        random_state:確定隨機種子,保證每次的資料都是一樣的
##                        cluster_std:每個簇的離散程度,越大越分散,越小越集中更好分類
##X是樣本資料座標,y是標籤
X,y = make_blobs(n_samples=50,centers=2,random_state=0,cluster_std=0.6)
##視覺化隨機資料
plt.figure(1)
plt.scatter(X[:,0],X[:,1],c = y,s = 60 ,cmap = 'autumn')

探索性切分資料,畫線:

plt.figure(2)
xfit = np.linspace(-1,3.5)
plt.scatter(X[:,0],X[:,1],c = y,s = 60 ,cmap = 'autumn')
plt.plot([0.6],[2.1],'x',color = 'red',markeredgewidth = 2,markersize = 10)##畫了一個X點

##以X點畫幾條切分線
for m,b in [(1,0.65),(0.5,1.6),(-0.2,2.9)]:
    ##m為斜率
    plt.plot(xfit,m*xfit+b,'-k')
plt.xlim(-1,3.5)

 

給每條線構造陰影區域,表示隔離帶,先直觀上看看那條比較好

plt.figure(3)
xfit = np.linspace(-1,3.5)
plt.scatter(X[:,0],X[:,1],c = y,s = 60 ,cmap = 'autumn')
plt.plot([0.6],[2.1],'x',color = 'red',markeredgewidth = 2,markersize = 10)##畫了一個X點

##以X點畫幾條切分線
for m,b,d in [(1,0.65,0.33),(0.5,1.6,0.55),(-0.2,2.9,0.2)]:
    ##m為斜率
    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  ###支援向量機的一個分類器
model = SVC(kernel='linear')##核函式選用線性分類
###開始訓練一個基本的SVM
model.fit(X,y)


# 繪圖函式,邊界上的點才是支援向量,係數不等於0,非邊界上的係數值等於0.
def plot_svc_decision_function(model, ax=None, plot_support=True):
    """Plot the decision function for a 2D SVC"""
    if ax is None:
        ax = plt.gca()
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()

    # create grid to evaluate model
    x = np.linspace(xlim[0], xlim[1], 30)
    y = np.linspace(ylim[0], ylim[1], 30)
    Y, X = np.meshgrid(y, x)
    xy = np.vstack([X.ravel(), Y.ravel()]).T
    P = model.decision_function(xy).reshape(X.shape)

    # 畫決策邊界和邊緣
    ax.contour(X, Y, P, colors='k',
               levels=[-1, 0, 1], alpha=0.5,
               linestyles=['--', '-', '--'])

    # 畫支援向量
    if plot_support:
        ax.scatter(model.support_vectors_[:, 0],
                   model.support_vectors_[:, 1],
                   s=250, linewidth=1, facecolors='b')
    ax.set_xlim(xlim)
    ax.set_ylim(ylim)

plt.figure(4)
plt.scatter(X[:,0],X[:,1],c = y,s = 60 ,cmap = 'autumn')
plot_svc_decision_function(model)

###輸出支援向量的座標:
print(model.support_vectors_)
# [[0.44359863 3.11530945]
#  [2.33812285 3.43116792]
#  [2.06156753 1.96918596]]

 

改變資料的個數【60,120】,只要支援向量不變,決策邊界就不改變。

'''改變資料的個數【60,120】,只要支援向量不變,決策邊界就不改變'''
def plot_svm(N=10, ax=None):
    X, y = make_blobs(n_samples=200, centers=2,
                      random_state=0, cluster_std=0.60)
    X = X[:N]
    y = y[:N]
    model = SVC(kernel='linear', C=1E10)
    model.fit(X, y)

    ax = ax or plt.gca()
    ax.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')
    ax.set_xlim(-1, 4)
    ax.set_ylim(-1, 6)
    plot_svc_decision_function(model, ax)

fig, ax = plt.subplots(1, 2, figsize=(12, 6))
fig.subplots_adjust(left=0.0625, right=0.95, wspace=0.1)
for axi, N in zip(ax, [60, 120]):
    plot_svm(N, axi)
    axi.set_title('N = {0}'.format(N))

 

引入核函式的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)##先採用線性的SVM
plt.figure(6)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')
plot_svc_decision_function(clf, plot_support=False)

將二維的資料變換到三維,畫圖直觀表示出來,更容易切分

#加入了新的維度r
from mpl_toolkits import mplot3d
r = np.exp(-(X ** 2).sum(1))
def plot_3D(elev=30, azim=30, X=X, y=y):
    ax = plt.subplot(projection='3d')
    ax.scatter3D(X[:, 0], X[:, 1], r, c=y, s=50, cmap='autumn')
    ax.view_init(elev=elev, azim=azim)
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('r')
plt.figure(7)
plot_3D(elev=45, azim=45, X=X, y=y)

實際做法:將低維對映到高維,再切分

#加入徑向基函式(就是高斯核函式或者rbf核函式),都是高斯變換
clf = SVC(kernel='rbf', C=1E6)
clf.fit(X, y)
###非線性劃分展示
plt.figure(8)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')
plot_svc_decision_function(clf)
plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1],
            s=300, lw=1, facecolors='none')

SVM引數之Soft Margin問題

   調節C引數: 當C趨近於無窮大時:意味著分類嚴格不能有錯誤

                         當C趨近於很小的時:意味著可以有更大的錯誤容忍

###重新隨機一些資料,使離散程度更大一些
plt.figure(9)
X, y = make_blobs(n_samples=100, centers=2,
                  random_state=0, cluster_std=0.8)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')

改變C引數的大小對結果的影響

###改變C引數的大小對結果的影響,可以看到,C太大劃分更嚴格,泛化能力更弱,適合要求
###C小,要求越放鬆。
###通常用交叉驗證來評判哪個效果好,就取哪個C
X, y = make_blobs(n_samples=100, centers=2,
                  random_state=0, cluster_std=0.8)

fig, ax = plt.subplots(1, 2, figsize=(13, 6))
fig.subplots_adjust(left=0.0625, right=0.95, wspace=0.1)

for axi, C in zip(ax, [10.0, 0.1]):##分別取得ax,10;ax,0.1賦給axi,C然後執行迴圈。
    model1 = SVC(kernel='linear', C=C).fit(X, y)
    axi.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')
    plot_svc_decision_function(model1, axi)
    axi.scatter(model1.support_vectors_[:, 0],
                model1.support_vectors_[:, 1],
                s=300, lw=1, facecolors='none');
    axi.set_title('C = {0:.1f}'.format(C), size=14)

 

探究高斯核函式中的gamma係數

#####探究高斯核函式中的gamma係數:
#####                控制模型的一些複雜程度,
#####                越大的gamma值,表示對映的維度越高,模型越複雜,可能會讓所有點都成了支援向量
#####                越小,模型越精簡,結果更平穩。所以精度並不能直接說明模型好壞
X, y = make_blobs(n_samples=100, centers=2,
                  random_state=0, cluster_std=1.1)

fig, ax = plt.subplots(1, 2, figsize=(14, 6))
fig.subplots_adjust(left=0.0625, right=0.95, wspace=0.1)

for axi, gamma in zip(ax, [10.0, 0.1]):
    model = SVC(kernel='rbf', gamma=gamma).fit(X, y)
    axi.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')
    plot_svc_decision_function(model, axi)
    axi.scatter(model.support_vectors_[:, 0],
                model.support_vectors_[:, 1],
                s=300, lw=1, facecolors='none');
    axi.set_title('gamma = {0:.1f}'.format(gamma), size=14)

 

對圖的解釋已經在程式碼註釋中了,可以詳細看看支援向量機是如何一步步開展的。