从 GridSearchCV 中检索特定的分类器和数据
Retrieving specific classifiers and data from GridSearchCV
我是运行一个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
即我在上面测试的所有新分类器的每个验证集的预测
GridSearchCV 不包含原始数据(如果包含原始数据,则可以说是荒谬的)。它包含的唯一数据是它自己的簿记,即每次 CV 折叠尝试的详细分数和参数。 best_estimator_
returned 是将模型应用于遇到的任何新数据唯一需要的东西,但是如果像您所说的那样,您想更深入地挖掘细节,完整的结果是 returned 在其 cv_results_
属性中。
将 documentation 中的示例与您自己的 knn_parameters
网格适配到 knn 分类器(但删除 n_jobs
,这只会影响拟合速度,而不是真正的超参数算法),并为简单起见保持 cv=3
,我们有:
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
会导致 much 更快的 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_
属性中 return 编辑,您甚至可以将其导入 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
- 所以实际上我们有不止一种“最佳”模型(即参数组合)!虽然这很可能是由于所用鸢尾花数据集相对简单,但原则上没有理由不能在真实案例中发生。在这种情况下,returned 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
尝试的模型总数中)!所以,实际上你可以 select 在更多的选择中,甚至使用其他额外的标准,比如 returned 分数的标准差(越少越好,虽然这里是最小值0), 而不是简单地依赖最大平均分数,这是自动程序将 return.
希望这些足以让您入门...
我是运行一个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
即我在上面测试的所有新分类器的每个验证集的预测
GridSearchCV 不包含原始数据(如果包含原始数据,则可以说是荒谬的)。它包含的唯一数据是它自己的簿记,即每次 CV 折叠尝试的详细分数和参数。 best_estimator_
returned 是将模型应用于遇到的任何新数据唯一需要的东西,但是如果像您所说的那样,您想更深入地挖掘细节,完整的结果是 returned 在其 cv_results_
属性中。
将 documentation 中的示例与您自己的 knn_parameters
网格适配到 knn 分类器(但删除 n_jobs
,这只会影响拟合速度,而不是真正的超参数算法),并为简单起见保持 cv=3
,我们有:
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
会导致 much 更快的 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_
属性中 return 编辑,您甚至可以将其导入 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
- 所以实际上我们有不止一种“最佳”模型(即参数组合)!虽然这很可能是由于所用鸢尾花数据集相对简单,但原则上没有理由不能在真实案例中发生。在这种情况下,returned 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
尝试的模型总数中)!所以,实际上你可以 select 在更多的选择中,甚至使用其他额外的标准,比如 returned 分数的标准差(越少越好,虽然这里是最小值0), 而不是简单地依赖最大平均分数,这是自动程序将 return.
希望这些足以让您入门...