SVM原理
線性可分與線性不可分
線性可分
線性不可分-------【無論用哪條直線都無法將女生情緒正確分類】
SVM的核函數可以幫助我們:
假設‘開心’是輕飄飄的,“不開心”是沉重的
將三維視圖還原成二維:
剛利用“開心”“不開心”的重量差實現將二維數據變成三維的過程,稱為將數據投射至高維空間,這正是核函數的功能
在SVM中,用的最普遍的兩種把數據投射到高維空間的方法分別是多項式內核、徑向基內核(RFB)
多項式內核:
通過把樣本原始特征進行乘方來把數據投射到高維空間【如特征1^2,特征2^3,特征3^5......】
RBF:
又稱高斯內核
支持向量機的SVM核函數
用圖形直觀了解:
#導入numpy
import numpy as np
#導入畫圖工具
import matplotlib.pyplot as plt
#導入支持向量機SVM
from sklearn import svm
#導入數據集生成工具
from sklearn.datasets import make_blobs
#先創建50個數據點,讓它們分成兩類
X,y = make_blobs(n_samples=50,centers=2,random_state = 6)
#創建一個線性內核的支持向量機模型
clf = svm.SVC(kernel = 'linear',C=1000)
clf.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)
YY,XX = np.meshgrid(yy,xx)
xy = np.vstack([XX.ravel(),YY.ravel()]).T
Z = clf.decision_function(xy).reshape(XX.shape)
#把分類的邊界畫出來
ax.contour(XX,YY,Z,colors='k',levels=[-1,0,1],alpha=0.5,linestyles=['--','-','--'])
ax.scatter(clf.support_vectors_[:,0],clf.support_vectors_[:,1],s=100,linewidth=1,facecolors='none')
plt.show()
——線性內核的SVM分類器
【結果分析】:
在分類器兩側有兩條虛線,正好壓在虛線上的數據點,即支持向量
本例所使用的方法稱為“最大邊界間隔超平面”
指,實線【在高維數據中是一個超平面】和所有支持向量的距離都是最大的
把SVM的內核換成RBF:
#創建一個RBF內核的支持向量機模型
clf_rbf = svm.SVC(kernel='rbf',C=1000)
clf_rbf.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)
YY,XX = np.meshgrid(yy,xx)
xy = np.vstack([XX.ravel(),YY.ravel()]).T
Z = clf_rbf.decision_function(xy).reshape(XX.shape)
#把分類的邊界畫出來
ax.contour(XX,YY,Z,colors='k',levels=[-1,0,1],alpha=0.5,linestyles=['--','-','--'])
ax.scatter(clf_rbf.support_vectors_[:,0],clf_rbf.support_vectors_[:,1],s=100,linewidth=1,facecolors='none')
plt.show()
——RBF內核的SVM分類器
【結果分析】:
使用RBF內核時,數據點距離計算是用如下公式計算的:
SVM的核函數和參數選擇
1.不同核函數的SVM對比
線性模型中提到過,linearSVM算法,就是一種使用了線性內核的SVM算法,不過linearSVM不支持對核函數進行修改【默認只能使用線性內核】
直觀體驗不同內核的SVM算法在分類中的不同表現:
from sklearn.datasets import load_wine
#定義一個函數來畫圖
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_contours(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 = (clf.fit(X,y) for clf in models)
#設定圖題
titles = ('SVC with linear kernal','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)
#使用前面定義的函數進行畫圖
X0,X1 = X[:,0],X[:,1]
xx,yy = make_meshgrid(X0,X1)
plot_contours(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()

【結果分析】:
線性內核的SVC與linearSVC得到的結果近似,但仍然有一點差別——原因是linearSVC對L2范數進行最小化,而線性內核的SVC是對L1進行最小化
無論如何,線性內核的SVC和linearSVC生成的決定邊界都是線性的【在更高維數據集中將會是相交的超平面】
RBF內核的SVC和polynomial內核的SVC分類器的決定邊界則完全不是線性的,更加彈性
決定他們邊界形狀的是參數:
polynomial內核的SVC分類器
degree和正則化參數C
【本例中degree=3,即對原始數據集的特征乘3次方操作】
RBF內核的SVC
gamma和正則化參數C
RBF內核SVC的gamma參數調節
models = (clf.fit(X,y) for clf in models)
#設定圖題
titles = ('gamma=0.1','gamma=1','gamma=10')
#設置子圖形個數和排列
flg,sub = plt.subplots(1,3,figsize=(10,3))
X0,X1 = X[:,0],X[:,1]
xx,yy = make_meshgrid(X0,X1)
plot_contours(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()
【結果分析】:
gamma值越小,RBF內核的直徑越大——> 有更多的點被模型圈進決定邊界中——> 邊界越圓滑
- gamma越小,模型傾向於 欠擬合
- gamma越大,模型傾向於 過擬合
正則化參數C,可以見線性模型一章
- C越小,模型越受限【單個數據對模型的影響越小】,模型越簡單
- C越大,每個數據點對模型的影響越大,模型越復雜
SVM優點
- 可應對高維數據集和低維數據集
- 即使數據集中樣本特征的測度都比較接近,如圖像識別領域,以及樣本特征數和樣本數比較接近的時候,都游刃有余
SVM缺點
- 當數據集中特征數量在1萬以內,SVM可以駕馭,但數量大於10萬,就非常占內存和耗費時間
- 對數據預處理和參數調節要求很高
【注意】
SVM中3個參數非常重要:
- 核函數的選擇
- 核函數的參數【如RBF的gamma】
- 正則化參數C
RBF內核的gamma值是用來調節內核寬度的,gamma值和C值一起控制模型的復雜度,數值越大,模型越復雜【實際中,一起調節,才能達到最好的效果】
實戰
SVM在回歸分析中的應用——波士頓房價數據集
1.了解數據集
#導入波士頓房價
from sklearn.datasets import load_boston
boston = load_boston()
#打印鍵
print(boston.keys())
#打印數據集中的短描述
print(boston['DESCR'])
【一部分】
【結果分析】
數據集共有506個樣本,每個樣本有13個特征變量,后面還有一個叫做中位數的第14個變量【這變量就是該數據集中的target】
2.通過SVR算法建立房價預測模型
#導入數據集拆分工具
from sklearn.model_selection import train_test_split
#建立數據集和測試集
X,y = boston.data,boston.target
X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=8)
#打印訓練集和測試集的形態
print(X_train.shape)
print(X_test.shape)
用SVR建模
#導入支持向量回歸模型
from sklearn.svm import SVR
#分別測試linear核函數和rbf核函數
for kernel in ['linear','rbf']:
svr = SVR(kernel=kernel)
svr.fit(X_train,y_train)
print(kernel,'核函數模型訓練集得分:',svr.score(X_train,y_train))
print(kernel,'核函數模型測試集得分:',svr.score(X_test,y_test))
SVM算法對數據預處理的要求較大,如果 數據特征量級差異較大 ,就需要預處理數據
先用圖形可視化:
#將特征數值中的min和max用散點圖畫出來
plt.plot(X.min(axis=0),'v',label='min')
plt.plot(X.max(axis=0),'^',label='max')
#設定縱坐標為對數形式
plt.yscale('log')
#設定圖注位置最佳
plt.legend(loc='best')
plt.xlabel('features')
plt.ylabel('feature magnitude')
plt.show()
顯然,量級差異較大
預處理:
from sklearn.preprocessing import StandardScaler
#預處理
scaler = StandardScaler()
scaler.fit(X_train)
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)
#將預處理后的數據特征的max和min用散點圖表示出來
plt.plot(X_train_scaled.min(axis=0),'v',label='train set min')
plt.plot(X_train_scaled.max(axis=0),'^',label='train set max')
plt.plot(X_test_scaled.min(axis=0),'v',label='test set min')
plt.plot(X_test_scaled.max(axis=0),'^',label='test set max')
plt.legend(loc='best')
plt.xlabel('scaled features')
plt.ylabel('scaled feature magnitude')
plt.show()
【結果分析】
經過預處理,無論訓練集還是測試集,所有特征的最大值不會超過10,最小值趨近0,以至圖中看不到
用預處理的數據訓練模型:
#使用預處理后的數據重新訓練模型
for kernel in ['linear','rbf']:
svr = SVR(kernel=kernel)
svr.fit(X_train_scaled,y_train)
print(kernel,'訓練集得分:',svr.score(X_train_scaled,y_train))
print(kernel,'測試集得分:',svr.score(X_test_scaled,y_test))
進一步調整參數
#設置模型的C參數和gamma參數
svr = SVR(C=100,gamma=0.1)
svr.fit(X_train_scaled,y_train)
print('訓練集得分:',svr.score(X_train_scaled,y_train))
print('測試集得分:',svr.score(X_test_scaled,y_test))