在 GridSearchCV 的管道中替代不同的模型

Posted

技术标签:

【中文标题】在 GridSearchCV 的管道中替代不同的模型【英文标题】:Alternate different models in Pipeline for GridSearchCV 【发布时间】:2018-10-20 07:36:12 【问题描述】:

我想在 sklearn 中构建一个 Pipeline 并使用 GridSearchCV 测试不同的模型。

只是一个例子(请不要注意选择了哪些特定型号):

reg = LogisticRegression()

proj1 = PCA(n_components=2)
proj2 = MDS()
proj3 = TSNE()

pipe = [('proj', proj1), ('reg' , reg)]

pipe = Pipeline(pipe)

param_grid = 
    'reg__c': [0.01, 0.1, 1],


clf = GridSearchCV(pipe, param_grid = param_grid)

这里如果我想尝试不同的降维模型,我需要编写不同的管道并手动比较它们。有什么简单的方法吗?

我想出的一个解决方案是定义我自己的从基估计器派生的类:

class Projection(BaseEstimator):
    def __init__(self, est_name):
        if est_name == "MDS":
            self.model = MDS()
        ...
    ...
    def fit_transform(self, X):
        return self.model.fit_transform(X)

我认为它会起作用,我只是创建一个 Projection 对象并将其传递给 Pipeline,使用估计器的名称作为它的参数。

但对我来说,这种方式有点混乱且不可扩展:每次我想比较不同的模型时,它都会让我定义新的类。同样为了继续这个解决方案,人们可​​以实现一个做同样工作的类,但使用任意一组模型。这对我来说似乎过于复杂了。

比较不同模型最自然、最符合 Python 的方法是什么?

【问题讨论】:

您可以直接使用估算器作为参数。 【参考方案1】:

不需要在参数网格中为估计器名称添加前缀的替代解决方案如下:

from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression

# the models that you want to compare
models = 
    'RandomForestClassifier': RandomForestClassifier(),
    'KNeighboursClassifier': KNeighborsClassifier(),
    'LogisticRegression': LogisticRegression()


# the optimisation parameters for each of the above models
params = 
    'RandomForestClassifier': 
            "n_estimators"      : [100, 200, 500, 1000],
            "max_features"      : ["auto", "sqrt", "log2"],
            "bootstrap": [True],
            "criterion": ['gini', 'entropy'],
            "oob_score": [True, False]
            ,
    'KNeighboursClassifier': 
        'n_neighbors': np.arange(3, 15),
        'weights': ['uniform', 'distance'],
        'algorithm': ['ball_tree', 'kd_tree', 'brute']
        ,
    'LogisticRegression': 
        'solver': ['newton-cg', 'sag', 'lbfgs'],
        'multi_class': ['ovr', 'multinomial']
          

你可以定义:

from sklearn.model_selection import GridSearchCV

def fit(train_features, train_actuals):
        """
        fits the list of models to the training data, thereby obtaining in each 
        case an evaluation score after GridSearchCV cross-validation
        """
        for name in models.keys():
            est = models[name]
            est_params = params[name]
            gscv = GridSearchCV(estimator=est, param_grid=est_params, cv=5)
            gscv.fit(train_features, train_actuals)
            print("best parameters are: ".format(gscv.best_estimator_))

基本上运行在不同的模型中,每个模型通过字典引用自己的一组优化参数。当然不要忘记将模型和参数字典传递给fit 函数,以防您没有将它们作为全局变量。查看at this GitHub project 以获得更完整的概述。

【讨论】:

gscv.fit(train_actuals, train_features) 一旦我遍历我的所有模型以使用网格搜索找到最佳超参数,我是否使用给出最高“最佳得分值”的模型?例如如果在完成上述操作后我发现随机森林最佳分数= 0.8 和逻辑回归最佳分数= 0.9 将进行逻辑回归? 原则上是的,您会采用一个模型并在整个数据集上对其进行训练。但请注意,交叉验证分数仅表示对未知测试数据可能遇到的错误。 我认为这不是一个完整的答案,因为它没有显示如何嵌套管道的其他步骤。我已经测试了一点,但找不到你的语法。【参考方案2】:

假设您想使用 PCA 和 TruncatedSVD 作为降维步骤。

pca = decomposition.PCA()
svd = decomposition.TruncatedSVD()
svm = SVC()
n_components = [20, 40, 64]

你可以这样做:

pipe = Pipeline(steps=[('reduction', pca), ('svm', svm)])

# Change params_grid -> Instead of dict, make it a list of dict
# In the first element, pass parameters related to pca, and in second related to svd

params_grid = [
'svm__C': [1, 10, 100, 1000],
'svm__kernel': ['linear', 'rbf'],
'svm__gamma': [0.001, 0.0001],
'reduction':pca,
'reduction__n_components': n_components,
,

'svm__C': [1, 10, 100, 1000],
'svm__kernel': ['linear', 'rbf'],
'svm__gamma': [0.001, 0.0001],
'reduction':svd,
'reduction__n_components': n_components,
'reduction__algorithm':['randomized']
]

现在只需将管道对象传递给 gridsearchCV

grd = GridSearchCV(pipe, param_grid = params_grid)

调用grd.fit() 将在params_grid 列表的两个元素上搜索参数,一次使用来自one 的所有值。

更多详情请看我的其他回答:"Parallel" pipeline to get best model using gridsearch

【讨论】:

我是否理解正确,还需要在 param_grid 的两个元素中包含 'reduction': algo_name ?否则 svd 不用于训练分类器(如果我理解你的其他答案,这对我有用,正确)。 @sooobus 啊,是的,这是我的错误。现已更正。谢谢。 @VivekKumar 很好的答案!仅供参考,在 scikit-learn 0.23(可能还有早期版本)中,参数网格中的单个值需要用一个元素包装在一个列表中,否则会出错。因此,您必须使用 'reduction':[pca] 和 'reduction':[svd] 才能使其工作。

以上是关于在 GridSearchCV 的管道中替代不同的模型的主要内容,如果未能解决你的问题,请参考以下文章

在 GridSearch CV 之后进行预测时是不是遵循管道步骤

如何使用 GridSearchCV 在嵌套管道中测试预处理组合?

使用 `GridSearchCV` 测试完全从管道中删除步骤的效果? [复制]

Scikit Learn GridSearchCV 和 pipeline 使用不同的方法

使用 GridSearchCV scikit-learn 在管道中的 KMeans

在 Scikit Learn 中使用网格搜索 (GridSearchCV) 和管道的支持向量回归 (SVR) 中的系数