Spec-Zone.ru › scikit-learn

Примечание

Перейти к концу, чтобы загрузить полный код примера. или запустить этот пример в браузере через JupyterLite или Binder

Настройка стратегии повторной подгонки для поиска по сетке с перекрестной проверкой

Этот пример демонстрирует, как классификатор оптимизируется с помощью перекрестной проверки, которая выполняется с помощью объекта GridSearchCV на наборе данных для обучения, который включает только половину доступных помеченных данных.

Производительность выбранных гиперпараметров и обученной модели затем измеряется на отдельном наборе данных для оценки, который не использовался на этапе выбора модели.

Более подробную информацию о доступных инструментах для выбора модели можно найти в разделах Перекрестная проверка: оценка производительности оценок и Настройка гиперпараметров оценок.

# Authors: The scikit-learn developers
# SPDX-License-Identifier: BSD-3-Clause

Набор данных

Мы будем работать с набором данных digits. Цель состоит в классификации изображений рукописных цифр. Мы трансформируем задачу в бинарную классификацию для лучшего понимания: цель — определить, является ли цифра 8 или нет.

from sklearn import datasets

digits = datasets.load_digits()

Для обучения классификатора на изображениях необходимо их сгладить в векторы. Каждое изображение размером 8 на 8 пикселей должно быть преобразовано в вектор из 64 пикселей. Таким образом, мы получим конечный массив данных размером (n_images, n_pixels).

n_samples = len(digits.images)
X = digits.images.reshape((n_samples, -1))
y = digits.target == 8
print(
    f"The number of images is {X.shape[0]} and each image contains {X.shape[1]} pixels"
)
The number of images is 1797 and each image contains 64 pixels

Как показано во введении, данные будут разделены на обучающий и тестовый наборы равного размера.

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=0)

Определение нашей стратегии поиска по сетке

Мы будем выбирать классификатор, подбирая лучшие гиперпараметры на разбиениях обучающего набора. Для этого нам нужно определить метрики, по которым будет выбираться лучший кандидат.

scores = ["precision", "recall"]

Мы также можем определить функцию, которая будет передана в параметр refit экземпляра GridSearchCV. Она реализует пользовательскую стратегию выбора лучшего кандидата из атрибута cv_results_ экземпляра GridSearchCV. После выбора кандидата он автоматически повторно подгоняется экземпляром GridSearchCV.

Здесь стратегия заключается в отборе моделей, которые лучше всего справляются с точностью и полнотой. Из отобранных моделей мы, наконец, выбираем самую быструю модель для предсказания. Обратите внимание, что эти пользовательские выборы полностью условны.

import pandas as pd


def print_dataframe(filtered_cv_results):
    """Pretty print for filtered dataframe"""
    for mean_precision, std_precision, mean_recall, std_recall, params in zip(
        filtered_cv_results["mean_test_precision"],
        filtered_cv_results["std_test_precision"],
        filtered_cv_results["mean_test_recall"],
        filtered_cv_results["std_test_recall"],
        filtered_cv_results["params"],
    ):
        print(
            f"precision: {mean_precision:0.3f} (±{std_precision:0.03f}),"
            f" recall: {mean_recall:0.3f} (±{std_recall:0.03f}),"
            f" for {params}"
        )
    print()


