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

ami*_*aps 6 python linear-regression scikit-learn

在岭回归中,我们正在Ax=b通过L2正则化来解决.直接计算如下:

x =(A T A + alpha*I)-1 A T b

我查看了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]]
Run Code Online (Sandbox Code Playgroud)

我可以采取哪些建议来解决这种差异?

JAR*_*ARS 6

对于直接版本和 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_
Run Code Online (Sandbox Code Playgroud)

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

这是在将矩阵传递给_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)
Run Code Online (Sandbox Code Playgroud)

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

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

这取决于solver参数的选择。

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

严格来说,_solve_cholesky使用numpy.linalg.solve代替numpy.inv. 但可以很容易地检查出

np.linalg.solve(A.T*A + alpha * I, A.T*b)
Run Code Online (Sandbox Code Playgroud)

产量与

np.linalg.inv(A.T*A + alpha * I)*A.T*b
Run Code Online (Sandbox Code Playgroud)