【问题标题】:Why manually calculated MSE different from LassoCV.mse_path in sklearn为什么手动计算 MSE 不同于 sklearn 中的 LassoCV.mse_path
【发布时间】:2018-02-27 09:05:21
【问题描述】:

我正在 python 中使用套索,但有一个问题让我感到困惑。 在下面example中,我的代码如下:

kf = KFold(10,random_state=0,shuffle=False)  
model_lassocv = LassoCV(cv=kf).fit(X, y) 

model_lassocv.mse_path_ 给出数组([[ 5747.95194531, 4590.75732123, ...]])。

我手动计算了 mse:

from sklearn import linear_model
from sklearn.model_selection import cross_val_predict, cross_val_score
lasso = linear_model.Lasso(alpha = model_lassocv.alphas_[0])
predict = cross_val_predict(lasso, X, y, cv=kf)
metrics.mean_squared_error(y_pred=predict[0:44],y_true=y[0:44]) 
# 0:44 is the first test set according to KFold function
# and result here gives 5625 instead of 5747.95

然而,

cross_val_score(lasso,X,y, cv=kf, scoring="neg_mean_squared_error")

给出与 model_lassocv.mse_path_ 相同的结果,但否定结果除外。

对不起,我的误导性问题。我想知道为什么metrics.mean_squared_error 返回与mse_path_ 不同的结果。如果我没有误解KFold 的分区,那么 10 倍 CV 中的第一个测试集是 0:44。并且由metrics.mean_squared_error 计算的第一个 alpha(在我的情况下为 2.14804358)的第一个测试集中的交叉验证预测和真实值的 MSE 返回 5625,而 LassoCV 的 mse_path_ 返回 5747。

【问题讨论】:

  • 您能举个 X 和 Y 的例子,以便我们检查结果吗?
  • 我相信这是在这里讨论的:github.com/scikit-learn/scikit-learn/issues/2439我想如果你想让两者匹配,使用make_scorer并通过greater_is_better = True
  • 嗯,mse_path_ 属性提供了在建模过程中测试的不同 alpha 的 MSE。您必须找到模型选择的 alpha,然后找到该 alpha 值对应的 MSE。至于MSE的负值,开发者就是这么设计的。这就是为什么评分被称为neg_mean_squared_error。在之前版本的 sklearn 中,neg 不在评分描述中,这导致用户感到困惑。
  • @Mabel Villalba 很抱歉,下面的链接中提供了示例。
  • @Scratch'N'Purr 我收到了您的消息,但问题可能存在误导。我对 neg_mean_squared_error 和 mse_path_ 的结果很满意,它们是一样的。我自己计算的MSE是使用lassoCV结果中的第一个alpha,这个MSE应该是5747.95194531(对于第一个alpha和10倍CV中的第一个测试集)。但是我得到 5625。这让我很困惑。

标签: python machine-learning scikit-learn


【解决方案1】:

原因在于您手动执行拟合模型。 mse_path_ 属性中的 MSE 是您的 KFold 对象生成的每个折叠的 MSE。但是,在您的手动实现中,当您使用 cross_val_predict 时,您是在要求 sklearn 训练具有所有可用折叠的模型,而不是在 LassoCv 实现中使用的特定折叠。我将使用 sklearn 提供的 boston 数据集提供正确的解决方案。

from sklearn.model_selection import cross_val_predict, cross_val_score, KFold
from sklearn.linear_model import LassoCV, Lasso
from sklearn.metrics import mean_squared_error
from sklearn.datasets import load_boston

X, y = load_boston(return_X_y=True)
kf = KFold(10, random_state=0, shuffle=False)

现在让我们看看折叠是什么样子的:

for train_i, test_i in kf.split(X):
    print(train_i, test_i)

(array([ 51,  52,  53, ... , 505], dtype=int64), array([ 0,  1,  2, ... , 50], dtype=int64)) ... (array([ ... ]))

为简洁起见,我只展示第一折,其中训练集包含从 51 到 505 的索引,而对于该折中的测试集,索引是从 0 到 50。

现在让我们使用您的 LassoCV 方法进行拟合:

model_lassocv = LassoCV(cv=kf).fit(X, y)
model_lassocv.mse_path_

MSE 路径的结果:

  array([[  41.74173819,   29.78409579,   32.00672122,  191.68560655,
           103.46618603,  172.62108062,   16.92365434,  181.06822315,
           116.83656233,   35.92813347], [ ... ], ... ])

再次,为简洁起见,我只显示第一个 alpha 的所有 10 折的 MSE。根据您的示例,您希望匹配 LassoCV 中使用的第一个 alpha 的第一个折叠的 MSE,因此在我的情况下,我想手动获得结果 = 41.74173819。

现在,我将使用手动实现来执行以下操作:

  lasso = Lasso(alpha = model_lassocv.alphas_[0])
  lasso.fit(X[51:506], y[51:506])
  predict = lasso.predict(X[0:51])
  mean_squared_error(y_pred=predict, y_true=y[0:51])

主要区别:

  1. 我使用由 KFold 对象标识的第一个折叠的训练集来拟合我的模型(还记得我说过第一个折叠训练的索引从 51 到 505 吗?)。
  2. 然后我根据第一折的测试集生成我的预测。 (这里,测试集的索引是 0-50)

我手动计算的结果?

41.741738189299873

因此,我们有一场比赛。

【讨论】:

  • 非常感谢!我认为我在示例中选择测试集索引时犯了一个错误。您的解决方案确实帮了大忙。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-21
  • 1970-01-01
  • 1970-01-01
  • 2021-09-15
  • 2019-10-09
  • 2019-06-26
相关资源
最近更新 更多