【问题标题】:Retrieving specific classifiers and data from GridSearchCV从 GridSearchCV 检索特定的分类器和数据
【发布时间】:2020-08-24 12:29:48
【问题描述】:

我正在使用以下代码在服务器上运行 Python 3 分类脚本:

# define knn classifier for transformed data
knn_classifier = neighbors.KNeighborsClassifier()

# define KNN parameters
knn_parameters = [{
    'n_neighbors': [1,3,5,7, 9, 11],
    'leaf_size': [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60],
    'algorithm': ['auto', 'ball_tree', 'kd_tree', 'brute'],
    'n_jobs': [-1],
    'weights': ['uniform', 'distance']}]

# Stratified k-fold (default for classifier)
# n = 5 folds is default
knn_models = GridSearchCV(estimator = knn_classifier, param_grid = knn_parameters, scoring = 'accuracy')

# fit grid search models to transformed training data
knn_models.fit(X_train_transformed, y_train)

然后我使用pickle 保存GridSearchCV 对象:

# save model
with open('knn_models.pickle', 'wb') as f:
    pickle.dump(knn_models, f)

所以我可以通过运行在本地机器上的较小数据集上测试分类器:

knn_models = pickle.load(open("knn_models.pickle", "rb"))
validation_knn_model = knn_models.best_estimator_

如果我只想评估验证集上的最佳估计器,这很好。但我真正想做的是:

  • GridSearchCV 对象中提取原始数据(我假设它存储在对象中的某个位置,因为要对新的验证集进行分类,这是必需的)
  • 尝试使用几乎所有由网格搜索确定的最佳参数的特定分类器,但更改特定输入参数,即k = 3, 5, 7
  • 检索y_pred,即我在上面测试的所有新分类器的每个验证集的预测

【问题讨论】:

    标签: python machine-learning scikit-learn cross-validation grid-search


    【解决方案1】:

    GridSearchCV 不包含原始数据(如果包含,那将是荒谬的)。它包含的唯一数据是它自己的簿记,即每个 CV 折叠尝试的详细分数和参数。返回的best_estimator_ 是将模型应用于遇到的任何新数据所需的唯一内容,但如果如您所说,您想更深入地挖掘细节,完整的结果将在其cv_results_ 属性中返回。

    用你自己的knn_parameters网格将documentation的例子改成knn分类器(但是去掉n_jobs,这只会影响拟合速度,并不是算法的真正超参数),并保持@ 987654326@ 为简单起见,我们有:

    from sklearn.neighbors import KNeighborsClassifier
    from sklearn.datasets import load_iris
    from sklearn.model_selection import GridSearchCV
    import pandas as pd
    
    iris = load_iris()
    knn_parameters = [{
        'n_neighbors': [1,3,5,7, 9, 11],
        'leaf_size': [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60],
        'algorithm': ['auto', 'ball_tree', 'kd_tree', 'brute'],
        'weights': ['uniform', 'distance']}]
    
    knn_classifier = KNeighborsClassifier()
    clf = GridSearchCV(estimator = knn_classifier, param_grid = knn_parameters, scoring = 'accuracy', n_jobs=-1, cv=3)
    clf.fit(iris.data, iris.target)
    
    clf.best_estimator_
    # result:
    KNeighborsClassifier(algorithm='auto', leaf_size=5, metric='minkowski',
                         metric_params=None, n_jobs=None, n_neighbors=5, p=2,
                         weights='uniform')
    

    因此,如前所述,最后一个结果告诉您将算法应用于任何新数据(验证、测试、部署等)所需的所有知识。此外,您可能会发现实际上从knn_parameters 网格中删除n_jobs 条目并在GridSearchCV 对象中请求n_jobs=-1 会导致快得多 的CV 过程。不过,如果您想在最终模型中使用 n_jobs=-1,您可以轻松地操作 best_estimator_ 来实现:

    clf.best_estimator_.n_jobs = -1
    clf.best_estimator_
    # result
    KNeighborsClassifier(algorithm='auto', leaf_size=5, metric='minkowski',
                         metric_params=None, n_jobs=-1, n_neighbors=5, p=2,
                         weights='uniform')
    

    这实际上回答了您的第二个问题,因为您也可以类似地操纵 best_estimator_ 来更改其他超参数。

    因此,找到最佳模型是大多数人会停下来的地方。但是,如果出于任何原因,您想进一步深入了解整个网格搜索过程的细节,详细结果将在 cv_results_ 属性中返回,您甚至可以将其导入 pandas 数据框以便于检查:

    cv_results = pd.DataFrame.from_dict(clf.cv_results_)
    

    例如,cv_results 数据框包含一列 rank_test_score,顾名思义,该列包含每个参数组合的排名:

    cv_results['rank_test_score']
    # result:
    0      481
    1      481
    2      145
    3      145
    4        1
          ... 
    571      1
    572    145
    573    145
    574    433
    575      1
    Name: rank_test_score, Length: 576, dtype: int32
    

    这里1 表示最佳,您可以很容易地看到有多个组合被列为1 - 所以实际上这里我们有多个“最佳”模型(即参数组合)!虽然这很可能是由于使用的 iris 数据集相对简单,但原则上没有理由在真实案例中也不会发生这种情况。在这种情况下,返回的 best_estimator_ 只是这些事件中的第一个 - 这里是组合编号 4:

    cv_results.iloc[4]
    # result:
    mean_fit_time                                              0.000669559
    std_fit_time                                               1.55811e-05
    mean_score_time                                             0.00474652
    std_score_time                                             0.000488042
    param_algorithm                                                   auto
    param_leaf_size                                                      5
    param_n_neighbors                                                    5
    param_weights                                                  uniform
    params               {'algorithm': 'auto', 'leaf_size': 5, 'n_neigh...
    split0_test_score                                                 0.98
    split1_test_score                                                 0.98
    split2_test_score                                                 0.98
    mean_test_score                                                   0.98
    std_test_score                                                       0
    rank_test_score                                                      1
    Name: 4, dtype: object
    

    您可以很容易地看到它与我们上面的best_estimator_ 具有相同的参数。但现在您可以检查所有“最佳”模型,只需:

    cv_results.loc[cv_results['rank_test_score']==1]
    

    在我的情况下,产生不少于 144 个模型(在尝试的 6*12*4*2 = 576 个模型总数中)!因此,您实际上可以在更多选项中进行选择,甚至可以使用其他附加标准,例如返回分数的标准差(越小越好,尽管这里它的最小值为 0),而不是简单地依赖于最大平均分,这是自动程序将返回的值。

    希望这些足以让你开始......

    【讨论】:

    • 这是一个很棒的答案,谢谢。我将不得不研究歧义:多个 best_estimators 和参数组合。再次感谢。
    猜你喜欢
    • 2018-05-28
    • 2020-09-21
    • 1970-01-01
    • 2018-12-09
    • 1970-01-01
    • 2019-03-09
    • 1970-01-01
    • 2022-06-24
    相关资源
    最近更新 更多