如何在执行 10 倍交叉验证时在每次拆分时获得 Lasso Regression 中的系数?

Posted

技术标签:

【中文标题】如何在执行 10 倍交叉验证时在每次拆分时获得 Lasso Regression 中的系数?【英文标题】:How to get the coefficients in Lasso Regression at every split while performing 10 fold cross validation? 【发布时间】:2021-08-31 03:24:08 【问题描述】:

我正在执行随机搜索 cv 以在 Lasso 回归中查找 alpha 值,并且我正在执行 10 折交叉验证。有没有办法获取每个拆分的系数值,就像我们使用 cv_results 函数获取分数一样?

【问题讨论】:

@MustafaAydın 我相信 OP 想要在每次迭代中拟合 Lasso 估计器的 coef_。这无法从cv_results_ 中检索到,因为并非所有拟合的估计器都被保存。在我的回答中提供了解决方法。 @afsharov 哦,谢谢,我现在明白了,感谢您的回答,+1。​​ 【参考方案1】:

在我看来,将系数保存为附加分数比修改估计器本身(如@afsharov's answer)更巧妙。定义记分器并将其传递给搜索

def coefs_scorer(estimator, X, y):
    return estimator.coef_

rs = RandomizedSearchCV(
    ...
    scoring='r2': 'r2', 'coefs': coefs_scorer,
    refit='r2',
)

失败,因为有记录员返回单个数字的检查。所以你需要解压缩系数,我最终得到了这个:

def coefs_scorer(estimator, X, y, i):
    return estimator.coef_[i]

from functools import partial
scoring = 'r2': 'r2'
for i in range(X_train.shape[1]):
    scoring[f'coefi'] = partial(coefs_scorer, i=i)

param_distributions = 'alpha': [0.01, 0.1, 1]
rs = RandomizedSearchCV(
    Lasso(),
    param_distributions=param_distributions,
    cv=2,
    n_iter=3,
    random_state=42,
    scoring=scoring,
    refit='r2',
)

请注意,对于多个指标,您需要指定用于改装的指标。由于所有额外的工作,我不太确定这是否比自定义类更好。不过它确实有一些优点:

如果您想挑选最佳估算器,则无需打包自定义类。 分数以编程方式保存,而不仅仅是打印出来。 由于它们是分数,因此您可以获得存储在 cv_results_ 中的各个折叠系数的平均值和标准偏差(当然,自己计算它们并不困难)。

缺点:

我们必须为每个功能指定一个指标。这很丑陋,但更糟糕的是,它假设您事先知道特征的数量(如果您的估算器是具有特征选择或某些特征工程步骤的管道,它将失败)。 如果您返回火车分数,您将复制cv_results_ 中的系数。 这些实际上不是分数,所以从语义上讲这是hacky。 记分员假定coef_ 存在并且是一维的。

【讨论】:

【参考方案2】:

没有直接的方法可以通过RandomizedSearchCV 执行此操作。但是您可以通过定义自己的类来解决这个问题,例如调用 predict 函数时将系数打印到控制台:

from sklearn.linear_model import Lasso


class MyLasso(Lasso):

    def predict(self, X):
        print(self.coef_)
        return super().predict(X)

MyLasso 的行为与Lasso 相同,可以照常使用:

from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split, RandomizedSearchCV


X, y = make_regression(n_features=5, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)

param_distributions = 'alpha': [0.01, 0.1, 1]
rs = RandomizedSearchCV(
    MyLasso(),
    param_distributions=param_distributions,
    cv=2,
    n_iter=3,
    random_state=42
)

rs.fit(X_train, y_train)

上述示例的输出(2 折交叉验证的三次迭代得到六个结果):

[64.57650818 98.64237403 57.07123743 60.56898095 35.59985227]
[64.57001187 98.63679695 57.06557977 60.56304163 35.59888746]
[64.43774582 98.55938568 57.01219706 60.49221968 35.51151313]
[64.37690435 98.49805298 56.95345309 60.43375789 35.5018112 ]
[63.05012223 97.72950224 56.42179336 59.72460697 34.62812171]
[62.44582912 97.11061327 55.83218634 59.14092054 34.53104869]

【讨论】:

以上是关于如何在执行 10 倍交叉验证时在每次拆分时获得 Lasso Regression 中的系数?的主要内容,如果未能解决你的问题,请参考以下文章

在 sklearn 中运行 10 倍交叉验证后如何运行 SVC 分类器?

如何在 Scikit-Learn 中绘制超过 10 倍交叉验证的 PR 曲线

如何使用 Weka API 在 J48 / C4.5 上进行 10 倍交叉验证后保存最佳树

应该对原始数据还是拆分数据执行交叉验证分数?

有没有办法使用 SKlearn 获得滑动嵌套交叉验证?

为啥 scikit-learn SVM 分类器交叉验证这么慢?