def refit_strategy(cv_results):
    """Define the strategy to select the best estimator.

    The strategy defined here is to filter-out all results below a precision threshold
    of 0.98, rank the remaining by recall and keep all models with one standard
    deviation of the best by recall. Once these models are selected, we can select the
    fastest model to predict.

    Parameters
    ----------
    cv_results : dict of numpy (masked) ndarrays
        CV results as returned by the `GridSearchCV`.

    Returns
    -------
    best_index : int
        The index of the best estimator as it appears in `cv_results`.
    """
    # print the info about the grid-search for the different scores
    precision_threshold = 0.98

    cv_results_ = pd.DataFrame(cv_results)
    print("All grid-search results:")
    print_dataframe(cv_results_)

    # Filter-out all results below the threshold
    high_precision_cv_results = cv_results_[
        cv_results_["mean_test_precision"] > precision_threshold
    ]

    print(f"Models with a precision higher than {precision_threshold}:")
    print_dataframe(high_precision_cv_results)

    high_precision_cv_results = high_precision_cv_results[
        [
            "mean_score_time",
            "mean_test_recall",
            "std_test_recall",
            "mean_test_precision",
            "std_test_precision",
            "rank_test_recall",
            "rank_test_precision",
            "params",
        ]
    ]

    # Select the most performant models in terms of recall
    # (within 1 sigma from the best)
    best_recall_std = high_precision_cv_results["mean_test_recall"].std()
    best_recall = high_precision_cv_results["mean_test_recall"].max()
    best_recall_threshold = best_recall - best_recall_std

    high_recall_cv_results = high_precision_cv_results[
        high_precision_cv_results["mean_test_recall"] > best_recall_threshold
    ]
    print(
        "Out of the previously selected high precision models, we keep all the\n"
        "the models within one standard deviation of the highest recall model:"
    )
    print_dataframe(high_recall_cv_results)

    # From the best candidates, select the fastest model to predict
    fastest_top_recall_high_precision_index = high_recall_cv_results[
        "mean_score_time"
    ].idxmin()

    print(
        "\nThe selected final model is the fastest to predict out of the previously\n"
        "selected subset of best models based on precision and recall.\n"
        "Its scoring time is:\n\n"
        f"{high_recall_cv_results.loc[fastest_top_recall_high_precision_index]}"
    )

    return fastest_top_recall_high_precision_index

Настройка гиперпараметров

После определения нашей стратегии выбора лучшей модели мы определяем значения гиперпараметров и создаем экземпляр поиска по сетке:

from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC

tuned_parameters = [
    {"kernel": ["rbf"], "gamma": [1e-3, 1e-4], "C": [1, 10, 100, 1000]},
    {"kernel": ["linear"], "C": [1, 10, 100, 1000]},
]

grid_search = GridSearchCV(
    SVC(), tuned_parameters, scoring=scores, refit=refit_strategy
)
grid_search.fit(X_train, y_train)
All grid-search results:
precision: 1.000 (±0.000), recall: 0.854 (±0.063), for {'C': 1, 'gamma': 0.001, 'kernel': 'rbf'}
precision: 1.000 (±0.000), recall: 0.257 (±0.061), for {'C': 1, 'gamma': 0.0001, 'kernel': 'rbf'}
precision: 1.000 (±0.000), recall: 0.877 (±0.069), for {'C': 10, 'gamma': 0.001, 'kernel': 'rbf'}
precision: 0.968 (±0.039), recall: 0.780 (±0.083), for {'C': 10, 'gamma': 0.0001, 'kernel': 'rbf'}
precision: 1.000 (±0.000), recall: 0.877 (±0.069), for {'C': 100, 'gamma': 0.001, 'kernel': 'rbf'}
precision: 0.905 (±0.058), recall: 0.889 (±0.074), for {'C': 100, 'gamma': 0.0001, 'kernel': 'rbf'}
precision: 1.000 (±0.000), recall: 0.877 (±0.069), for {'C': 1000, 'gamma': 0.001, 'kernel': 'rbf'}
precision: 0.904 (±0.058), recall: 0.890 (±0.073), for {'C': 1000, 'gamma': 0.0001, 'kernel': 'rbf'}
precision: 0.695 (±0.073), recall: 0.743 (±0.065), for {'C': 1, 'kernel': 'linear'}
precision: 0.643 (±0.066), recall: 0.757 (±0.066), for {'C': 10, 'kernel': 'linear'}
precision: 0.611 (±0.028), recall: 0.744 (±0.044), for {'C': 100, 'kernel': 'linear'}
precision: 0.618 (±0.039), recall: 0.744 (±0.044), for {'C': 1000, 'kernel': 'linear'}

Models with a precision higher than 0.98:
precision: 1.000 (±0.000), recall: 0.854 (±0.063), for {'C': 1, 'gamma': 0.001, 'kernel': 'rbf'}
precision: 1.000 (±0.000), recall: 0.257 (±0.061), for {'C': 1, 'gamma': 0.0001, 'kernel': 'rbf'}
precision: 1.000 (±0.000), recall: 0.877 (±0.069), for {'C': 10, 'gamma': 0.001, 'kernel': 'rbf'}
precision: 1.000 (±0.000), recall: 0.877 (±0.069), for {'C': 100, 'gamma': 0.001, 'kernel': 'rbf'}
precision: 1.000 (±0.000), recall: 0.877 (±0.069), for {'C': 1000, 'gamma': 0.001, 'kernel': 'rbf'}

