用Python描畫分類模型的決策邊界
在做數據分析時,經常需要採集少量的樣本數據查看數據的分布狀況,根據數據的特徵選擇適當的機器學習演算法。Python語言精鍊,通過很少的代碼即可完成複雜的功能,非常適合完成調研階段的數據分析處理,給用戶製作Demo。在訓練數據分類模型時,將數據以圖形的形式展現出來,更能直觀地理解數據的分布情況,便於說明和講解。
一、數據的三維描畫
顯示中的數據集通常包含多個特徵,我們無法對三維以上的數據進行直接的描畫,即使三維的數據描畫也不常用,因為通過3D的立體數據展現通常很難直觀觀察出數據的關聯和特徵。最常用的是描畫二維的數據圖形,對於多維度的數據,通常通過主成分分析法(PCA)等對數據進行降維,然後將數據描畫出來。使用python描畫3D圖形,可以使用Axes3D。
例:
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from mpl_toolkits.mplot3d import Axes3D
iris = datasets.load_iris()
X = iris.data
y = iris.target
ax = plt.subplot(111, projection="3d")
ax.scatter(X[:, 0], X[:, 1], X[:, 2], c=y, cmap=plt.cm.Paired, edgecolor="k", s=20)
plt.show()
導入Axes3D後,需要指定projection為3d模式,然後通過scatter方法描畫散點圖。
scatter的前三個參數分別為數據點所在的x軸、y軸和z軸的坐標;c參數指定數據點的顏色,這裡使用顏色應色(ColorMap)的方式指定數據的的顏色,方法是將c參數設置為y,即數據類別的值,cmap參數設置Paired,這樣在描畫圖形時系統會自動選用較為接近的顏色,然後將這些顏色分別映射到c參數制定的y的每一種值上。在當前的數據集中共有三種類別的數據,所以系統會選擇三個接近的顏色分別映射給三中類別,相同類別的數據點會被描畫成相同的顏色。
edgecolor參數制定圖形的輪廓,k表示使用黑色;s制定數據點的大小。
描畫的結果如下:
通過滑鼠拖拽,可以改變觀察的角度,對圖形進行旋轉。
二、二維數據及分類決策邊界的描畫
相較於三維的圖形,二維的圖形看起來更直觀,在使用分類的機器學習模型時,通常將用作展示的小樣本數據通過二維圖形描畫出來,並在圖形中描畫訓練好的分類模型的決策邊界,這樣更便於直觀觀察和講解分類模型的效果。二在三維圖形中,基本上很難畫出三維的分割超平面。
分類模型有很多中,根據模型的演算法不同,決策邊界的描畫方法也不相同,常見的有以下幾種類別:
1、回歸模型
這類模型通常包括線性回歸、多項式回歸、嶺回歸、Lasso回歸等,這類模型的共同特點是通過使用訓練集訓練,得到一個曲面的方程,使得方程對訓練集數據有最佳的擬合,我們可以姑且將這個曲面理解為回歸模型的"決策邊界"。
因為通過訓練得到了曲面方程和最佳擬合參數,要描畫出曲面(在二維的情況下退化成曲線),只需要在一定範圍內取一定量連續的輸入值X,輸入訓練好的模型,得到模型的預測值y,將X和y所代表的傳給plot函數,plot函數即可根據這些點的分布描畫出曲線的形狀。為了和訓練集中的數據進行對比,我們在獲取連續輸入值的範圍時,以訓練集的X的數據的上下限為取值範圍。
例如,我們有如下包含五個數據點的訓練集:
通過直觀的觀察,如果使用線性回歸,偏差將會很大,需要使用多項式回歸;另外,y軸的數據存在起伏波動,如果使用二次多項式,估計也不能很好擬合。因此初步判斷,需要使用三次多項式進行擬合,示例代碼如下:
import numpy as np
from sklearn import datasets
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
import matplotlib.pyplot as plt
diabets = datasets.load_diabetes()
X = diabets.data
y = diabets.target
X_train = X[:5, np.newaxis, 2];
y_train = y[:5]
poly_featurizer = PolynomialFeatures(degree=3)
X_train_poly = poly_featurizer.fit_transform(X_train)
clf = LinearRegression()
clf.fit(X_train_poly, y_train)
X_plot = np.linspace(X_train.min(), X_train.max(), 100)[:, np.newaxis]
X_plot_poly = poly_featurizer.fit_transform(X_plot)
y_plot = clf.predict(X_plot_poly)
plt.scatter(X_train, y_train)
plt.plot(X_plot, y_plot)
plt.show()
首先看一下擬合的結果:
可見,曲線對訓練集數據進行了較好的擬合。
以上處理過程大致分為一下幾個步驟:
(1)引入多項式特徵生成器並生成高次特徵
多項式回歸本質上也是線性回歸,不同的是對特徵值進行了處理,將原始的特徵值處理成了二次或更高次,從而獲得更好擬合自由度。如果將高次的特徵值看做是初始的訓練數據,則處理過程和線性回歸相同。
(2)使用生成的高次特徵對模型進行訓練
(3)獲取訓練集的上下限範圍,生成描畫擬合曲線使用的X值
這裡首先使用min和max方法獲取訓練數據的最大值和最小值,確定生成數據的邊界;然後使用linspace方法在確定的範圍內生成等差數列,等差數列的個數指定為100,數據點個數越大,描畫出的曲線越精細。
生成的等差數列是一個一維的數組,和plot函數即可接收一維數組也可以接受(2, 1)的兩維數組做為參數不同,線性回歸模型需要的參數是二維數組,其中行方向上是樣本,有多少個樣本就有多少行;列方向上是特徵,有多少個特徵就有多少列。因此需要對等差數列進行轉換。對維度進行轉化可以使用reshape方法,分別制定轉換目標的維度的長度,也可以使用numpy.newaxis,給數組添加維度。
In [47]: test = np.linspace(1, 9, 9)
In [48]: test
Out[48]: array([1., 2., 3., 4., 5., 6., 7., 8., 9.])
In [49]: test = test.reshape(3, 3)
In [50]: test
Out[50]:
array([[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.]])
In [51]: test[:, np.newaxis]
Out[51]:
array([[[1., 2., 3.]],
[[4., 5., 6.]],
[[7., 8., 9.]]])
In [52]: test[np.newaxis, :]
Out[52]:
array([[[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.]]])
通過這個示例可以看出,對數組進行維度變換,可以使用reshape方法直接制定要轉換到的目標的各個維度的長度,返回新的數組。而使用numpy.newaxis是在原始數組的基礎上添加維度,共有兩種添加維度的方法:一種是[:, np.newaxis]的寫法,給最外層中括弧中的每一個元素添加一層[];另一種是[np.newaxis, :],給最外一層中的所有元素統一加一層[]。
在閱讀多維數組的表示時,可以從最內層中括弧讀起,中括弧中元素的個數是一個維度的長度,嵌套的層數是維度的總層數。
綜上,新添加的維度是新數組的倒數第二個維度,而在第一種寫法時,因為給每一個元素都單獨加上了[],因此倒數第二維的長度為1,shape輸出為(3,1,3);第二種寫法時,因為給最外一層中的所有元素都加上了一個[],所以倒數第二層的維度長度為3,shape輸出為(1, 3, 3)。
(4)對生成的等差數列數據生成三次特徵
(5)使用訓練好的模型對步驟4中的數據進行預測,得到y值
(6)將訓練數據通過散點圖描畫在圖中,用等差數列值和對應的預測y值描畫擬合曲線,得到最終結果。
2. 基於閾值的分類模型
這類分類模型主要包括邏輯回歸、感知機、kNN等模型,這類模型的特點是通過訓練,得到模型參數,通過閾值對數據進行分類。但是例如邏輯回歸,雖然是基於線性方程的模型,但是需要通過sigmoid函數激活後獲得結果值作為分類的依據,因此,決策邊界不能直接通過線性方程代入連續的值來描畫決策邊界。
描畫這類模型的決策邊界,需要在x軸和y軸兩個方向上生成數據點陣,使用訓練好的模型,對點陣中的每一個數據點進行預測,獲得其類別,然後對相同類別的數據區域描畫相同的顏色。
示例如下:
import numpy as np
from sklearn import datasets
import matplotlib as mpl
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression
iris = datasets.load_iris()
X = iris.data[:, :2]
y= iris.target
clf = LogisticRegression(C=1e5)
clf.fit(X, y)
x_min = X[:, 0].min()
x_max = X[:, 0].max()
y_min = X[:, 1].min()
y_max = X[:, 1].max()
x_plot, y_plot = np.mgrid[x_min:x_max:200j, y_min:y_max:200j]
z_plot = clf.predict(np.c_[x_plot.ravel(), y_plot.ravel()])
z_plot = z_plot.reshape(200, 200)
cm_dark = mpl.colors.ListedColormap(["g", "r", "b"])
plt.pcolormesh(x_plot, y_plot, z_plot, cmap=plt.cm.Paired)
plt.scatter(X[:,0], X[:,1], c=y, cmap=cm_dark)
plt.show()
生成的圖形如下:
從圖中數據點的分布可以看出,綠色的數據點容易與其它數據點分割開來,紅色和藍色的數據點較難分割。通過訓練得到的模型也是較好的分割了綠色的數據點,紅色和藍色數據點分割上會有較大的誤差。
描畫Logistic回歸的步驟如下:
(1)構造訓練數據和訓練模型
因為我們是描畫二維數據和決策邊界作為示例,所以選取數據集中的前兩個特徵作為訓練數據。構造模型時,將C參數設置為10的5次方,對模型的擬合程度進行調節。
(2)構造用於描畫決策邊界的網格數據
要構造邏輯回歸的決策邊界,需要在x軸和y軸兩個方向上構造網格數據點,之後用訓練好的模型對生成的這些數據點進行預測,將預測結果相同的數據點所在的區域範圍描畫成相同的顏色,這樣就能看出不同類別之間的邊界了。為了與訓練數據進行對比,我們取x軸和y軸的數據分為分別為訓練數據的第一個特徵和第二個特徵的上下限。
構造網格數據,可以使用mgrid函數,mgrid函數生成雙矩陣,其傳入參數和返回值的對應關係如下:
第一組參數指定x軸的數據分布範圍和長度,第二組參數指定y軸上的數據分布範圍和長度。可以結合下圖進行理解:
我們需要生成的數據點陣大致如上圖所示,其中每一個點都包含x和y兩個數據坐標值,mgrid的返回值是將每個點的x和y坐標值分別放入了兩個矩陣中。
第一個矩陣的行方向對應x軸方向上的數據變化,每一行的數據值都相同,列數等於y軸上數據的個數;
第二個矩陣的列方向對應y軸方向上的數據變化,每一列的數據值都相同,列數等於x軸上數據的數。
(3)對網格數據進行分類預測
在對網格數據點進行預測時,首先需要將兩個網格矩陣的數據合併成(x, y)形式的數據樣本格式,並生成二維的樣本數據矩陣,樣本矩陣格式為兩維矩陣,行方向是樣本的個數,列方向上是各個特徵值。
將網格數據合併成(x, y)樣本數據格式,首先使用ravel函數將矩陣轉換為一維矩陣,然後使用c_函數將兩個一維矩陣在列方向上合併,生成二維矩陣。
(4)根據數據預測結果,對相同類別的數據區域描畫相同的顏色
和上一個例子一樣,使用cmap參數將分類值映射為一個顏色,使用pcolormesh函數描畫網格區域。
3. 支持向量機的決策邊界描畫
支持向量機的決策邊界描畫是比較特殊的一類。以上歸納的機種描畫方法都是通過使用訓練好的模型對一個數據範圍內的數據點進行預測,根據預測的結果描畫圖形,而支持向量機是以支持向量和函數距離為基礎的分類演算法,因此在描畫決策邊界時,可以使用函數距離描畫等高線作為決策邊界。
描畫支持向量機的決策邊界的示例代碼如下:
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets, svm
iris = datasets.load_iris()
X = iris.data
y = iris.target
X = X[y != 0, :2]
y = y[y != 0]
n_sample = len(X)
X = X[order]
y = y[order].astype(np.float)
X_train = X[:int(.9 * n_sample)]
y_train = y[:int(.9 * n_sample)]
X_test = X[int(.9 * n_sample):]
y_test = y[int(.9 * n_sample):]
# fit the model
for fig_num, kernel in enumerate(("linear", "rbf", "poly")):
clf = svm.SVC(kernel=kernel, gamma=10)
clf.fit(X_train, y_train)
plt.figure(fig_num)
plt.clf()
plt.scatter(X[:, 0], X[:, 1], c=y, zorder=10, cmap=plt.cm.Paired,
edgecolor="k", s=20)
# Circle out the test data
plt.scatter(X_test[:, 0], X_test[:, 1], s=80, facecolors="none",
zorder=10, edgecolor="k")
plt.axis("tight")
x_min = X[:, 0].min()
x_max = X[:, 0].max()
y_min = X[:, 1].min()
y_max = X[:, 1].max()
XX, YY = np.mgrid[x_min:x_max:200j, y_min:y_max:200j]
Z = clf.decision_function(np.c_[XX.ravel(), YY.ravel()])
# Put the result into a color plot
Z = Z.reshape(XX.shape)
plt.pcolormesh(XX, YY, Z > 0, cmap=plt.cm.Paired)
plt.contour(XX, YY, Z, colors=["k", "k", "k"],
linestyles=["--", "-", "--"], levels=[-.5, 0, .5])
plt.title(kernel)
plt.show()
支持向量機根據使用的核函數的不同會生成不同的模型結果,大多數SVM庫內置了流行的核函數,比如多項式(Polynomial)、徑向基函數(Radial Basis Function,RBF)、Sigmoid。當我們不進行投影時(比如本文的第一個例子),我們直接在原始空間計算點積——我們把這叫做使用線性核(linear kernel)在使用線性核函數、多項式核函數和RBF內核(徑向基函數)作為核函數時,決策邊界的效果分別如下圖所示:
描畫支持向量機的決策邊界的方法和步驟與邏輯回歸決策邊界描畫基本相同:
(1)構造訓練數據和訓練模型
這裡要注意的是我們使用y!=0條件從數據中去除了標籤為0的樣本,只保留兩種標籤的數據,也就是讓SVM做普通的二分類,這樣在後續通過decision_function函數計算決策值(函數距離)時,返回值是一維的矩陣。如果不出去標籤為0的樣本,則SVM會進行多分類,SVM在進行多分類時會採用1V1或者1VRest方式(可以通過decision_function_shape參數指定),這中情況下decision_function函數會返回內部每個子分類器的決策值。所以以上示例代碼只適用於二分類的決策邊界描畫,多分類時需要進行改造。
(2)構造用於描畫決策邊界的網格數據
這裡的計算步驟和上一個例子基本相同,不再贅述。
(3)對網格數據進行決策值計算
這一步和上一個例子不同,不使用pridict函數對網格數據點進行類別預測,而是使用decision_function函數計算網格數據點對應的函數距離,因為SVM模型是根據樣本點到超平面的函數距離作為分類依據的。
(4)根據決策值計算結果,對相同類別的數據區域描畫相同的顏色
因為是二分類模型,所以根據計算的函數距離是否大於0對所有的函數距離計算結果進行顏色映射。最後,使用等高線描畫函數contour描畫超平面對應的等高線。


※想要更換和手機殼一樣的顏色主題?教你用幾行Python代碼輕鬆搞定
※使用Python進行人臉聚類的詳細教程
TAG:Python |