如何使用 GridSearchCV 在嵌套管道中测试预处理组合?
Posted
技术标签:
【中文标题】如何使用 GridSearchCV 在嵌套管道中测试预处理组合?【英文标题】:How to test preprocessing combinations in nested pipeline using GridSearchCV? 【发布时间】:2020-12-21 04:57:56 【问题描述】:我一直在研究这个分类问题,使用 sklearn 的 Pipeline 将预处理步骤(缩放)和使用 Logistic 回归的交叉验证步骤 (GridSearchCV) 结合起来。
这是简化的代码:
# import dependencies
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, StandardScaler, MinMaxScaler, RobustScaler
# scaler and encoder options
scaler = StandardScaler() # there are 3 options that I want to try
encoder = OneHotEncoder() # only one option, no need to GridSearch it
# use ColumnTransformer to apply different preprocesses to numerical and categorical columns
preprocessor = ColumnTransformer(transformers = [('categorical', encoder, cat_columns),
('numerical', scaler, num_columns),
])
# combine the preprocessor with LogisticRegression() using Pipeline
full_pipeline = Pipeline(steps = [('preprocessor', preprocessor),
('log_reg', LogisticRegression())])
我正在尝试做的是尝试不同的缩放方法(例如标准缩放、稳健缩放等),然后在尝试所有这些之后,选择产生最佳度量(即准确性)的缩放方法。但是,我不知道如何使用 GridSearchCV:
from sklearn.model_selection import GridSearchCV
# set params combination I want to try
scaler_options = 'numerical':[StandardScaler(), RobustScaler(), MinMaxScaler()]
# initialize GridSearchCV using full_pipeline as final estimator
grid_cv = GridSearchCV(full_pipeline, param_grid = scaler_options, cv = 5)
# fit the data
grid_cv.fit(X_train, y_train)
我知道上面的代码不起作用,特别是因为我设置为 param_grid 的 scaler_options。我意识到我设置的 scaler_options 不能被 GridSearchCV 处理。为什么?因为它不是管道的超参数(与 'log_reg__C' 不同,来自 LogisticRegression() 的超参数可以由 GridSearchCV 访问)。但它是我嵌套在 full_pipeline 中的 ColumnTransformer 的一个组件。
所以主要问题是,如何自动化 GridSearchCV 来测试我的所有缩放选项?由于缩放器是子管道的一个组件(即之前的 ColumnTransformer)。
【问题讨论】:
更新:我想我已经找到了解决方案,即创建一个自定义转换器,其中包含一个具有“scaling_options”作为其初始化参数的类,以选择我想要应用的缩放方法。这样我可以插入以下字典 preprocessor__customtransformer__scaling_options: [list of options] 作为 param_grid。如果我错了,请纠正我。 请edit你的问题添加一些解释或代码,而不是像你一样使用cmets。 【参考方案1】:按照您的建议,您可以创建一个 class
,它接受您要使用的 缩放器 __init()__
参数。
然后你可以在你的网格搜索参数中指定你的类应该用来初始化类的 Scaler。
我写道,希望对您有所帮助:
class ScalerSelector(BaseEstimator, TransformerMixin):
def __init__(self, scaler=StandardScaler()):
super().__init__()
self.scaler = scaler
def fit(self, X, y=None):
return self.scaler.fit(X)
def transform(self, X, y=None):
return self.scaler.transform(X)
在这里你可以找到一个完整的例子,你可以运行它来测试:
# import dependencies
from sklearn.tree import DecisionTreeClassifier
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
from sklearn.datasets import load_breast_cancer
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
import pandas as pd
class ScalerSelector(BaseEstimator, TransformerMixin):
def __init__(self, scaler=StandardScaler()):
super().__init__()
self.scaler = scaler
def fit(self, X, y=None):
return self.scaler.fit(X)
def transform(self, X, y=None):
return self.scaler.transform(X)
data = load_breast_cancer()
features = data["data"]
target = data["target"]
data = pd.DataFrame(data['data'], columns=data['feature_names'])
col_names = data.columns.tolist()
# scaler and encoder options
my_scaler = ScalerSelector()
preprocessor = ColumnTransformer(transformers = [('numerical', my_scaler, col_names)
])
# combine the preprocessor with LogisticRegression() using Pipeline
full_pipeline = Pipeline(steps = [('preprocessor', preprocessor),
('log_reg', LogisticRegression())
])
# set params combination I want to try
scaler_options = 'preprocessor__numerical__scaler':[StandardScaler(), RobustScaler(), MinMaxScaler()]
# initialize GridSearchCV using full_pipeline as final estimator
grid_cv = GridSearchCV(full_pipeline, param_grid = scaler_options)
# fit the data
grid_cv.fit(data, target)
# best params :
grid_cv.best_params_
【讨论】:
【参考方案2】:无需创建自定义转换器即可实现您的目标。您甚至可以将 'passthrough'
参数传递给 param_grid 以试验您根本不想在该步骤中进行任何缩放的场景。
在本例中,假设我们想调查模型是否更好地对数值特征施加 Scaler 变换器,num_features。
cat_features = selector(dtype_exclude='number')(train.drop('target', axis=1))
num_features = selector(dtype_include='number')(train.drop('target', axis=1))
cat_preprocessor = Pipeline(steps=[
('oh', OneHotEncoder(handle_unknown='ignore')),
('ss', StandardScaler())
])
num_preprocessor = Pipeline(steps=[
('pt', PowerTransformer(method='yeo-johnson')),
('ss', StandardScaler()) # Create a place holder for your test here !!!
])
preprocessor = ColumnTransformer(transformers=[
('cat', cat_preprocessor, cat_features),
('num', num_preprocessor, num_features)
])
model = Pipeline(steps=[
('prep', preprocessor),
('clf', RidgeClassifier())
])
X = train.drop('target', axis=1)
y = train['target']
param_grid =
'prep__cat__ss': ['passthrough', StandardScaler(with_mean=False)] # 'passthrough',
gs = GridSearchCV(
estimator=model,
param_grid=param_grid,
scoring='roc_auc',
n_jobs=-1,
cv=2
)
gs.fit(X, y)
【讨论】:
以上是关于如何使用 GridSearchCV 在嵌套管道中测试预处理组合?的主要内容,如果未能解决你的问题,请参考以下文章
如何实现 sklearn 的 Estimator 接口以在 GridSearchCV 管道中使用?
使用嵌套在 GridSearchCV 中的 RFECV 时,如何避免使用 estimator_params?
sklearn - 如何从传递给 GridSearchCV 的管道中检索 PCA 组件和解释方差
如何使用 GridSearchCV 比较多个模型以及 python 中的管道和超参数调整