Получение определенных c классификаторов и данных из GridSearchCV - PullRequest
0 голосов
/ 08 мая 2020

Я запускаю сценарий классификации 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)

Затем я сохраняю объект GridSearchCV, используя pickle:

# 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 (я предполагаю, что они хранятся где-то в объекте, потому что для классификации нового набора проверки, это необходимо)
  • попробуйте несколько спецификаций c классификаторов с почти всеми лучшими параметрами, как определено поиском по сетке, но изменив входной параметр спецификаций c, т.е. k = 3, 5, 7
  • получить y_pred, т.е. прогнозы для каждого набора проверки для всех новых классификаторов, которые я тестировал выше

1 Ответ

3 голосов
/ 09 мая 2020

GridSearchCV не включает исходные данные (и было бы возможно абсурдно, если бы это было). Единственные данные, которые он включает, - это его собственная бухгалтерия, т. Е. Подробные оценки и параметры, проверенные для каждого сгиба резюме. Возвращенный best_estimator_ - единственное, что необходимо для применения модели к любым новым встреченным данным, но если, как вы говорите, вы хотите глубже изучить детали, полные результаты будут возвращены в его атрибуте cv_results_.

Адаптация примера из документации к классификатору knn с вашей собственной knn_parameters сеткой (но удаление 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')

Итак, как уже говорилось, этот последний результат сообщает вам все, что вам нужно знать, чтобы применить алгоритм к любым новым данным (проверка, проверка , из развертывания и др. c). Кроме того, вы можете обнаружить, что фактическое удаление записи n_jobs из сетки knn_parameters и запрос вместо n_jobs=-1 в объекте GridSearchCV приводит к намного более быстрой процедуре 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 - так что на самом деле здесь у нас есть более одной «лучших» моделей (то есть комбинаций параметров)! Хотя здесь это, скорее всего, связано с относительной простотой используемого набора данных радужной оболочки, в принципе нет причин, по которым это не может произойти и в реальном случае. В таких случаях возвращенный 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), вместо того, чтобы просто полагаться на максимальный средний балл, который возвращает автоматическая c процедура.

Надеюсь, этого будет достаточно, чтобы вы начали ...

...