Python不依赖sklearn手写Ridge多项式回归时调大lambda拟合误差升高问题
Ridge多项式回归lambda增大时误差升高的解决方案
根本原因
出现lambda越大误差越高的反常表现,是两个实现逻辑错误共同导致的:
- 未对不同阶的多项式特征做标准化,导致各特征量级失衡
- 错误将*偏置项(全1的截距列)*纳入Ridge惩罚范围
当特征未做标准化时,高次多项式的特征值(如$x5$)的数值远大于低次项(如$x1$)和偏置项,$X^TX$矩阵的元素量级差可达数个数量级。此时施加相同的lambda对角惩罚,会出现两个极端问题:
- 对量级极大的高次项特征,lambda的惩罚值相对于$X^TX$本身的元素可以忽略,根本起不到收缩高次权重、抑制过拟合的作用
- 对量级极小的偏置项(全1列对应的$X^TX$元素为样本数,通常仅为几十到几百),随着lambda增大,惩罚占比快速提升,直接将偏置项的权重压缩到偏离真实值的程度,导致整个拟合曲线发生大幅平移,误差自然飙升。
原代码中用于计算最大值的逻辑、重复赋值的代码都是冗余内容,可直接删除简化。
具体修改步骤
1. 重构设计矩阵,拆分偏置项与多项式特征
将原本直接堆叠未标准化多项式的逻辑,调整为拆分偏置、单独对非偏置特征做标准化的流程:
n = 5 # 多项式阶数 m = len(xv) # 构造全1的偏置列 X_bias = np.ones((m, 1)) # 构造x^1 到 x^n 的原始多项式特征 X_poly = np.zeros((m, n)) for i in range(m): for j in range(1, n+1): X_poly[i, j-1] = xv[i] ** j # 对非偏置的多项式特征做z-score标准化 poly_mean = X_poly.mean(axis=0) poly_std = X_poly.std(axis=0) X_poly_scaled = (X_poly - poly_mean) / poly_std # 拼接为最终设计矩阵 X = np.hstack([X_bias, X_poly_scaled])
2. 修正惩罚矩阵的构造
不再使用全对角的单位矩阵施加惩罚,将偏置项对应的对角元设为0,避免对截距的错误收缩:
# 惩罚矩阵维度与设计矩阵的列数一致 penalty_matrix = np.identity(X.shape[1]) penalty_matrix[0, 0] = 0 # 偏置项不参与惩罚
3. 按修正后的逻辑计算权重、完成预测
权重计算遵循调整后的公式,预测时使用训练集阶段留存的均值、标准差参数转换输入,保证特征尺度统一:
lam = 5 XtX = X.T @ X Xty = X.T @ np.array(yv) # 对应权重公式:w = (XᵀX + λ * P)⁻¹ Xᵀy,P为修正后的惩罚矩阵 A = XtX + lam * penalty_matrix w = np.linalg.inv(A) @ Xty # 修正预测函数,保证输入转换逻辑和训练时一致 def h(c): c_poly = np.array([c**j for j in range(1, n+1)]) c_scaled = (c_poly - poly_mean) / poly_std c_all = np.hstack([1, c_scaled]) return c_all @ w hv = [h(xv[i]) for i in range(m)]
调整后的预期表现
完成以上修改后,所有非偏置的多项式特征处于相同数值尺度,lambda的惩罚可以公平作用在每个特征的权重上:lambda从0开始增大时,首先收缩高次项的权重,降低模型过拟合程度,验证集误差会先逐步下降;直到lambda过大导致模型欠拟合时,误差才会回升,完全符合Ridge回归的预期表现。
内容的提问来源于stack exchange,提问作者Mehdi M.A.
相关产品推荐
相关产品推荐

