Python 解決線性及非線性SVM決策過程的可視化

關注微信公共號:小程在線

關注CSDN博客:程志偉的博客

使用sklearn中的式子來爲可視化我們的決策邊界,支持向量,以及決策邊界平行的兩個超平面。

 

1. 導入需要的模塊

from sklearn.datasets import make_blobs
from sklearn.svm import SVC
import matplotlib.pyplot as plt
import numpy as np

 

2. 實例化數據集,可視化數據集

X,y = make_blobs(n_samples=50, centers=2, random_state=0,cluster_std=0.6)

plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")
plt.xticks([])
plt.yticks([])
plt.show()

可以看出數據的分類呈現出2類

 

3. 畫決策邊界:理解函數contour
matplotlib.axes.Axes.contour([X, Y,] Z, [levels], **kwargs)Contour是我們專門用來繪製等高線的函數。等高線,本質上是在二維圖像上表現三維圖像的一種形式,其中兩維X和Y是兩條座標軸上的取值,而Z表示高度。Contour就是將由X和Y構成平面上的所有點中,高度一致的點連接成線段的函數,在同一條等高線上的點一定具有相同的Z值。我們可以利用這個性質來繪製我們的決策邊界。

參數 含義
X,Y 選填。兩維平面上所有的點的橫縱座標取值,一般要求是二維結構並且形狀需要與Z相同,往往通
過numpy.meshgrid()這樣的函數來創建。如果X和Y都是一維,則Z的結構必須爲(len(Y), len(X))。
如果不填寫,則默認X = range(Z.shape[1]),Y = range(Z.shape[0])。
Z 必填。平面上所有的點所對應的高度。
levels 可不填,不填默認顯示所有的等高線,填寫用於確定等高線的數量和位置。如果填寫整數n,則顯
示n個數據區間,即繪製n+1條等高線。水平高度自動選擇。如果填寫的是數組或列表,則在指定
的高度級別繪製等高線。列表或數組中的值必須按遞增順序排列

我們只需要在我們的樣本構成的平面上,把所有到決策邊界的距離爲0的點相連,就是我們的決策邊界,而把所有到決策邊界的相對距離爲1的點相連,就是我們的兩個平行於決策邊界的超平面了。此時,我們的Z就是平面上的任意點到達超平面的距離。

plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")
ax = plt.gca() #獲取當前的子圖,如果不存在,則創建新的子圖

4. 畫決策邊界:製作網格,理解函數meshgrid
#獲取平面上兩條座標軸的最大值和最小值
xlim = ax.get_xlim()
ylim = ax.get_ylim()

 

#在最大值和最小值之間形成30個規律的數據

axisx = np.linspace(xlim[0],xlim[1],30)
axisy = np.linspace(ylim[0],ylim[1],30)
axisx,axisy = np.meshgrid(axisx,axisy)

#我們將使用這裏形成的二維數組作爲我們contour函數中的X和Y
#使用meshgrid函數將兩個一維向量轉換爲特徵矩陣
#核心是將兩個特徵向量廣播,以便獲取y.shape * x.shape這麼多個座標點的橫座標和縱座標

 

 

xy = np.vstack([axisx.ravel(), axisy.ravel()]).T
#其中ravel()是降維函數,vstack能夠將多個結構一致的一維數組按行堆疊起來
#xy就是已經形成的網格,它是遍佈在整個畫布上的密集的點
plt.scatter(xy[:,0],xy[:,1],s=1);

可以看出一共有900個點

a = np.array([1,2,3])
b = np.array([7,8])

a,b
Out[8]: (array([1, 2, 3]), array([7, 8]))

v1,v2 = np.meshgrid(a,b)
v1
Out[9]: 
array([[1, 2, 3],
       [1, 2, 3]])

v2
Out[10]: 
array([[7, 7, 7],
       [8, 8, 8]])

v = np.vstack([v1.ravel(), v2.ravel()]).T
v
Out[11]: 
array([[1, 7],
       [2, 7],
       [3, 7],
       [1, 8],
       [2, 8],
       [3, 8]])

 

5. 建模,計算決策邊界並找出網格上每個點到決策邊界的距離

