如何使用 GridSearchCV 比较多个模型以及 python 中的管道和超参数调整

Posted

技术标签:

【中文标题】如何使用 GridSearchCV 比较多个模型以及 python 中的管道和超参数调整【英文标题】:How to use GridSearchCV for comparing multiple models along with pipeline and hyper-parameter tuning in python 【发布时间】:2020-08-24 03:13:23 【问题描述】:

我正在使用两个估计器,随机森林和 SVM

random_forest_pipeline=Pipeline([   
    ('vectorizer',CountVectorizer(stop_words='english')),
    ('random_forest',RandomForestClassifier())
])
svm_pipeline=Pipeline([
    ('vectorizer',CountVectorizer(stop_words='english')),
    ('svm',LinearSVC())
])

我想首先对数据进行矢量化,然后使用估计器,我正在通过这个在线 tutorial 。然后我使用超参数如下

parameters=[
    
        'vectorizer__max_features':[500,1000,1500],
        'random_forest__min_samples_split':[50,100,250,500]
    ,
    
        'vectorizer__max_features':[500,1000,1500],
        'svm__C':[1,3,5]
    
]

并传递给GridSearchCV

pipelines=[random_forest_pipeline,svm_pipeline]
grid_search=GridSearchCV(pipelines,param_grid=parameters,cv=3,n_jobs=-1)
grid_search.fit(x_train,y_train)

但是,当我运行代码时,我得到一个错误

TypeError: estimator 应该是一个实现 'fit' 方法的估计器

不知道为什么会出现这个错误

【问题讨论】:

【参考方案1】:

问题在于pipelines=[random_forest_pipeline,svm_pipeline] 是一个没有fit 方法的列表。

即使您可以使其以这种方式工作,在某些时候'random_forest__min_samples_split':[50,100,250,500] 也会在svm_pipeline 中传递,这会引发错误。

ValueError:估计器管道的参数 svm 无效

您不能以这种方式混合 2 个管道,因为在某些时候您请求使用 random_forest__min_samples_split 的值评估 svm_pipeline,这是无效的。


解决方案:Fit a GridSearch object for the Random forest model and another GridSearch object for the SVC model

pipelines=[random_forest_pipeline,svm_pipeline]

grid_search_1=GridSearchCV(pipelines[0],param_grid=parameters[0],cv=3,n_jobs=-1)
grid_search_1.fit(X,y)

grid_search_2=GridSearchCV(pipelines[1],param_grid=parameters[1],cv=3,n_jobs=-1)
grid_search_2.fit(X,y)

完整代码:

random_forest_pipeline=Pipeline([   
    ('vectorizer',CountVectorizer(stop_words='english')),
    ('random_forest',RandomForestClassifier())
])
svm_pipeline=Pipeline([
    ('vectorizer',CountVectorizer(stop_words='english')),
    ('svm',LinearSVC())
])

parameters=[
    
        'vectorizer__max_features':[500,1000,1500],
        'random_forest__min_samples_split':[50,100,250,500]
    ,
    
        'vectorizer__max_features':[500,1000,1500],
        'svm__C':[1,3,5]
    
]

pipelines=[random_forest_pipeline,svm_pipeline]

# gridsearch only for the Random Forest model
grid_search_1 =GridSearchCV(pipelines[0],param_grid=parameters[0],cv=3,n_jobs=-1)
grid_search_1.fit(X,y)

# gridsearch only for the SVC model
grid_search_2 =GridSearchCV(pipelines[1],param_grid=parameters[1],cv=3,n_jobs=-1)
grid_search_2.fit(X,y)

编辑

如果您将模型明确定义到param_grid 列表中,则可以根据文档。

链接:https://scikit-learn.org/stable/auto_examples/compose/plot_compare_reduction.html?highlight=pipeline%20gridsearch

来自文档的代码:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_digits
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import Pipeline
from sklearn.svm import LinearSVC
from sklearn.decomposition import PCA, NMF
from sklearn.feature_selection import SelectKBest, chi2

print(__doc__)

pipe = Pipeline([
    # the reduce_dim stage is populated by the param_grid
    ('reduce_dim', 'passthrough'),
    ('classify', LinearSVC(dual=False, max_iter=10000))
])

N_FEATURES_OPTIONS = [2, 4, 8]
C_OPTIONS = [1, 10, 100, 1000]
param_grid = [
    
        'reduce_dim': [PCA(iterated_power=7), NMF()],
        'reduce_dim__n_components': N_FEATURES_OPTIONS,
        'classify__C': C_OPTIONS
    ,
    
        'reduce_dim': [SelectKBest(chi2)],
        'reduce_dim__k': N_FEATURES_OPTIONS,
        'classify__C': C_OPTIONS
    ,
]
reducer_labels = ['PCA', 'NMF', 'KBest(chi2)']

grid = GridSearchCV(pipe, n_jobs=1, param_grid=param_grid)
X, y = load_digits(return_X_y=True)
grid.fit(X, y)

【讨论】:

我一直在关注这个视频youtube.com/watch?v=DHxsNrL7Zfw,作者是如何做到不出错的? 在视频中,在 #17 单元格中,您可以看到一个循环 (for pipe in pipelines:),所以基本上它与我的答案相同 我认为也可以使用单个 GridSearchCV 来完成。请检查我的答案。 只有在您重新定义 parameters 列表中的模型时才可以。但是OP没有这种情况。反正我也报道过这个案子【参考方案2】:

很有可能在单个Pipeline/GridSearchCV 中完成,基于示例here。

您只需明确提及管道的scoring 方法,因为我们最初并未声明最终估算器。

例子:

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import LinearSVC


my_pipeline = Pipeline([
    ('vectorizer', CountVectorizer(stop_words='english')),
    ('clf', 'passthrough')
])


parameters = [
    
        'vectorizer__max_features': [500, 1000],
        'clf':[RandomForestClassifier()],
        'clf__min_samples_split':[50, 100,]
    ,
    
        'vectorizer__max_features': [500, 1000],
        'clf':[LinearSVC()],
        'clf__C':[1, 3]
    
]

grid_search = GridSearchCV(my_pipeline, param_grid=parameters, cv=3, n_jobs=-1, scoring='accuracy')
grid_search.fit(X, y)

grid_search.best_params_

> # 'clf': RandomForestClassifier(bootstrap=True, ccp_alpha=0.0, class_weight=None,
#                         criterion='gini', max_depth=None, max_features='auto',
#                         max_leaf_nodes=None, max_samples=None,
#                         min_impurity_decrease=0.0, min_impurity_split=None,
#                         min_samples_leaf=1, min_samples_split=100,
#                         min_weight_fraction_leaf=0.0, n_estimators=100,
#                         n_jobs=None, oob_score=False, random_state=None,
#                         verbose=0, warm_start=False),
#  'clf__min_samples_split': 100,
#  'vectorizer__max_features': 1000




pd.DataFrame(grid_search.cv_results_)[['param_vectorizer__max_features',
                                       'param_clf__min_samples_split',
                                       'param_clf__C','mean_test_score',
                                       'rank_test_score']]

【讨论】:

以上是关于如何使用 GridSearchCV 比较多个模型以及 python 中的管道和超参数调整的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 sklearn 中的 GridSearchCV 设置自己的评分以进行回归?

如何在 cv 中使用多个值运行 GridSearchCV

如何确定 GridSearchCV 中每个评分指标的最佳参数和最佳分数

用于多个模型的 GridSearchCV

有没有办法在科学工具包中预测 GridSearchCV 中的多个模型?

如何实现 sklearn 的 Estimator 接口以在 GridSearchCV 管道中使用?