岭回归:Scikit-learn 与直接计算不匹配 alpha > 0
Ridge Regression: Scikit-learn vs. direct calculation does not match for alpha > 0
在岭回归中,我们使用 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]]
有什么建议可以解决这个差异吗?
这个修改似乎对直接版本和 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_
似乎差异的主要原因是 class Ridge
具有参数 fit_intercept=True
(继承自 class _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 class 是否真的实现了直接公式?
这取决于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
在岭回归中,我们使用 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]]
有什么建议可以解决这个差异吗?
这个修改似乎对直接版本和 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_
似乎差异的主要原因是 class Ridge
具有参数 fit_intercept=True
(继承自 class _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 class 是否真的实现了直接公式?
这取决于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