一、基礎理解
- 決策邊界:在特征空間內,根據不同特征對樣本進行分類,不同類型間的分界就是模型針對該數據集的決策邊界。
- 決策邊界,用於分類問題中,通過決策邊界可以更好的可視化分類結果;
- 在二維特征空間中,決策邊界為一條直線,理論上,在該直線上 θ.T.x = 0,但實際上不一定存在這樣的樣本點;
- 通過決策邊界可以直接根據樣本在特征空間的位置對該樣本的類型進行預測;
- 滿足決策邊界條件的樣本點,分為哪一類都可以,但實際應用中很少發生;
- 作用:得到一個模型后,可以直接繪制該模型的決策邊界,然后再繪制出需要預測的樣本點,根據樣本點相對於特征空間中的決策邊界的分布,直接預測樣本的類型;
- 通過決策邊界可以直接根據樣本在特征空間的位置對該樣本的類型進行預測;
- 決策:根據樣本發生概率 p 的值,到底將該樣本分為哪一類?
- 邊界:
- 1)函數 σ(t) 的特點,t > 0 時σ(t) > 0.5(也就是 P > 0.5);t < 0 時σ(t) < 0.5(也就是 P < 0.5);
- 2)也就是 ý 的最終預測結果,由 θT.xb 決定,決定的邊界條件就是 θT.xb = 0;
二、兩種特征的數據集的決策邊界(限線性回歸、邏輯回歸)
- 二維特征空間中,決策邊界是一條理論上的直線,該直線是有線性模型的系數和截距決定的,並不一定有樣本滿足此條件;
- 如果樣本只有兩個特征,決策邊界可以表示為:
- θT.xb = θ0 + θ1.x1 + θ2.x2 = 0,則該邊界是一條直線,因為分類問題中特征空間的坐標軸都表示特征;
- 則有:
;
1)在二維特征空間中繪制決策邊界
-
模擬數據集並繪制
import numpy as np import matplotlib.pyplot as plt from sklearn import datasets iris = datasets.load_iris() X = iris.data y = iris.target X = X[y<2, :2] y = y[y<2] plt.scatter(X[y==0, 0], X[y==0, 1], color='red') plt.scatter(X[y==1, 0], X[y==1, 1], color='blue') plt.show()
-
用自己的邏輯回歸算法訓練模型並繪制模型針對模擬數據集的決策邊界
from playML.train_test_split import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, seed=666) from playML.LogisticRegression import LogisticRegression log_reg = LogisticRegression() log_reg.fit(X_train, y_train) # x2()函數:求滿足決策邊界關系的直線的函數值; def x2(x1): return (-log_reg.coef_[0] * x1 - log_reg.intercept_) / log_reg.coef_[1] x1_plot = np.linspace(4, 8, 1000) x2_plot = x2(x1_plot) plt.scatter(X[y==0, 0], X[y==0, 1], color='red') plt.scatter(X[y==1, 0], X[y==1, 1], color='blue') plt.plot(x1_plot, x2_plot) plt.show()
三、不規則的決策邊界的繪制方法
- 思路:特征空間中分布着無數的點,通過細分,將特征空間分割無數的點,對於每一個點都使用模型對其進行預測分類,將這些預測結果繪制出來,不同顏色的點的邊界就是分類的決策邊界;
- 分割方法:將特征空間的坐標軸等分為 n 份(可視化時只顯示兩種特征),則特征空間被分割為 n X n 個點(每個點相當於一個樣本),用模型預測這 n2 個點的類型,經預測結果(樣本點)顯示在特征空間;
1) 將繪制決策邊界的代碼封裝起來
-
# plot_decision_boundary()函數:繪制模型在二維特征空間的決策邊界; def plot_decision_boundary(model, axis): # model:算法模型; # axis:區域坐標軸的范圍,其中 0,1,2,3 分別對應 x 軸和 y 軸的范圍; # 1)將坐標軸等分為無數的小點,將 x、y 軸分別等分 (坐標軸范圍最大值 - 坐標軸范圍最小值)*100 份, # np.meshgrid(): x0, x1 = np.meshgrid( np.linspace(axis[0], axis[1], int((axis[1]-axis[0])*100)).reshape(-1,1), np.linspace(axis[2], axis[3], int((axis[3]-axis[2])*100)).reshape(-1,1) ) # np.c_(): X_new = np.c_[x0.ravel(), x1.ravel()] # 2)model.predict(X_new):將分割出的所有的點,都使用模型預測 y_predict = model.predict(X_new) zz = y_predict.reshape(x0.shape) # 3)繪制預測結果 from matplotlib.colors import ListedColormap custom_cmap = ListedColormap(['#EF9A9A','#FFF59D','#90CAF9']) plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)
四、繪制不同模型的決策邊界(使用模擬的數據集訓練模型)
1)繪制邏輯回歸算法的模型的決策邊界
-
plot_decision_boundary(log_reg, axis=[4, 7.5, 1.5, 4.5]) plt.scatter(X[y==0, 0], X[y==0, 1], color='red') plt.scatter(X[y==1, 0], X[y==1, 1], color='blue') plt.show()
- 兩種色塊就是將特征空間分割成 n2 個樣本點的分類結果;兩種色塊的分界線就是該模型的決策邊界;
2)繪制 kNN 算法的模型的決策邊界( 2 種樣本)
-
from sklearn.neighbors import KNeighborsClassifier knn_clf = KNeighborsClassifier() knn_clf.fit(X_train, y_train) plot_decision_boundary(knn_clf, axis=[4, 7.5, 1.5, 4.5]) plt.scatter(X[y==0, 0], X[y==0, 1]) plt.scatter(X[y==1, 0], X[y==1, 1]) plt.show()
3)繪制 kNN 算法的模型的決策邊界( 3 種樣本)
-
代碼
knn_clf_all = KNeighborsClassifier() knn_clf_all.fit(iris.data[:,:2], iris.target) # 輸出:KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski', metric_params=None, n_jobs=1, n_neighbors=5, p=2, weights='uniform') plot_decision_boundary(knn_clf_all, axis=[4, 8, 1.5, 4.5]) plt.scatter(iris.data[iris.target==0,0], iris.data[iris.target==0,1]) plt.scatter(iris.data[iris.target==1,0], iris.data[iris.target==1,1]) plt.scatter(iris.data[iris.target==2,0], iris.data[iris.target==2,1]) plt.show()
- 問題
- 決策邊界不規則,圖中黃色區域和藍色區域的界限不明顯;
- 黃色區域存在綠色的點,藍色區域存在橙色的點;
- 原因:模型可能過擬合;
- 方案:重新調整參數訓練模型;
- n_neighbors=5,模型的 k 參數選擇了 5,太小,導致模型太復雜;(kNN 算法中,k 值越小模型越復雜)
-
更改 k 參數,重新繪制
knn_clf_all = KNeighborsClassifier(n_neighbors=50) knn_clf_all.fit(iris.data[:,:2], iris.target) # 輸出:KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski', metric_params=None, n_jobs=1, n_neighbors=50, p=2, weights='uniform') plot_decision_boundary(knn_clf_all, axis=[4, 8, 1.5, 4.5]) plt.scatter(iris.data[iris.target==0,0], iris.data[iris.target==0,1]) plt.scatter(iris.data[iris.target==1,0], iris.data[iris.target==1,1]) plt.scatter(iris.data[iris.target==2,0], iris.data[iris.target==2,1]) plt.show()