为什么sklearn(python)和matlab统计软件中的LASSO不同?

11
我正在使用来自sklearn的LaasoCV选择最佳模型以进行交叉验证。我发现,如果我使用sklearn或matlab统计工具箱,交叉验证会给出不同的结果。
我使用了matlab并复制了http://www.mathworks.se/help/stats/lasso-and-elastic-net.html中提供的示例来获得如此的图形: enter image description here 然后我保存了matlab数据,并尝试使用sklearn的laaso_path来复制该图形,我得到了: enter image description here 尽管这两个图形之间存在某些相似之处,但也存在某些差异。据我所知,matlab中的lambda参数和sklearn中的alpha参数是相同的,但在这个图中似乎存在一些差异。有人能指出哪一个正确还是我忽略了某些内容?此外,获得的系数也是不同的(这是我的主要关注点)。
Matlab代码:
rng(3,'twister') % for reproducibility
X = zeros(200,5);
for ii = 1:5
      X(:,ii) = exprnd(ii,200,1);
end
r = [0;2;0;-3;0];
Y = X*r + randn(200,1)*.1;

save randomData.mat % To be used in python code

[b fitinfo] = lasso(X,Y,'cv',10);
lassoPlot(b,fitinfo,'plottype','lambda','xscale','log');

disp('Lambda with min MSE')
fitinfo.LambdaMinMSE
disp('Lambda with 1SE')
fitinfo.Lambda1SE
disp('Quality of Fit')
lambdaindex = fitinfo.Index1SE;
fitinfo.MSE(lambdaindex)
disp('Number of non zero predictos')
fitinfo.DF(lambdaindex)
disp('Coefficient of fit at that lambda')
b(:,lambdaindex)

Python 代码:

import scipy.io
import numpy as np
import pylab as pl
from sklearn.linear_model import lasso_path, LassoCV

data=scipy.io.loadmat('randomData.mat')
X=data['X']
Y=data['Y'].flatten()

model = LassoCV(cv=10,max_iter=1000).fit(X, Y)
print 'alpha', model.alpha_
print 'coef', model.coef_

eps = 1e-2 # the smaller it is the longer is the path
models = lasso_path(X, Y, eps=eps)
alphas_lasso = np.array([model.alpha for model in models])
coefs_lasso = np.array([model.coef_ for model in models])

pl.figure(1)
ax = pl.gca()
ax.set_color_cycle(2 * ['b', 'r', 'g', 'c', 'k'])
l1 = pl.semilogx(alphas_lasso,coefs_lasso)
pl.gca().invert_xaxis()
pl.xlabel('alpha')
pl.show()

我只能说,当我处理真实数据时,我记得有类似的发现。Matlab的结果不同且显著更好。虽然我没有深入探讨这个问题的根源。 - Bitwise
4个回答

3

我没有Matlab,但请注意:通过交叉验证获得的值可能不稳定。这是因为它受样本划分方式的影响。

即使您在Python中运行两次交叉验证,也可以获得2个不同的结果。考虑以下示例:

kf=sklearn.cross_validation.KFold(len(y),n_folds=10,shuffle=True)
cv=sklearn.linear_model.LassoCV(cv=kf,normalize=True).fit(x,y)
print cv.alpha_
kf=sklearn.cross_validation.KFold(len(y),n_folds=10,shuffle=True)
cv=sklearn.linear_model.LassoCV(cv=kf,normalize=True).fit(x,y)
print cv.alpha_

0.00645093258722
0.00691712356467

2

可能会出现 alpha = lambda / n_samples 的情况,其中 n_samples = X.shape[0] 在scikit-learn中。

另一个注意事项是你的路径不够分段线性,可以考虑减小tol并增加max_iter

希望这可以帮到您。


我猜问题不只是规范化的问题。我尝试了上面的方法,但仍然得到了不同的曲线。此外,通过交叉验证得到的系数也非常不同。 - imsc
这对我来说仍然看起来像是一个参数化问题:两条曲线看起来相似,但在X轴上有所偏移。在scikit-learn中对alpha进行log空间的重新缩放可能会导致这种情况。scikit-learn中使用的参数化方法在文档中给出(http://scikit-learn.org/stable/modules/linear_model.html#lasso)。您还可以从相同的分布中生成更多数据,并计算回归得分(例如确定系数r^2或RMSE),并检查最优的alpha值是否接近于交叉验证的alpha值。 - ogrisel
@imsc,你尝试过使用alpha = lambda / (2 * X.shape[0])吗? - ogrisel

0

我知道这是一个旧的帖子,但是:

我正在从glmnet(在R中)切换到LassoCV,并发现LassoCV在首先对X矩阵进行归一化时效果不太好(即使您指定参数normalize = True)。

使用LassoCV时,请先尝试对X矩阵进行归一化。

如果它是一个pandas对象,

(X - X.mean())/X.std()

看起来你还需要将 alpha 乘以 2


-2

虽然我无法确定问题的原因,但有一个逻辑方向可以继续。

以下是事实:

  • Mathworks已经选择了一个示例,并决定将其包含在他们的文档中
  • 您的Matlab代码产生的结果与示例完全相同。
  • 另一种方法不能匹配结果,并且过去提供了不准确的结果

这是我的假设:

  • 与Mathworks选择在他们的文档中放置不正确的示例相比,以其他方式复制此示例并不会给出正确的结果的机会微乎其微。

逻辑结论:您的Matlab实现此示例是可靠的,而另一种方法则不可靠。这可能是代码中的问题,也可能是您使用它的方式,但无论如何,唯一的逻辑结论是您应该继续使用Matlab来选择您的模型。


1
这是一个非常薄弱的论点,试图宣传一种技术胜过另一种。scikit-learn也提供了示例。它能否通过matlab代码复现?实际上,LASSO更像是一类求解器而不是一个精确定义的算法。因此,算法可能略有不同。基于你的论点声称scikit-learn不可靠是相当严厉的。 - Nicolas Barbey
我并不想暗示这一点,我稍微重新表述了我的回答以使其更加清晰。 - Dennis Jaheruddin
感谢您的回答。scikit-learn确实是一个良好实现的模块。然而,文档和示例仍然不足,导致了上述问题。我通过适当的规范化解决了这个问题。 - imsc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接