支援向量機演算法的實現和應用(Python3超詳細的原始碼實現+圖介紹)
阿新 • • 發佈:2018-11-28
支援向量機演算法的實現和應用,因為自己推到過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)
對圖的解釋已經在程式碼註釋中了,可以詳細看看支援向量機是如何一步步開展的。