Scikit-learn SGDRegressor无法拟合数据问题求助
解决SGDRegressor拟合不佳、系数爆炸的问题
嘿,你遇到的这个问题其实是SGDRegressor的典型痛点——特征没有做标准化处理,再加上数据里存在明显的异常值,直接导致梯度下降训练不稳定,系数疯长,根本没法收敛到合理的结果。
核心原因分析
SGD(随机梯度下降)对特征的尺度极其敏感:你的输入特征里,大部分数值都在60-90之间,但第10个样本的第一个特征是870.9,比其他特征大了一个数量级;同时目标变量y里还有2922这样的极端值,这会让梯度更新完全被大尺度的特征主导,小尺度特征的梯度信号被淹没,模型根本没法学到合理的权重,反而会因为步长(eta0=0.1)太大导致参数震荡甚至发散,最终得到离谱的系数。
而Ridge、Lasso这些模型要么自带正则化约束(限制系数大小),要么其实现(比如坐标下降)对尺度的容忍度更高,所以能得到不错的拟合得分,但其实它们也建议先做标准化来进一步提升效果。
具体解决方案
我给你整理了几个关键步骤,按顺序来就能解决问题:
1. 对特征做标准化处理
用StandardScaler对输入特征X做标准化,让每个特征的均值为0、方差为1,这是SGD类模型训练的必备前置步骤,能让所有特征的梯度更新处于同一量级,避免被大尺度特征带偏。
2. 修正/移除异常值
检查你的数据:第10个样本的第一个特征870.9大概率是输入错误(应该是87.9?),还有y里的2922也远高于其他值(其他y大多在200-1200之间),这些异常值会严重干扰模型训练,建议先修正或者移除这些样本。
3. 调整SGDRegressor的参数
- 不要用
learning_rate="constant",固定步长很容易导致震荡,建议用"adaptive"或者"invscaling",让步长随着训练逐渐减小,帮助模型收敛。 - 加上正则化!SGDRegressor默认是没有正则化的(
penalty=None),加上penalty="l2"(和Ridge一致)或者"l1"(和Lasso一致),既能约束系数大小,又能提升泛化能力。 - 初始步长
eta0=0.1太大了,标准化后可以调小到0.01试试。 - 恢复
shuffle=True(默认设置),固定样本顺序会让SGD容易陷入局部最优,打乱顺序能提升收敛效率。
修改后的代码示例
import numpy as np from sklearn import linear_model from sklearn.preprocessing import StandardScaler # 处理异常值:修正第10个样本的异常特征值,移除y=2922的样本 X = np.array([[86.5999984741211, 9.10000038146973, 14.3000001907349,1], [66.9000015258789, 17.3999996185303, 11.5,1], [66.3000030517578, 20 , 10.6999998092651,1], [78.6999969482422, 15.3999996185303, 12.1000003814697,1], [76.1999969482422, 18.2000007629395, 12.5,1], [84.4000015258789, 9.89999961853027, 12.1000003814697,1], [79.1999969482422, 8.5 , 10.1000003814697,1], [77.5 , 10.1999998092651, 11.3999996185303,1], [74.4000015258789, 17.7999992370605, 10.6000003814697,1], [87.9000015258789, 13.5 , 13,1], # 修正异常特征值 [80.0999984741211, 8 , 9.10000038146973,1], [80.0999984741211, 10.3000001907349, 9,1], [79.6999969482422, 13.1000003814697, 9.5,1], [76.1999969482422, 13.6000003814697, 11.5,1], [75.5999984741211, 12.1999998092651, 10.8000001907349,1], [81.3000030517578, 13.1000003814697, 9.89999961853027,1], [64.5999984741211, 20.3999996185303, 10.6000003814697,1], [68.3000030517578, 26.3999996185303, 14.8999996185303,1], [80 , 10.6999998092651, 10.8999996185303,1], [78.4000015258789, 9.69999980926514, 12,1], [78.8000030517578, 10.6999998092651, 10.6000003814697,1], [76.8000030517578, 15.3999996185303, 13,1], [82.4000015258789, 11.6000003814697, 9.89999961853027,1], [73.9000015258789, 16.1000003814697, 10.8999996185303,1], [64.3000030517578, 24.7000007629395, 14.6999998092651,1], [81 , 14.8999996185303, 10.8000001907349,1], [70 , 14.3999996185303, 11.1000003814697,1], [76.6999969482422, 11.1999998092651, 8.39999961853027,1], [81.8000030517578, 10.3000001907349, 9.39999961853027,1], [82.1999969482422, 9.89999961853027, 9.19999980926514,1], [76.6999969482422, 10.8999996185303, 9.60000038146973,1], [75.0999984741211, 17.3999996185303, 13.8000001907349,1], [78.8000030517578, 9.80000019073486, 12.3999996185303,1], [74.8000030517578, 16.3999996185303, 12.6999998092651,1], [75.6999969482422, 13 , 11.3999996185303,1], [74.5999984741211, 19.8999996185303, 11.1000003814697,1], [81.5 , 11.8000001907349, 11.3000001907349,1], [74.6999969482422, 13.1999998092651, 9.60000038146973,1], [72 , 11.1999998092651, 10.8000001907349,1], [68.3000030517578, 18.7000007629395, 12.3000001907349,1], [77.0999984741211, 14.1999998092651, 9.39999961853027,1], [67.0999984741211, 19.6000003814697, 11.1999998092651,1], [72.0999984741211, 17.3999996185303, 11.8000001907349,1], [85.0999984741211, 10.6999998092651, 10,1], [75.1999969482422, 9.69999980926514, 10.3000001907349,1], [80.8000030517578, 10 , 11,1], [83.8000030517578, 12.1000003814697, 11.6999998092651,1], [78.5999984741211, 12.6000003814697, 10.3999996185303,1], [66 , 22.2000007629395, 9.39999961853027,1], [83 , 13.3000001907349, 10.8000001907349,1], [73.0999984741211, 26.3999996185303, 22.1000003814697,1]]) y = np.array([761, 780, 593, 715, 1078, 567, 456, 686, 1206, 723, 261, 326, 282, 960, 489, 496, 463, 1062, 805, 998, 126, 792, 327, 744, 434, 178, 679, 82, 339, 138, 627, 930, 875, 1074, 504, 635, 503, 418, 402, 1023, 208, 766, 762, 301, 372, 114, 515, 264, 208, 286]) # 移除异常y值 # 标准化特征 scaler = StandardScaler() X_scaled = scaler.fit_transform(X) # 配置优化后的SGDRegressor model = linear_model.SGDRegressor( max_iter=10000, tol=1e-6, learning_rate="adaptive", eta0=0.01, shuffle=True, penalty="l2", random_state=42 ) model.fit(X_scaled, y) print(model.coef_) print(model.score(X_scaled, y))
额外提示
- 训练前一定要做数据探索:检查特征的分布、是否有异常值,这是机器学习的基础步骤,能避免很多不必要的问题。
- 如果一定要用固定学习率,标准化后要把
eta0调得更小(比如0.001),否则还是容易出现震荡。 - 可以尝试用
SGDRegressor的warm_start=True来逐步调整参数,观察训练过程中的系数变化,方便调试。
内容的提问来源于stack exchange,提问作者omerfirmak
相关产品推荐
相关产品推荐