有了網格後,我們需要計算網格所代表的“平面上所有的點”到我們的決策邊界的距離。所以我們需要我們的模型和決策邊界。
建模,計算決策邊界並找出網格上每個點到決策邊界的距離:
#建模,通過fit計算出對應的決策邊界
clf = SVC(kernel = "linear").fit(X,y)
Z = clf.decision_function(xy).reshape(axisx.shape)

#重要接口decision_function,返回每個輸入的樣本所對應的到決策邊界的距離
#然後再將這個距離轉換爲axisx的結構,這是由於畫圖的函數contour要求Z的結構必須與X和Y保持一致
#畫決策邊界和平行於決策邊界的超平面

plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")
ax = plt.gca() #獲取當前子圖
ax.contour(axisx,axisy,Z
    ,colors="k"
    ,levels=[-1,0,1] #畫三條等高線,分別是Z爲-1,Z爲0和Z爲1的三條線
    ,alpha=0.5
    ,linestyles=["--","-","--"])
ax.set_xlim(xlim)
ax.set_ylim(ylim)
plt.show()

 

Z的本質麼是輸入的樣本到決策邊界的距離,而contour函數中的level其實是輸入了這個距離,現在讓我們找一個點來試試
#以第10號樣本爲例,以黑色表示

plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")
plt.scatter(X[10,0],X[10,1],c="black",s=100);

 

#計算第10號樣本到決策邊界的距離

clf.decision_function(X[10].reshape(1,2))
Out[15]: array([-3.33917354])

 

#繪製決策邊界

plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")
plt.scatter(X[10,0],X[10,1],c="black",s=100)
ax = plt.gca()
ax.contour(axisx,axisy,Z
            ,colors="k"
            ,levels=[-3.33917354]
            ,alpha=0.5
            ,linestyles=["--"]);

6. 將繪圖過程包裝成函數
#將上述過程包裝成函數:
def plot_svc_decision_function(model,ax=None):
    if ax is None:
        ax = plt.gca()
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()
    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=["--","-","--"])
    ax.set_xlim(xlim)
    ax.set_ylim(ylim)
    plt.show()

clf = SVC(kernel = "linear").fit(X,y)
plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")
plot_svc_decision_function(clf)

 

7. 探索建好的模型
#根據決策邊界,對X中的樣本進行分類,返回的結構爲n_samples

clf.predict(X)
Out[19]: 
array([1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1,
       1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1,
       0, 1, 1, 0, 1, 0])

 

#返回給定測試數據和標籤的平均準確度

clf.score(X,y)
Out[20]: 1.0

 

#返回支持向量

clf.support_vectors_
Out[21]: 
array([[0.44359863, 3.11530945],
       [2.33812285, 3.43116792],
       [2.06156753, 1.96918596]])

 

#返回每個類中支持向量的個數

clf.n_support_
Out[22]: array([2, 1])

 

8. 推廣到非線性情況

from sklearn.datasets import make_circles
#創建環形數據
X,y = make_circles(100, factor=0.1, noise=.1, random_state=10)
X.shape
Out[23]: (100, 2)

y.shape
Out[24]: (100,)

plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")
Out[25]: <matplotlib.collections.PathCollection at 0x1e4f5b69b00>

clf = SVC(kernel = "linear").fit(X,y)
plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")
plot_svc_decision_function(clf)

現在線性SVM已經不適合於我們的狀況了,我們無法找出一條直線來劃分我們的數據集,讓直線的兩邊分別
是兩種類別。這個時候,如果我們能夠在原本的X和y的基礎上,添加一個維度r,變成三維,我們可視化這個數
據,來看看添加維度讓我們的數據如何變化。



9. 爲非線性數據增加維度並繪製3D圖像
from mpl_toolkits import mplot3d #導入3D繪圖包
#定義一個由x計算出來的新維度r
r = np.exp(-(X**2).sum(1))
#定義一個繪製三維圖像的函數
#elev表示上下旋轉的角度
#azim表示平行旋轉的角度
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='rainbow')
    ax.view_init(elev=elev,azim=azim)
    ax.set_xlabel("x")
    ax.set_ylabel("y")
    ax.set_zlabel("r")
    plt.show()

plot_3D()


 


 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章