Out of the previously selected high precision models, we keep all the
the models within one standard deviation of the highest recall model:
precision: 1.000 (±0.000), recall: 0.854 (±0.063), for {'C': 1, 'gamma': 0.001, 'kernel': 'rbf'}
precision: 1.000 (±0.000), recall: 0.877 (±0.069), for {'C': 10, 'gamma': 0.001, 'kernel': 'rbf'}
precision: 1.000 (±0.000), recall: 0.877 (±0.069), for {'C': 100, 'gamma': 0.001, 'kernel': 'rbf'}
precision: 1.000 (±0.000), recall: 0.877 (±0.069), for {'C': 1000, 'gamma': 0.001, 'kernel': 'rbf'}


The selected final model is the fastest to predict out of the previously
selected subset of best models based on precision and recall.
Its scoring time is:

mean_score_time                                         0.007247
mean_test_recall                                        0.853676
std_test_recall                                         0.063184
mean_test_precision                                          1.0
std_test_precision                                           0.0
rank_test_recall                                               6
rank_test_precision                                            1
params                 {'C': 1, 'gamma': 0.001, 'kernel': 'rbf'}
Name: 0, dtype: object
GridSearchCV(estimator=SVC(),
             param_grid=[{'C': [1, 10, 100, 1000], 'gamma': [0.001, 0.0001],
                          'kernel': ['rbf']},
                         {'C': [1, 10, 100, 1000], 'kernel': ['linear']}],
             refit=<function refit_strategy at 0x7656b7f1f1f0>,
             scoring=['precision', 'recall'])
В среде Jupyter, пожалуйста, перезапустите эту ячейку, чтобы отобразить HTML-представление, или доверьтесь блокноту.
На GitHub HTML-представление не может быть отображено, попробуйте загрузить эту страницу с nbviewer.org.
GridSearchCV(estimator=SVC(),
             param_grid=[{'C': [1, 10, 100, 1000], 'gamma': [0.001, 0.0001],
                          'kernel': ['rbf']},
                         {'C': [1, 10, 100, 1000], 'kernel': ['linear']}],
             refit=<function refit_strategy at 0x7656b7f1f1f0>,
             scoring=['precision', 'recall'])
SVC(C=1, gamma=0.001)
SVC(C=1, gamma=0.001)


Параметры, выбранные поиском по сетке с нашей пользовательской стратегией, следующие:

grid_search.best_params_
{'C': 1, 'gamma': 0.001, 'kernel': 'rbf'}

Наконец, мы оцениваем настроенную модель на оставшемся наборе для оценки: объект grid_search был автоматически повторно обучен на полном обучающем наборе с параметрами, выбранными нашей пользовательской стратегией повторной подгонки.

Мы можем использовать отчёт классификации для вычисления стандартных метрик классификации на оставшемся наборе:

from sklearn.metrics import classification_report

y_pred = grid_search.predict(X_test)
print(classification_report(y_test, y_pred))
              precision    recall  f1-score   support

       False       0.98      1.00      0.99       807
        True       1.00      0.85      0.92        92

    accuracy                           0.98       899
   macro avg       0.99      0.92      0.95       899
weighted avg       0.98      0.98      0.98       899

Примечание

Задача слишком простая: плато гиперпараметров слишком плоское, и выходная модель одинакова для точности и полноты с совпадением по качеству.

Общее время выполнения скрипта: (0 минут 12,361 секунды)

Launch binder
Launch JupyterLite

Download Jupyter notebook: plot_grid_search_digits.ipynb

Download Python source code: plot_grid_search_digits.py

Download zipped: plot_grid_search_digits.zip

Похожие примеры

Точность-полнота

Балансировка сложности модели и кросс-валидированной оценки

Сравнение случайного и сетчатого поиска для оценки гиперпараметров

Рекурсивное исключение признаков с перекрестной проверкой

© 2007–2025 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.6/auto_examples/model_selection/plot_grid_search_digits.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API