使用sklearn的多元线性回归与正规方程结果不符,代码是否正确?
问题根源:重复处理截距项
你的代码问题出在手动添加截距列的同时,sklearn的LinearRegression默认自动拟合截距,这导致模型输入出现冗余的常数项,最终结果不一致。
具体分析:
- 你手动执行了
x=np.insert(x,0,1,axis=1),给特征矩阵添加了全1的列,这对应多元线性模型的形式是:$y = X\beta$,其中$X$包含常数项,$\beta$的第一个元素就是截距,后续是特征系数。 - 但
sklearn.linear_model.LinearRegression的默认参数fit_intercept=True,它会自动给输入特征添加一个隐含的常数项来拟合截距。这就意味着你的模型里同时存在两个常数项(手动加的列+自动加的隐含列),引发了多重共线性,导致最小二乘解不唯一:- 你的正规方程用伪逆(
linalg.pinv)计算的是最小范数解; - sklearn则给出了另一个满足最小二乘的解,也就是你看到的
[[0. , 0.0625, 0.0625, 0.0625, 0.0625]]。
- 你的正规方程用伪逆(
两种修正方法:
方法1:关闭sklearn的自动截距拟合
既然你已经手动添加了截距列,就告诉LinearRegression不要自动处理截距:
import numpy as np from sklearn import linear_model import numpy.linalg as linalg x=np.arange(12).reshape(3,4) y=np.arange(3,6).reshape(3,1) x=np.insert(x,0,1,axis=1) def normal(X,y): return np.dot(np.dot(linalg.pinv(np.dot(X.T,X)),X.T),y) print("正规方程结果:\n", normal(x,y)) reg=linear_model.LinearRegression(fit_intercept=False) # 关闭自动截距 reg.fit(x,y) print("sklearn修正后结果:\n", reg.coef_)
运行后你会发现两者结果完全一致,都是:
[[ 0.4375 ] [-0.59375] [-0.15625] [ 0.28125] [ 0.71875]]
方法2:让sklearn自动处理截距,不要手动添加全1列
删掉手动插入全1列的代码,用sklearn默认的截距拟合逻辑,此时coef_是特征的系数,intercept_是截距项,两者组合起来和正规方程结果对应:
import numpy as np from sklearn import linear_model import numpy.linalg as linalg x=np.arange(12).reshape(3,4) y=np.arange(3,6).reshape(3,1) # 正规方程需要手动加截距列来对比 x_with_intercept = np.insert(x,0,1,axis=1) def normal(X,y): return np.dot(np.dot(linalg.pinv(np.dot(X.T,X)),X.T),y) normal_result = normal(x_with_intercept,y) print("正规方程结果(截距+系数):\n", normal_result) reg=linear_model.LinearRegression() # 默认fit_intercept=True reg.fit(x,y) print("sklearn截距:", reg.intercept_) print("sklearn特征系数:", reg.coef_)
输出会是:
正规方程结果(截距+系数): [[ 0.4375 ] [-0.59375] [-0.15625] [ 0.28125] [ 0.71875]] sklearn截距: [0.4375] sklearn特征系数: [[-0.59375 -0.15625 0.28125 0.71875]]
可以看到intercept_对应正规方程结果的第一个元素,coef_对应后续的特征系数,完全匹配。
内容的提问来源于stack exchange,提问作者kramer
相关产品推荐
相关产品推荐

