过拟合
分类任务的本质其实是找到边界,将不同类型的数据区分开,之前我们做的是尽量让这个边界更贴近每一个数据点,达到拟合的作用。
然而,极端数据的存在或要求模型的特征数过多,会导致过拟合现象的出现。它会导致模型在训练集表现优异,但是在测试集准确率不高,这显然不是我们想要的。
术语“偏置(Bias)”和“方差(Variance)”
偏置描述了学习算法的期望预测与真实结果之间的偏差。高偏置与欠拟合成正比。
方差表示模型预测结果的波动程度,即模型在不同训练集上的预测值的变化程度。高方差与过拟合成正比。
偏置-方差权衡(Bias-Variance Tradeoff)
要控制模型的偏置和方差,避免欠拟合和过拟合的出现。
正则化
正则化的本质是引入额外信息(偏置)来惩罚极端的参数值。
常见的L1,L2正则化就是在代价函数末尾加上关于w的式子,使w过大时代价函数也会过大。
L1正则化
J ( w ⃗ ) = J 0 ( w ⃗ ) + λ ∑ j = 1 m ∣ w j ∣ J(\vec{w}) = J_{0}(\vec{w}) + \lambda\sum_{j=1}^{m}|w_{j}| J(w)=J0(w)+λ∑j=1m∣wj∣
其中 J 0 J_{0} J0是原代价函数, λ \lambda λ为正则化参数
一般将 ∑ j = 1 m ∣ w j ∣ \sum_{j=1}^{m}|w_{j}| ∑j=1m∣wj∣记作 ∣ ∣ w ⃗ ∣ ∣ 1 ||\vec{w}||^{1} ∣∣w∣∣1
L2正则化
J ( w ⃗ ) = J 0 ( w ⃗ ) + λ ∑ j = 1 m w j 2 J(\vec{w}) = J_{0}(\vec{w}) + \lambda\sum_{j=1}^{m}w_{j}^{2} J(w)=J0(w)+λ∑j=1mwj2
一般将 ∑ j = 1 m w j 2 \sum_{j=1}^{m}w_{j}^{2} ∑j=1mwj2记作 ∣ ∣ w ⃗ ∣ ∣ 2 ||\vec{w}||^{2} ∣∣w∣∣2
L1和L2的区别
L2正则化会让高次项系数趋于0,而L1正则化则会让其变成0,减少空间消耗和特征数。故在对模型稀疏度要求较高的情况下选择L1。
L1正则化函数不平滑,可能会导致优化更复杂;当特征有高度相关性时,L1正则化可能会使选择的特征不唯一。
举个例子:假设我们有两个特征
X
1
X_{1}
X1和
X
2
X_{2}
X2,它们之间的相关系数接近1,即它们几乎完全线性相关。
假设模型的目标函数(包括L1正则化项)为:
L = ∑ ( y − z ) 2 + λ ( ∣ w 1 ∣ + ∣ w 2 ∣ ) L = \sum(y-z)^{2} + \lambda(|w_{1}| + |w_{2}|) L=∑(y−z)2+λ(∣w1∣+∣w2∣)
由于 X 1 X_{1} X1和 X 2 X_{2} X2相关,模型可以通过调整 w 1 w_{1} w1和 w 2 w_{2} w2来同时减小 L 的前半部分(预测误差),并且由于L1正则化项的存在,模型可能倾向于将其中一个权重设置为零。然而,由于 X 1 X_{1} X1和 X 2 X_{2} X2的高度相关性,选择 w 1 w_{1} w1或 w 2 w_{2} w2的非零值可能不会对模型的整体性能产生显著影响,从而导致特征的选择不唯一。
代码实现改变权重系数来控制模型正则化
前置代码略,以下代码通过改变 λ \lambda λ直观展示正则化对模型系数的影响。
# 数据读入略
from sklearn.linear_model import LogisticRegression # 逻辑回归分类器
# 初始化权重和参数列表
weights, params = [], []
# 遍历对数尺度上的C参数范围 (10^-5 到 10^5)
for c in np.arange(-5, 5):
# 创建逻辑回归模型实例,设置C参数(正则化强度的倒数)
# C越大,正则化强度越低;C越小,正则化强度越高
lr = LogisticRegression(C=10.**c, random_state=1,
solver='lbfgs', # 使用L-BFGS-B算法求解
multi_class='ovr') # 多分类问题采用one-vs-rest策略
# 使用标准化后的训练数据和标签训练模型
lr.fit(X_train_std, y_train)
# 将模型的权重系数保存到列表中
weights.append(lr.coef_[1])
# 将C参数的值保存到列表中
params.append(10.**c)
# 将权重列表转换成numpy数组,便于后续操作
weights = np.array(weights)
# 使用matplotlib绘制权重系数随C参数变化的图像
plt.plot(params, weights[:, 0],
label='petal length') # 绘制花瓣长度的权重变化
plt.plot(params, weights[:, 1], linestyle='--',
label='petal width') # 绘制花瓣宽度的权重变化,使用虚线表示
# 设置图表的y轴标签为权重系数
plt.ylabel('weight coefficient')
# 设置图表的x轴标签为C参数
plt.xlabel('C')
# 设置图例位置在左上角
plt.legend(loc='upper left')
# 设置x轴为对数尺度,以清晰展示C参数的范围
plt.xscale('log')
# 展示图表
plt.show()