【问题标题】:Adding feature scaling to a nested cross-validation with randomized search and recursive feature elimination通过随机搜索和递归特征消除将特征缩放添加到嵌套交叉验证
【发布时间】:2021-12-21 06:55:53
【问题描述】:

我有一个分类任务,想使用重复的嵌套交叉验证来同时执行超参数调整和特征选择。为此,我正在使用 Python 的 sklearn 库在 RFECV 上运行 RandomizedSearchCV,正如 this SO answer 中所建议的那样。

但是,我还需要先扩展我的特征并估算一些缺失值。这两个步骤也应该包含在 CV 框架中,以避免训练和测试折叠之间的信息泄漏。我试图创建一个管道来到达那里,但我认为它“破坏”了我的 CV 嵌套(即,彼此分开执行 RFECV 和随机搜索):

import numpy as np    
from sklearn.datasets import make_classification
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.feature_selection import RFECV
import scipy.stats as stats
from sklearn.utils.fixes import loguniform
from sklearn.preprocessing import StandardScaler
from sklearn.impute import KNNImputer
from sklearn.linear_model import SGDClassifier
from sklearn.model_selection import RandomizedSearchCV
from sklearn.pipeline import Pipeline

# create example data with missings
Xtrain, ytrain = make_classification(n_samples = 500,
                                     n_features = 150,
                                     n_informative = 25,
                                     n_redundant = 125,
                                     random_state = 1897)
c = 10000 # number of missings
Xtrain.ravel()[np.random.choice(Xtrain.size, c, replace = False)] = np.nan # introduce random missings

folds = 5
repeats = 5
rskfold = RepeatedStratifiedKFold(n_splits = folds, n_repeats = repeats, random_state = 1897)
n_iter = 100

scl = StandardScaler()
imp = KNNImputer(n_neighbors = 5, weights = 'uniform')
sgdc = SGDClassifier(loss = 'log', penalty = 'elasticnet', class_weight = 'balanced', random_state = 1897)
sel = RFECV(sgdc, cv = folds)
pipe = Pipeline([('scaler', scl),
                 ('imputer', imp),
                 ('selector', sel),
                 ('clf', sgdc)])
param_rand = {'clf__l1_ratio': stats.uniform(0, 1),
              'clf__alpha': loguniform(0.001, 1)}
rskfold_search = RandomizedSearchCV(pipe, param_rand, n_iter = n_iter, cv = rskfold, scoring = 'accuracy', random_state = 1897, verbose = 1, n_jobs = -1)
rskfold_search.fit(Xtrain, ytrain)

有谁知道如何在不丢失我的 RandomizedSearchCVRFECV 的嵌套的情况下将缩放和插补纳入 CV 框架?

非常感谢任何帮助!

【问题讨论】:

    标签: python scikit-learn


    【解决方案1】:

    你没有丢失嵌套的简历。

    您在顶层有一个搜索对象;当您调用fit 时,它会将数据拆分为多个折叠。让我们关注一个这样的火车折叠。您的管道安装在上面,因此您可以进行缩放和估算,然后 RFECV 将其拆分为内部折叠。最后,一个新的估计器被安装在外部训练折叠上,并在外部测试折叠上进行评分。

    这意味着 RFE 可能会有一点泄漏,因为缩放和插补发生在其分裂之前。您可以将它们添加到估算器之前的管道中,并将该管道用作 RFE 估算器。由于RFECV 使用发现的最佳特征数量重新调整了它的估计器,并为predict 等公开了它,所以你真的不需要sgdc 的第二个副本;仅使用一个副本也会产生超参数调整选择的副作用:

    scl = StandardScaler()
    imp = KNNImputer(n_neighbors=5, weights='uniform')
    sgdc = SGDClassifier(loss='log', penalty='elasticnet', class_weight='balanced', random_state=1897)
    base_pipe = Pipeline([
        ('scaler', scl),
        ('imputer', imp),
        ('clf', sgdc),
    ])
    sel = RFECV(base_pipe, cv=folds)
    
    param_rand = {'estimator__clf__l1_ratio': stats.uniform(0, 1),
                  'estimator__clf__alpha': loguniform(0.001, 1)}
    rskfold_search = RandomizedSearchCV(sel, param_rand, n_iter=n_iter, cv=rskfold, scoring='accuracy', random_state=1897, verbose=1, n_jobs=-1)
    

    【讨论】:

    • 感谢您的帮助!当我尝试这个时,我收到以下错误:ValueError: Input contains NaN, infinity or a value too large for dtype('float64'). 我认为这是因为插补仅应用于内部 CV 而不是外部 CV?
    • @Ramsesll,对,对不起。我在想转换时的 RFE 仍会运行管道,但这是不正确的。它确实包含整个管道的合适副本,并且可以predict,这将首先进行估算和扩展,但transform 没有。使用base_pipe 作为clf 应该这样做(适当地更改超参数名称),或者您可以将步骤添加到pipe
    • 再次感谢您,但我仍然得到相同的ValueError...?正如你所建议的,我写了pipe = Pipeline([('sel', sel), ('clf', base_pipe)])param_rand = {'clf__clf__l1_ratio': stats.uniform(0, 1), 'clf__clf__alpha': loguniform(0.001, 1)},而不是你答案中的相应行。你有别的想法吗?
    • 我不知道为什么那行不通,不。你能提供一个数据sn-p吗?我还意识到您可以更多地依靠RFECV 改装,所以答案会更新,但它可能不会/不应该影响错误。
    猜你喜欢
    • 2017-03-30
    • 2018-12-13
    • 1970-01-01
    • 2021-04-09
    • 2013-11-08
    • 2018-11-28
    • 2020-06-05
    • 2019-07-15
    • 2022-11-05
    相关资源
    最近更新 更多