1.0 决策边界
1.1 什么是决策边界
以logistic回归为例,当求得参数之后,那么对于每一个个例
,都可以通过代入下式的sigmoid函数对其结果进行预测,函数结果为定义的事件
概率值
,当
,则认为事件可以发生记为1,否则事件不发生,记为0。
事件的发生结果以概率值作为分界判断,而此时的
即为决策边界(decision boundary ),即
。那么当
时,
,则
;反之
时,
,则
。
而实际为一条直线。假设特征
只有两个变量
时,那么决策边界可改写为
,于是有
,这样就可以在二维坐标空间中进行绘制。
1.2 决策边界可视化
以sklearn中的鸢尾花数据集为例,观察logistics回归的决策划分。
1.2.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] # 取标签为0,1的数据,取特征的前两个,
y = y[y<2] # 取标签0,1
plt.scatter(X[y==0,0], X[y==0,1], color="red") # 绘制标签为0的数据点
plt.scatter(X[y==1,0], X[y==1,1], color="blue") # 绘制标签为1的数据点
plt.show()

1.2.2 逻辑回归
然后使用逻辑回归进行分类:
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
log_reg = LogisticRegression()
log_reg.fit(X_train, y_train)
log_reg.coef_ # 输出array([ 3.01749692, -5.03046934])
log_reg.intercept_ # 输出-0.6827383698993108
1.2.3 绘制决策边界
按照绘制决策边界
def decision_boundary(x1): # 定义决策边界函数
x2 = (-log_reg.intercept_ - log_reg.coef_[0] * x1) / log_reg.coef_[1]
return x2
x1 = np.linspace(4,8,500) # 生成决策边界的横轴数据
x2 = decision_boundary(x1) # 生成决策边界的纵轴数据
plt.plot(x1, x2) # 绘制决策边界
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.legend(('dcsn_bdry', 'Label 0', 'Label 1'))
plt.show()

上图中的浅蓝色直线就是该分类模型中决策边界,直线上方分类为0,直线下方分类为1。
2.0 逻辑回归的非线性决策边界
决策边界实际就是能够把样本正确分类的一条界线,主要有线性决策边界(linear decision boundaries)和非线性决策边界(non-linear decision boundaries)。对于上图中的浅蓝色的直线可以比较完美地将数据分成两类,但是直线的分类方式通常过于简单,实际中遇到更多为复杂的非线性情况。
( 注意:决策边界是假设函数的属性,由参数决定,而不是由数据集的特征决定。)
下面举例一个非线性决策边界的情况:
np.random.seed(666)
X = np.random.normal(0,1,(200,2)) # 生成200在0,1之间的点
y = np.array((X[:,0]**2+X[:,1]**2)<1.5, dtype='int') # 半径在1.5以内的标签为1,其他为0
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.legend(('Label 0', 'Label 1'))
plt.show()

根据上图的数据集进行逻辑回归。从上图可以判断,逻辑回归的决策边界接近于一个圆形,因此决策边界的函数应该和圆的函数非常接近,是二次项构成的。因此构建二次多项式logistics回归:
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
def plot_decision_boundary(model, axis): # 定义决策边界绘制函数
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),
)
X_new = np.c_[x0.ravel(), x1.ravel()]
y_predict = model.predict(X_new)
zz = y_predict.reshape(x0.shape)
from matplotlib.colors import ListedColormap
custom_cmap = ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)
def PolynomialLogisticRegression(degree): # 定义多项式logistics回归
return Pipeline([
("poly", PolynomialFeatures(degree)),
("std_scaler", StandardScaler()),
("log_reg", LogisticRegression())
])
poly_log_reg = PolynomialLogisticRegression(degree=2) # 建立二次多项式logistics回归实例
poly_log_reg.fit(X,y)
poly_log_reg.score(X, y) # 输出0.97
plot_decision_boundary(poly_log_reg, axis=[-4, 4, -4, 4])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()

上图通过二次多项式得到了较好的决策边界。但实际情况很难通过图形直接判断决策边界函数适合的多项式次数。此时可以设置较大的次数,再通过正则化提高分类结果的准确性。
3.0 逻辑回归和正则化
依然使用上一章的数据作为示例。
3.1 准备数据
在上一章数据进行修改,增加部分噪音数据:
np.random.seed(666)
X = np.random.normal(0, 1, size=(200, 2))
y = np.array((X[:,0]**2+X[:,1])<1.5, dtype='int')
for _ in range(20): # 随机将20个点的标签设为1,作为噪音
y[np.random.randint(200)]=1
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()

3.2 逻辑回归(线性)
首先建立线性的逻辑回归模型:
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
log_reg3 = LogisticRegression() # logistic回归的实例化
log_reg3.fit(X_train, y_train)
log_reg.score(X_train, y_train) # 输出0.7933333333333333
log_reg.score(X_test, y_test) # 输出0.86

上图logistic回归实例化的输出内容中,有几个参数需要注意下。首先“c=1.0”,这里c为超参数,但逻辑回归的正则化中,超参数是加在函数项而非惩罚项,即,这里与一般正则化的形式不太一样,需要注意。其次“penalty='l2'”,意思是惩罚项采用的L2正则化。
3.3 可视化决策边界
在回归模型的基础上可视化决策边界:
plot_decision_boundary(log_reg3, axis=[-4, 4, -4, 4])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()

3.4 逻辑回归(多项式)并可视化决策边界
对上述数据建立多项式逻辑回归模型:
poly_log_reg2 = PolynomialLogisticRegression(degree=2)
poly_log_reg2.fit(X_train, y_train)
poly_log_reg2.score(X_train, y_train) # 输出0.9133333333333333
poly_log_reg2.score(X_test, y_test) # 输出0.94
plot_decision_boundary(poly_log_reg2, axis=[-4, 4, -4, 4])
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()

上图可以明显看出多项式回归下的决策边界分界效果明显要比线性分界要好,这一点从score值也可以看出来。
3.5 逻辑回归(高次多项式)和正则化
建立高次多项式的逻辑回归,如20次,决策边界可视化如下。这强烈不规则的边界必然带来的过拟合。下面就在这个过拟合的基础上加入正则化。

3.5.1 L1正则化
构建高次(20)多项式的逻辑回归,增加L1正则化。从决策边界可视化结果看出,虽然分类准确率没有非常高,但是没有过拟合,且分类决策边界非常接近原本的真实数据了。
def PolynomialLogisticRegression2(degree, C, penalty): # 定义含惩罚项参数的多项式逻辑回归模型
return Pipeline([
("poly", PolynomialFeatures(degree=degree)),
("std_scaler", StandardScaler()),
("log_reg", LogisticRegression(C=C, penalty=penalty))
])
poly_log_reg4 = PolynomialLogisticRegression2(degree=20, C=0.1, penalty='l1') # 超参数0.1,l1正则化
poly_log_reg4.fit(X_train, y_train)
poly_log_reg4.score(X_train, y_train) # 输出0.8266666666666667
poly_log_reg4.score(X_test, y_test) # 输出0.9
plot_decision_boundary(poly_log_reg4, axis=[-4, 4, -4, 4])
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()
