首页 > 解决方案 > 通过随机搜索和递归特征消除将特征缩放添加到嵌套交叉验证

问题描述

我有一个分类任务,想使用重复的嵌套交叉验证来同时执行超参数调整和特征选择。为此,我正在RandomizedSearchCV使用RFECVPython 的sklearn库,正如这个 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)

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

非常感谢任何帮助!

标签: pythonscikit-learn

解决方案


你没有丢失嵌套的简历。

您在顶层有一个搜索对象;当您调用 时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)

推荐阅读