推文:支持向量機通俗導論(理解SVM的三層境界)
----------------線性核函數-----------------
一:作業介紹
在本練習的前半部分,您將使用支持向量機。各種示例2D數據集。使用這些數據集進行實驗將幫助您直觀地了解支持向量機如何工作,以及如何使用支持向量機的高斯內核。
二:導入數據和數據可視化
(一)數據導入
data = sio.loadmat("ex6data1.mat") X = data['X'] y = data['y'].flatten() m = y.size print(X.shape,y.shape)
(二)數據顯示
print("X:\n",X[:10,]) print("y:\n",y[:10])
(三)數據可視化
def plot_data(X,y): posX = X[np.where(y==1)] #獲取正樣本 negX = X[np.where(y==0)] #獲取負樣本 plt.scatter(posX[:,0],posX[:,1],c='b',marker='X') #散點圖繪制 正樣本 plt.scatter(negX[:,0],negX[:,1],c='r',marker='o') #散點圖繪制 負樣本
plt.figure()
plot_data(X,y)
plt.show()
可以看出左上角的那個數據點為異常點(誤差點)。
(四)獲取橫軸、、豎軸最值。后面繪制決策邊界需要
print(np.min(X[:,0]),np.max(X[:,0])) #0.086405 4.015 print(np.min(X[:,1]),np.max(X[:,1])) #1.6177 4.6162
所以我們對於橫軸取值范圍為(-0.5,4.5),豎軸取值范圍為(1.3,5)
三:svm模塊之線性核函數
sklearn提供了很多機器學習的庫,本次作業主要也是用它來解決SVM的問題
重點補充numpy.meshgrid()理解
https://blog.csdn.net/lllxxq141592654/article/details/81532855
(一)C=1時(C較小時,相當於入較大(平滑,泛化能力好),可能會導致欠擬合,高偏差),不因為一個異常點影響“大邊界”
1.獲取分類器的准確率
c = 1 clf = svm.SVC(c,kernel="linear",tol=1e-3) #實例化分類器,C為誤差項懲罰系數,核函數選擇線性核,停止訓練的誤差值大小,默認為1e-3。https://blog.csdn.net/weixin_41990278/article/details/93137009 clf.fit(X,y) #導入數據進行訓練 print(clf.score(X,y)) #分類器的准確率
2.繪制決策邊界《重點》
#繪制決策邊界 def plot_boundary(model): x_min,x_max = -0.5,4.5 y_min, y_max = 1.3, 5 # 生成網格點坐標矩陣 xx,yy = np.meshgrid(np.linspace(x_min,x_max,500), #xx (500, 500) yy (500, 500) np.linspace(y_min,y_max,500)) # print(xx.shape,yy.shape) # print(np.c_[xx.flatten(), yy.flatten()].shape) #(250000, 2)--->對應了網格點坐標矩陣中的每一個坐標點 # 用訓練好的分類器去預測各個坐標點中的數據的標簽為[1]的值(其他為0)---全為1的位置就是決策邊界 z = model.predict(np.c_[xx.flatten(), yy.flatten()]) #z (250000,) # print(z.shape) # for i in range(z.size): #z中全為0、1值 # if z[i] != 0: # print(z[i]) zz = z.reshape(xx.shape) #將我們預測出來的z值有一維空間,轉換為二維網格坐標矩陣,便於在二維平面繪制決策邊界 plt.contour(xx, yy, zz) #繪制決策邊界 xx,yy是矩陣坐標,zz是我們對各個坐標的賦值,其中為1 的地方就是我們要找的決策邊界
data = sio.loadmat("ex6data1.mat") X = data['X'] y = data['y'].flatten() m = y.size c = 1 clf = svm.SVC(c,kernel="linear",tol=1e-3) #實例化分類器,C為誤差項懲罰系數,核函數選擇線性核,停止訓練的誤差值大小,默認為1e-3。https://blog.csdn.net/weixin_41990278/article/details/93137009 clf.fit(X,y) #導入數據進行訓練 plt.figure() plot_boundary(clf) plot_data(X,y) plt.show()
c=1,此時不因為一個異常點影響“大邊界”,擬合效果較好
(二)c=100,可以很好的擬合正類和負類,但由於一個異常點造成過擬合,不能最大邊界
----------------高斯核函數-----------------
一:數據導入及可視化
(一)數據可視化
data = sio.loadmat("ex6data2.mat") X = data['X'] y = data['y'].flatten() m = y.size plt.figure() plot_data(X,y) plt.show()
(二)獲取數據上下界
print(np.min(X[:,0]),np.max(X[:,0])) #0.0449309 0.998848 print(np.min(X[:,1]),np.max(X[:,1])) #0.402632 0.988596
所以我們繪制決策邊界時,取橫坐標從(0,1)。豎軸(0.4,1)
二:svm模塊之高斯核函數
使用高斯核函數解決線性不可分問題,並觀察 σ取值對模型復雜度的影響。
(一)簡單實現高斯核函數---測試
高斯核函數公式:
def gaussian_kernel(x1,x2,sigma=0.1): x1 = x1.flatten() x2 = x2.flatten() gk = np.exp(-np.sum(np.power((x1-x2),2))/(2*np.power(sigma,2))) return gk
x1 = np.array([1,2,1]) x2 = np.array([0,4,-1]) sigma = 2 print(gaussian_kernel(x1,x2,sigma))
(二)調用sklearn中的高斯核函數實現SVM算法
c = 1gamma = 1 clf = svm.SVC(c,kernel="rbf",gamma) #實例化分類器,C為誤差項懲罰系數,核函數選擇高斯核,設置gamma字段為gamma,注意gamma不等於σ,但是兩者有關聯。https://blog.csdn.net/weixin_41990278/article/details/93137009 clf.fit(X,y) #導入數據進行訓練 print(clf.score(X,y)) #分類器的准確率
補充:SVM算法中的gamma字段《重點》
此外大家注意RBF公式里面的sigma和gamma的關系如下:
(三)繪制決策邊界---修改坐標范圍即可
#繪制決策邊界 def plot_boundary(model): x_min,x_max = 0,1 y_min, y_max = 0.4, 1 # 生成網格點坐標矩陣 xx,yy = np.meshgrid(np.linspace(x_min,x_max,500), #xx (500, 500) yy (500, 500) np.linspace(y_min,y_max,500)) # print(xx.shape,yy.shape) # print(np.c_[xx.flatten(), yy.flatten()].shape) #(250000, 2)--->對應了網格點坐標矩陣中的每一個坐標點 # 用訓練好的分類器去預測各個坐標點中的數據的標簽為[1]的值(其他為0)---全為1的位置就是決策邊界 z = model.predict(np.c_[xx.flatten(), yy.flatten()]) #z (250000,) # print(z.shape) # for i in range(z.size): #z中全為0、1值 # if z[i] != 0: # print(z[i]) zz = z.reshape(xx.shape) #將我們預測出來的z值有一維空間,轉換為二維網格坐標矩陣,便於在二維平面繪制決策邊界 plt.contour(xx, yy, zz) #繪制決策邊界 xx,yy是矩陣坐標,zz是我們對各個坐標的賦值,其中為1 的地方就是我們要找的決策邊界
plt.figure()
plot_boundary(clf)
plot_data(X,y)
plt.show()
可以看出當gamma=1時,擬合效果並不是很好!!!
(四)不同gamma的選取
1.gamma=1時
分類器的准確率如下:
2.gamma=50
分類器的准確率如下:
3.gamma=1000
分類器的准確率如下:
(五)結論:σ和gamma
sigma和gamma的關系如下:
這里面大家需要注意的就是gamma的物理意義,就是大家提到很多的RBF的幅寬,它會影響每個支持向量對應的高斯的作用范圍,從而影響泛化性能。
1.如果gamma設的太大,σ會很小,σ很小的高斯分布長得又高又瘦, 會造成只會作用於支持向量樣本附近,對於未知樣本分類效果很差,存在訓練准確率可以很高,(如果讓σ無窮小,則理論上,高斯核的SVM可以擬合任何非線性數據,但容易過擬合)而測試准確率不高的可能,就是通常說的過訓練;
2.而如果gamma設的過小,σ會很大,則會造成平滑效應太大,無法在訓練集上得到特別高的准確率,也會影響測試集的准確率。
----------------尋找最優參數 C 和 σ-----------------
一:SVM模型有兩個非常重要的參數C與σ
(一)其中 C是懲罰系數,即對誤差的寬容度。
1.c越高,入越小,容易過擬合。說明越不能容忍出現誤差,
2.C越小,入越大,容易欠擬合。說明可以容忍出現誤差,
C過大或過小,泛化能力變差
(二)σ隱含地決定了數據映射到新的特征空間后的分布
gamma是選擇RBF函數作為kernel后,該函數自帶的一個參數。
從gamma和σ之間關系,可以看出。gamma也隱含地決定了數據映射到新的特征空間后的分布
1.如果gamma設的太大,σ會很小,σ很小的高斯分布長得又高又瘦, 會造成只會作用於支持向量樣本附近,對於未知樣本分類效果很差,存在訓練准確率可以很高,(如果讓σ無窮小,則理論上,高斯核的SVM可以擬合任何非線性數據,但容易過擬合)而測試准確率不高的可能,就是通常說的過訓練;
2.而如果gamma設的過小,σ會很大,則會造成平滑效應太大,無法在訓練集上得到特別高的准確率,也會影響測試集的准確率。
二:加載數據及數據可視化
(一)繪制數據(訓練集數據)
def plot_data(X,y): posX = X[np.where(y==1)] #獲取正樣本 negX = X[np.where(y==0)] #獲取負樣本 plt.scatter(posX[:,0],posX[:,1],c='b',marker='X') #散點圖繪制 正樣本 plt.scatter(negX[:,0],negX[:,1],c='r',marker='o') #散點圖繪制 負樣本
data = sio.loadmat("ex6data3.mat") X = data['X'] y = data['y'].flatten()
X = data['X']
y = data['y'].flatten()
Xval = data['Xval']
yval = data['yval'].flatten()
m = y.size
plt.figure()
plot_data(X,y)
plt.show()
(二)獲取數據最值
print(np.min(X[:,0]),np.max(X[:,0])) #-0.596774 0.297235 print(np.min(X[:,1]),np.max(X[:,1])) #-0.657895 0.573392
這里我們取橫軸(-0.6,0.4),豎軸(-0.7,0.6)
三:根據驗證集評分獲取最優准確率和參數(C、σ)
def get_best_params(X,y,Xval,yval): # C 和 σ 的候選值 Cvalues = [3, 10, 30, 100, 0.01, 0.03, 0.1, 0.3, 1] # 9 gammas = [1, 3, 10, 30, 100, 0.01, 0.03, 0.1, 0.3] # 9 best_score = 0 #用於存放最佳准確率 best_params = (0,0) #用於存放參數C和σ for c in Cvalues: for gamma in gammas: clf = svm.SVC(c,kernel='rbf',gamma=gamma) clf.fit(X,y) # 用訓練集數據擬合模型 score = clf.score(Xval,yval) # 用驗證集數據進行評分 if score > best_score: best_score = score best_params = (c,gamma) return best_score,best_params
score, params = get_best_params(X,y,Xval,yval) print("score:\n",score) print("C gamma:\n",params)
注意:獲取到的最優參數組合不只有一組(可能有多組的評分一樣,都是最優,這里我們使用了>,所以只取了第一個最優的),更改候選值的順序,最佳參數組合及其對應的決策邊界也會改變。
四:根據我們獲得的最優參數,繪制決策邊界
#繪制決策邊界 def plot_boundary(model): x_min,x_max = -0.6,0.4 y_min, y_max = -0.7,0.6 # 生成網格點坐標矩陣 xx,yy = np.meshgrid(np.linspace(x_min,x_max,500), #xx (500, 500) yy (500, 500) np.linspace(y_min,y_max,500)) # print(xx.shape,yy.shape) # print(np.c_[xx.flatten(), yy.flatten()].shape) #(250000, 2)--->對應了網格點坐標矩陣中的每一個坐標點 # 用訓練好的分類器去預測各個坐標點中的數據的標簽為[1]的值(其他為0)---全為1的位置就是決策邊界 z = model.predict(np.c_[xx.flatten(), yy.flatten()]) #z (250000,) # print(z.shape) # for i in range(z.size): #z中全為0、1值 # if z[i] != 0: # print(z[i]) zz = z.reshape(xx.shape) #將我們預測出來的z值有一維空間,轉換為二維網格坐標矩陣,便於在二維平面繪制決策邊界 plt.contour(xx, yy, zz) #繪制決策邊界 xx,yy是矩陣坐標,zz是我們對各個坐標的賦值,其中為1 的地方就是我們要找的決策邊界
data = sio.loadmat("ex6data3.mat") X = data['X'] y = data['y'].flatten() Xval = data['Xval'] yval = data['yval'].flatten() score, params = get_best_params(X,y,Xval,yval) c = params[0] gamma = params[1] clf = svm.SVC(c,kernel="rbf",gamma=gamma) #實例化分類器,C為誤差項懲罰系數,核函數選擇線性核,停止訓練的誤差值大小,默認為1e-3。https://blog.csdn.net/weixin_41990278/article/details/93137009 clf.fit(X,y) #導入數據進行訓練 plt.figure() plot_boundary(clf) plot_data(X,y) plt.show()