我相信我已经正确实现了梯度下降(部分基于Aurelien Geron的书),但它返回的结果与sklearn的线性回归不同。以下是完整的笔记本:https://colab.research.google.com/drive/17lvCb_F_vMskT1PxbrKCSR57B5lMWT7A?usp=sharing
我没有做任何复杂的事情,以下是加载训练数据的代码:
以下是生成的权重:
array([[ 2.72774600e-17], [ 1.01847403e+00], [ 3.87858604e-02], [ 3.06547577e-04], [-3.67525543e-01], [ 9.09006216e-02], [ 4.21512716e-01], [ 4.25673672e-01], [ 4.77147289e-02], [-8.14471370e-03]])
以及均方误差: 5.24937033143115e-05
以下是sklearn给我的结果:
from sklearn.linear_model import LinearRegressionfrom sklearn.metrics import mean_squared_error%time reg = LinearRegression().fit(X, y)reg.coef_
sklearn的权重:
array([[ 0.00000000e+00, 1.00000000e+00, -9.99200722e-16, -1.69309011e-15, -1.11022302e-16, 1.38777878e-15, -3.88578059e-16, 6.80011603e-16, -8.32667268e-17, -5.55111512e-16]])
sklearn的均方误差: 1.697650600978984e-32
我尝试过增加/减少迭代次数和学习率的大小。Scikit-learn在几毫秒内就返回结果。我的GD实现可能需要运行几分钟,仍然无法接近sklearn的结果。
我在这里做错了什么明显的地方吗?
(笔记本中包含了这段代码的更清晰版本。)
回答:
你的代码中有一个小错误,因为X_raw
的第一列与y_raw
相同,即目标被用作特征。这在下面的代码中已被修正。
另一个问题是,如果你在特征矩阵X
中包含一列全为1的列,那么在用sklearn拟合线性回归时,你应该确保设置fit_intercept=False
,否则特征矩阵中将会有两列全为1的列。
在梯度更新中为什么要除以观测值的数量也不清楚,因为这会显著降低学习率。