岭回归:Scikit-learn 与直接计算不匹配 alpha > 0

Posted

技术标签:

【中文标题】岭回归:Scikit-learn 与直接计算不匹配 alpha > 0【英文标题】:Ridge Regression: Scikit-learn vs. direct calculation does not match for alpha > 0 【发布时间】:2016-11-28 11:56:23 【问题描述】:

在岭回归中,我们使用L2 正则化解决Ax=b。直接计算如下:

x = (ATA + alpha * I)-1ATb

我查看了 scikit-learn 代码,它们确实实现了相同的计算。但是,对于alpha > 0,我似乎无法得到相同的结果

重现这一点的最少代码。

import numpy as np
A = np.asmatrix(np.c_[np.ones((10,1)),np.random.rand(10,3)])
b = np.asmatrix(np.random.rand(10,1))
I = np.identity(A.shape[1])
alpha = 1
x = np.linalg.inv(A.T*A + alpha * I)*A.T*b
print(x.T)
>>> [[ 0.37371021  0.19558433  0.06065241  0.17030177]]

from sklearn.linear_model import Ridge
model = Ridge(alpha = alpha).fit(A[:,1:],b)
print(np.c_[model.intercept_, model.coef_])
>>> [[ 0.61241566  0.02727579 -0.06363385  0.05303027]]

有什么建议可以解决这个差异吗?

【问题讨论】:

【参考方案1】:

这种修改似乎对直接版本和 numpy 版本产生了相同的结果:

import numpy as np
A = np.asmatrix(np.random.rand(10,3))
b = np.asmatrix(np.random.rand(10,1))
I = np.identity(A.shape[1])
alpha = 1
x = np.linalg.inv(A.T*A + alpha * I)*A.T*b
print (x.T)


from sklearn.linear_model import Ridge
model = Ridge(alpha = alpha, tol=0.1, fit_intercept=False).fit(A ,b)

print model.coef_
print model.intercept_

似乎造成差异的主要原因是Ridge 类具有参数fit_intercept=True(通过从_BaseRidge 类继承)(source)

这是在将矩阵传递给_solve_cholesky 函数之前应用数据中心化过程。

这是 ridge.py 中的代码

        X, y, X_mean, y_mean, X_std = self._center_data(
        X, y, self.fit_intercept, self.normalize, self.copy_X,
        sample_weight=sample_weight)

此外,您似乎试图通过添加 1 的列来隐式解释截距。如您所见,如果您指定 fit_intercept=False

附录:Ridge 类是否真的实现了直接公式?

这取决于solver参数的选择。

实际上,如果您没有在Ridge 中指定solver 参数,则默认采用solver='auto'(内部采用solver='cholesky')。这应该相当于直接计算。

严格来说,_solve_cholesky 使用numpy.linalg.solve 而不是numpy.inv。但是可以很容易地检查出来

np.linalg.solve(A.T*A + alpha * I, A.T*b)

产生相同的结果
np.linalg.inv(A.T*A + alpha * I)*A.T*b

【讨论】:

感谢您的详细回复。这确实解决了fit_intercept = False。但是,在我的示例中,我确实想要intercept,因此我在直接计算中将 1 的列添加到我的A 矩阵中。当我使用A[:,1:] 传递给Ridge 时,我删除了1 的列。因此,即使我运行model = Ridge(alpha = alpha, normalize = False, fit_intercept = True, solver = "cholesky").fit(A[:,1:],b) - 我也无法获得相同的结果。当你想要fit_intercept = True时有任何澄清吗? 我相信你仍然可以保持A = np.asmatrix(np.c_[np.ones((10,1)),np.random.rand(10,3)])这一行并设置fit_intercept=False。第一个系数不应该是截距吗? 是的 - 就是这样!应该考虑一下。仍然想知道为什么normalize = False, fit_intercept=True 不这样做。感谢您的所有帮助。

以上是关于岭回归:Scikit-learn 与直接计算不匹配 alpha > 0的主要内容,如果未能解决你的问题,请参考以下文章

具有非正则截距项的 Scikit-learn 岭回归

scikit-learn学习基础知识三

scikit-learn : 优化岭回归参数alpha优化

线性回归 scikit-learn LinearRegression最小二乘法梯度下降SDG多项式回归学习曲线岭回归Lasso回归

scikit learn中的多目标岭回归如何工作?

机器学习岭回归和LASSO回归详解以及相关计算实例-加利福尼亚的房价数据集红酒数据集