Spec-Zone.ru › scikit-learn

Примечание

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

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

В этом примере показано, как сбалансировать сложность модели и оценку при кросс-валидации: найти приемлемую точность в пределах одного стандартного отклонения от наилучшей оценки точности, одновременно минимизируя число компонентов PCA [1]. Для выбора оптимальной модели используется GridSearchCV с настраиваемой функцией обратного обучения.

На рисунке показан компромисс между оценкой при кросс-валидации и числом компонентов PCA. Сбалансированный вариант — это когда n_components=10 и accuracy=0.88, то есть значение попадает в диапазон одного стандартного отклонения от наилучшей оценки точности.

Литература

[1]

Hastie, T., Tibshirani, R., Friedman, J. (2001). Оценка и выбор модели. Элементы статистического обучения (с. 219–260). Нью-Йорк, штат Нью-Йорк, США: Springer New York Inc.

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

import matplotlib.pyplot as plt
import numpy as np
import polars as pl

from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV, ShuffleSplit
from sklearn.pipeline import Pipeline

Введение

При настройке гиперпараметров мы часто стремимся найти баланс между сложностью модели и её производительностью. Распространённый подход — правило «одной стандартной ошибки»: выбрать самую простую модель, производительность которой находится в пределах одной стандартной ошибки от производительности наилучшей модели. Это помогает избежать переобучения: если производительность более простых моделей статистически сопоставима с производительностью более сложных моделей, предпочтение отдаётся более простым.

Вспомогательные функции

Определим две вспомогательные функции:

  1. lower_bound: вычисляет порог приемлемой производительности (наилучшая оценка − 1 стандартное отклонение)
  2. best_low_complexity: выбирает модель с наименьшим числом компонентов PCA, производительность которой превышает этот порог
def lower_bound(cv_results):
    """
    Calculate the lower bound within 1 standard deviation
    of the best `mean_test_scores`.

    Parameters
    ----------
    cv_results : dict of numpy(masked) ndarrays
        See attribute cv_results_ of `GridSearchCV`

    Returns
    -------
    float
        Lower bound within 1 standard deviation of the
        best `mean_test_score`.
    """
    best_score_idx = np.argmax(cv_results["mean_test_score"])

    return (
        cv_results["mean_test_score"][best_score_idx]
        - cv_results["std_test_score"][best_score_idx]
    )


def best_low_complexity(cv_results):
    """
    Balance model complexity with cross-validated score.

    Parameters
    ----------
    cv_results : dict of numpy(masked) ndarrays
        See attribute cv_results_ of `GridSearchCV`.

    Return
    ------
    int
        Index of a model that has the fewest PCA components
        while has its test score within 1 standard deviation of the best
        `mean_test_score`.
    """
    threshold = lower_bound(cv_results)
    candidate_idx = np.flatnonzero(cv_results["mean_test_score"] >= threshold)
    best_idx = candidate_idx[
        cv_results["param_reduce_dim__n_components"][candidate_idx].argmin()
    ]
    return best_idx

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

Создадим конвейер из двух этапов:

  1. Снижение размерности с помощью PCA
  2. Классификация с помощью LogisticRegression

Для определения оптимальной сложности мы выполним поиск по различным значениям числа компонентов PCA.

pipe = Pipeline(
    [
        ("reduce_dim", PCA(random_state=42)),
        ("classify", LogisticRegression(random_state=42, C=0.01, max_iter=1000)),
    ]
)

param_grid = {"reduce_dim__n_components": [6, 8, 10, 15, 20, 25, 35, 45, 55]}

Выполнение поиска с помощью GridSearchCV

Мы используем GridSearchCV и передаём нашу настраиваемую функцию best_low_complexity в качестве параметра обратного обучения. Эта функция выберет модель с наименьшим числом компонентов PCA, производительность которой при этом остаётся в пределах одного стандартного отклонения от наилучшей модели.

grid = GridSearchCV(
    pipe,
    # Use a non-stratified CV strategy to make sure that the inter-fold
    # standard deviation of the test scores is informative.
    cv=ShuffleSplit(n_splits=30, random_state=0),
    n_jobs=1,  # increase this on your machine to use more physical cores
    param_grid=param_grid,
    scoring="accuracy",
    refit=best_low_complexity,
    return_train_score=True,
)

Загрузка набора данных цифр и обучение модели

X, y = load_digits(return_X_y=True)
grid.fit(X, y)
GridSearchCV(cv=ShuffleSplit(n_splits=30, random_state=0, test_size=None, train_size=None),
             estimator=Pipeline(steps=[('reduce_dim', PCA(random_state=42)),
                                       ('classify',
                                        LogisticRegression(C=0.01,
                                                           max_iter=1000,
                                                           random_state=42))]),
             n_jobs=1,
             param_grid={'reduce_dim__n_components': [6, 8, 10, 15, 20, 25, 35,
                                                      45, 55]},
             refit=<function best_low_complexity at 0x784117c45fe0>,
             return_train_score=True, scoring='accuracy')
В среде Jupyter повторно запустите эту ячейку, чтобы отобразить представление HTML, или доверьте работу этому блокноту.
На GitHub невозможно отобразить представление HTML. Попробуйте открыть эту страницу на nbviewer.org.
Параметры
estimator estimator: объект-оценщик

Предполагается, что объект реализует интерфейс оценщика scikit-learn.
Оценщик должен предоставлять функцию ``score``
или необходимо передать параметр ``scoring``.
Pipeline(step...m_state=42))])
param_grid param_grid: словарь или список словарей

Словарь, в котором ключи — имена параметров (`str`), а значения —
списки значений параметров для перебора, либо список таких
словарей. В последнем случае выполняется поиск по сеткам,
заданным каждым словарём в списке. Это позволяет выполнять поиск
по любой последовательности значений параметров.
{'reduce_dim__n_components': [6, 8, ...]}
scoring scoring: строка, вызываемый объект, список, кортеж или словарь, по умолчанию=None

Стратегия оценки производительности модели, проверенной методом
кросс-валидации, на тестовом наборе.

Если `scoring` задаёт одну метрику, можно использовать:

- одну строку (см. :ref:`scoring_string_names`);
- вызываемый объект (см. :ref:`scoring_callable`), возвращающий одно значение;
- `None` — в этом случае используется
:ref:`критерий оценки по умолчанию для оценщика <scoring_api_overview>`.

Если `scoring` задаёт несколько метрик, можно использовать:

- список или кортеж уникальных строк;
- вызываемый объект, возвращающий словарь, в котором ключами являются
имена метрик, а значениями — оценки метрик;
- словарь, в котором ключами являются имена метрик, а значениями — вызываемые объекты.

Пример см. в разделе :ref:`multimetric_grid_search`.
'accuracy'
n_jobs n_jobs: целое число, по умолчанию=None

Число параллельно выполняемых задач.
``None`` означает 1, если только выполнение не находится в контексте :obj:`joblib.parallel_backend`.
``-1`` означает использование всех процессоров. Подробнее см. в :term:`глоссарии <n_jobs>`.

.. versionchanged:: v0.20
Значение по умолчанию для `n_jobs` изменено с 1 на None
1
refit refit: логическое значение, строка или вызываемый объект, по умолчанию=True

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

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

Если при выборе наилучшего оценщика важны не только максимальные оценки,
параметру ``refit`` можно присвоить функцию, которая
возвращает выбранный ``best_index_`` на основе ``cv_results_``. В этом
случае значения ``best_estimator_`` и ``best_params_`` будут заданы
в соответствии с возвращённым ``best_index_``, а атрибут ``best_score_``
будет недоступен.

Повторно обученный оценщик доступен через атрибут ``best_estimator_``
и позволяет напрямую использовать ``predict`` для этого экземпляра
``GridSearchCV``.

Также при оценке нескольких метрик атрибуты ``best_index_``,
``best_score_`` и ``best_params_`` будут доступны только в том случае,
если задан ``refit``; все они будут определяться относительно указанной
метрики.

Подробнее об оценке нескольких метрик см. в описании параметра ``scoring``.

О том, как разработать собственную стратегию выбора с помощью вызываемого объекта,
передаваемого через `refit`, см. :ref:`sphx_glr_auto_examples_model_selection_plot_grid_search_digits.py`.

Пример использования ``refit=callable`` для балансировки сложности модели
и оценки при кросс-валидации см. в :ref:`этом примере
<sphx_glr_auto_examples_model_selection_plot_grid_search_refit_callable.py>`.

.. versionchanged:: 0.20
Добавлена поддержка вызываемых объектов.
<function bes...x784117c45fe0>
cv cv: целое число, генератор кросс-валидации или итерируемый объект, по умолчанию=None

Определяет стратегию разбиения для кросс-валидации.
Для cv можно указать:

- None — использовать кросс-валидацию по умолчанию с 5 блоками;
- целое число — задать число блоков в `(Stratified)KFold`;
- :term:`разбиение CV`;
- итерируемый объект, выдающий разбиения (train, test) в виде массивов индексов.

Для целочисленного значения или None, если оценщик является классификатором, а ``y``
содержит два или несколько классов, используется :class:`StratifiedKFold`. Во всех
остальных случаях используется :class:`KFold`. Эти средства разбиения создаются
с параметром `shuffle=False`, поэтому при каждом вызове разбиения будут одинаковыми.

Описание доступных стратегий кросс-валидации см. в :ref:`руководстве пользователя <cross_validation>`.

.. versionchanged:: 0.22
Значение ``cv`` по умолчанию при None изменено с 3 блоков на 5.
ShuffleSplit(...ain_size=None)
return_train_score return_train_score: логическое значение, по умолчанию=False

Если ``False``, атрибут ``cv_results_`` не будет содержать оценки
на обучающем наборе.
Вычисление оценок на обучающем наборе помогает понять, как различные
значения параметров влияют на компромисс между переобучением и недообучением.
Однако вычисление оценок на обучающем наборе может быть затратным с точки зрения
вычислений и не является строго необходимым для выбора параметров,
обеспечивающих наилучшую обобщающую способность.

.. versionadded:: 0.19

.. versionchanged:: 0.21
Значение по умолчанию изменено с ``True`` на ``False``
True
verbose verbose: целое число, по умолчанию=0

Управляет подробностью информации, выводимой во время обучения: чем больше
значение, тем подробнее журнал.

- 0 : сообщения не выводятся;
- >=1 : сводка общего числа запусков обучения;
- >=2 : время вычислений для каждого блока и кандидата параметров;
- >=3 : индексы блоков и оценки;
- >=10 : индексы кандидатов параметров и сообщения START перед каждым запуском обучения.
0
pre_dispatch pre_dispatch: целое число или строка, по умолчанию='2*n_jobs'

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

- None: все задачи немедленно создаются и запускаются. Используйте
это значение для лёгких и быстро выполняющихся задач, чтобы избежать задержек
из-за запуска задач по мере необходимости;
- целое число: точное общее число запускаемых задач;
- строка: выражение, задающее значение как функцию от n_jobs, например '2*n_jobs'
'2*n_jobs'
error_score error_score: 'raise' или числовое значение, по умолчанию=np.nan

Значение оценки, присваиваемое в случае ошибки при обучении оценщика.
Если задано значение 'raise', вызывается исключение. Если указано числовое значение,
вызывается FitFailedWarning. Этот параметр не влияет на этап повторного обучения,
на котором ошибка будет вызвана в любом случае.
nan
Атрибуты обученной модели
Имя Тип Значение
best_estimator_ best_estimator_: estimator

Оцениватель, выбранный в результате поиска, то есть оцениватель,
который показал наибольшее значение метрики (или наименьшие потери, если они указаны)
на отложенных данных. Недоступно, если ``refit=False``.

Дополнительную информацию о допустимых значениях см. в параметре ``refit``.
Pipeline Pipeline(step...m_state=42))])
best_index_ best_index_: int

Индекс (в массивах ``cv_results_``), соответствующий наилучшему
значению параметров кандидата.

Словарь ``search.cv_results_['params'][search.best_index_]`` содержит
значение параметров лучшей модели, которая обеспечивает наибольшее
среднее значение метрики (``search.best_score_``).

При оценке по нескольким метрикам этот атрибут доступен, только если указан параметр ``refit``.
int64 np.int64(5)
best_params_ best_params_: dict

Значение параметров, обеспечившее наилучшие результаты на отложенных данных.

При оценке по нескольким метрикам этот атрибут доступен, только если указан параметр ``refit``.
dict {'re...ts': 25}
classes_ classes_: ndarray of shape (n_classes,)

Метки классов. Атрибут доступен, только если указан параметр ``refit`` и
базовый оцениватель является классификатором.
ndarray[int64](10,) [0,1,2,...,7,8,9]
cv_results_ cv_results_: dict of numpy (masked) ndarrays

Словарь, в котором ключи — это заголовки столбцов, а значения — столбцы; его можно
импортировать в ``DataFrame`` библиотеки pandas.

Например, приведённая ниже таблица

+------------+-----------+------------+-----------------+---+---------+
|param_kernel|param_gamma|param_degree|split0_test_score|...|rank_t...|
+============+===========+============+=================+===+=========+
| 'poly' | -- | 2 | 0.80 |...| 2 |
+------------+-----------+------------+-----------------+---+---------+
| 'poly' | -- | 3 | 0.70 |...| 4 |
+------------+-----------+------------+-----------------+---+---------+
| 'rbf' | 0.1 | -- | 0.80 |...| 3 |
+------------+-----------+------------+-----------------+---+---------+
| 'rbf' | 0.2 | -- | 0.93 |...| 1 |
+------------+-----------+------------+-----------------+---+---------+

будет представлена словарём ``cv_results_`` следующего вида::

{
'param_kernel': masked_array(data = ['poly', 'poly', 'rbf', 'rbf'],
mask = [False False False False]...)
'param_gamma': masked_array(data = [-- -- 0.1 0.2],
mask = [ True True False False]...),
'param_degree': masked_array(data = [2.0 3.0 -- --],
mask = [False False True True]...),
'split0_test_score' : [0.80, 0.70, 0.80, 0.93],
'split1_test_score' : [0.82, 0.50, 0.70, 0.78],
'mean_test_score' : [0.81, 0.60, 0.75, 0.85],
'std_test_score' : [0.01, 0.10, 0.05, 0.08],
'rank_test_score' : [2, 4, 3, 1],
'split0_train_score' : [0.80, 0.92, 0.70, 0.93],
'split1_train_score' : [0.82, 0.55, 0.70, 0.87],
'mean_train_score' : [0.81, 0.74, 0.70, 0.90],
'std_train_score' : [0.01, 0.19, 0.00, 0.03],
'mean_fit_time' : [0.73, 0.63, 0.43, 0.49],
'std_fit_time' : [0.01, 0.02, 0.01, 0.01],
'mean_score_time' : [0.01, 0.06, 0.04, 0.04],
'std_score_time' : [0.00, 0.00, 0.00, 0.01],
'params' : [{'kernel': 'poly', 'degree': 2}, ...],
}

Пример визуализации и интерпретации результатов GridSearch см.
в :ref:`sphx_glr_auto_examples_model_selection_plot_grid_search_stats.py`.

ПРИМЕЧАНИЕ

Ключ ``'params'`` используется для хранения списка словарей со значениями
параметров для всех кандидатов.

Значения ``mean_fit_time``, ``std_fit_time``, ``mean_score_time`` и
``std_score_time`` указаны в секундах.

При оценке по нескольким метрикам значения всех метрик доступны в словаре ``cv_results_``
по ключам, оканчивающимся именем соответствующей метрики (``'_<scorer_name>'``), а не на ``'_score'``, как показано
выше. ('split0_test_precision', 'mean_train_precision' и т. д.)
dict {'me...me': array([0.1227..., 0.07176538]), 'me...me': array([0.0016..., 0.00176717]), 'me...re': array([0.8631..., 0.97166667]), 'me...re': array([0.8696..., 0.99297052]), ...}
multimetric_ multimetric_: bool

Вычисляют ли метрики несколько показателей.
bool False
n_features_in_ n_features_in_: int

Количество признаков, использованных во время :term:`fit`. Определяется, только если
определён `best_estimator_` (подробную информацию см. в документации к параметру
`refit`) и этот `best_estimator_` предоставляет атрибут
`n_features_in_` после обучения.

.. versionadded:: 0.24
int 64
n_splits_ n_splits_: int

Количество разбиений (фолдов/итераций) при перекрёстной проверке.
int 30
refit_time_ refit_time_: float

Время в секундах, затраченное на повторное обучение лучшей модели на всём наборе данных.

Атрибут доступен, только если ``refit`` не равен False.

.. versionadded:: 0.20
float 0.06855
scorer_ scorer_: function or a dict

Функция оценки, используемая на отложенных данных для выбора наилучших
параметров модели.

При оценке по нескольким метрикам этот атрибут содержит проверенный
словарь ``scoring``, сопоставляющий ключ метрики с вызываемым объектом оценки.
_Scorer make_scorer(a...hod='predict')
Параметры
n_components n_components: int, float или 'mle', по умолчанию=None

Количество сохраняемых компонент.
Если n_components не задан, сохраняются все компоненты::

n_components == min(n_samples, n_features)

Если ``n_components == 'mle'`` и ``svd_solver == 'full'``, для оценки размерности используется
критерий MLE Минкá. При ``n_components == 'mle'``
значение ``svd_solver == 'auto'`` будет интерпретироваться как ``svd_solver == 'full'``.

Если ``0 < n_components < 1`` и ``svd_solver == 'full'``, выбирается
такое количество компонент, чтобы объяснённая дисперсия была
больше значения в процентах, заданного параметром n_components.

Если ``svd_solver == 'arpack'``, количество компонент должно быть
строго меньше минимума из n_features и n_samples.

Таким образом, в случае None получается::

n_components == min(n_samples, n_features) - 1
25
random_state random_state: int, экземпляр RandomState или None, по умолчанию=None

Используется при выборе решателей 'arpack' или 'randomized'. Передайте целое число,
чтобы получать воспроизводимые результаты при нескольких вызовах функции.
См. :term:`Глоссарий <random_state>`.

.. добавлено в версии:: 0.18.0
42
copy copy: bool, по умолчанию=True

Если False, данные, переданные в fit, перезаписываются, и выполнение
fit(X).transform(X) не даст ожидаемых результатов;
вместо этого используйте fit_transform(X).
True
whiten whiten: bool, по умолчанию=False

Если True (по умолчанию False), векторы `components_` умножаются
на квадратный корень из n_samples, а затем делятся на сингулярные значения,
чтобы обеспечить некоррелированные выходные данные с единичными дисперсиями по компонентам.

Отбеливание удаляет часть информации из преобразованного сигнала
(относительные масштабы дисперсии компонент), но иногда может
повысить точность прогнозирования последующих оценивателей,
обеспечивая соответствие данных некоторым жёстко заданным предположениям.
False
svd_solver svd_solver: {'auto', 'full', 'covariance_eigh', 'arpack', 'randomized'}, по умолчанию='auto'

"auto" :
Решатель выбирается согласно политике по умолчанию 'auto', основанной на `X.shape` и
`n_components`: если во входных данных менее 1000 признаков и
количество образцов более чем в 10 раз превышает количество признаков, используется решатель
"covariance_eigh". В противном случае, если размер входных данных превышает 500x500
и количество извлекаемых компонент меньше 80%
наименьшего размера данных, выбирается более эффективный
метод "randomized". В остальных случаях вычисляется точное полное SVD,
которое при необходимости затем усекается.
"full" :
Вычислить точное полное SVD с помощью стандартного решателя LAPACK через
`scipy.linalg.svd` и выбрать компоненты посредством постобработки.
"covariance_eigh" :
Предварительно вычислить ковариационную матрицу (для центрированных данных), выполнить
классическое разложение ковариационной матрицы на собственные значения и векторы,
обычно с помощью LAPACK, а затем выбрать компоненты посредством постобработки.
Этот решатель очень эффективен, если n_samples >> n_features и n_features
мало. Однако в противном случае он непрактичен при большом
n_features (для материализации ковариационной матрицы требуется много памяти). Также следует учитывать, что по сравнению с решателем "full"
этот решатель фактически удваивает число обусловленности и поэтому
менее устойчив с численной точки зрения (например, для входных данных с большим
диапазоном сингулярных значений).
"arpack" :
Выполнить усечённое до `n_components` SVD с помощью решателя ARPACK через
`scipy.sparse.linalg.svds`. Требуется, чтобы выполнялось строгое условие
`0 < n_components < min(X.shape)`
"randomized" :
Выполнить рандомизированное SVD методом Halko и др.

.. добавлено в версии:: 0.18.0

.. изменено в версии:: 1.5
Добавлен решатель 'covariance_eigh'.
'auto'
tol tol: float, по умолчанию=0.0

Допуск для сингулярных значений, вычисляемых при svd_solver == 'arpack'.
Должен находиться в диапазоне [0.0, infinity).

.. добавлено в версии:: 0.18.0
0.0
iterated_power iterated_power: int или 'auto', по умолчанию='auto'

Количество итераций степенного метода, вычисляемого при
svd_solver == 'randomized'.
Должно находиться в диапазоне [0, infinity).

.. добавлено в версии:: 0.18.0
'auto'
n_oversamples n_oversamples: int, по умолчанию=10

Этот параметр имеет значение только при `svd_solver="randomized"`.
Он задаёт дополнительное количество случайных векторов для выборки
области значений `X`, что обеспечивает достаточную обусловленность. Подробности см.
в :func:`~sklearn.utils.extmath.randomized_svd`.

.. добавлено в версии:: 1.1
10
power_iteration_normalizer power_iteration_normalizer: {'auto', 'QR', 'LU', 'none'}, по умолчанию='auto'

Нормализатор степенной итерации для решателя рандомизированного SVD.
Не используется ARPACK. Подробности см. в :func:`~sklearn.utils.extmath.randomized_svd`.

.. добавлено в версии:: 1.1
'auto'
Обученные атрибуты
Имя Тип Значение
components_ components_: ndarray размера (n_components, n_features)

Главные оси в пространстве признаков, представляющие направления
максимальной дисперсии данных. Эквивалентны правым сингулярным
векторам центрированных входных данных и параллельны их собственным векторам.
Компоненты отсортированы по убыванию ``explained_variance_``.
ndarray[float64](25, 64) [[ 0. ,-0.02,-0.22,...,-0.09,-0.04,-0.01], [ 0. , 0.01, 0.05,...,-0.18,-0.02, 0.01], [ 0. ,-0.02,-0.13,...,-0.23,-0.17,-0.03], ..., [-0. , 0.03, 0.09,...,-0.02,-0.12,-0.05], [-0. ,-0.05,-0.07,..., 0.02, 0.01, 0.03], [-0. ,-0.02,-0.04,..., 0.12, 0.12, 0.09]]
explained_variance_ explained_variance_: ndarray размера (n_components,)

Величина дисперсии, объясняемая каждой из выбранных компонент.
При оценке дисперсии используются `n_samples - 1` степеней свободы.

Равно n_components наибольшим собственным значениям
ковариационной матрицы X.

.. versionadded:: 0.18
ndarray[float64](25,) [179.01,163.72,141.79,..., 9.23, 8.69, 8.37]
explained_variance_ratio_ explained_variance_ratio_: ndarray размера (n_components,)

Доля дисперсии, объясняемая каждой из выбранных компонент.

Если ``n_components`` не задан, сохраняются все компоненты, а
сумма коэффициентов равна 1.0.
ndarray[float64](25,) [0.15,0.14,0.12,...,0.01,0.01,0.01]
mean_ mean_: ndarray размера (n_features,)

Эмпирическое среднее для каждого признака, оценённое по обучающей выборке.

Равно `X.mean(axis=0)`.
ndarray[float64](64,) [0. ,0.3 ,5.2 ,...,6.76,2.07,0.36]
n_components_ n_components_: int

Оценённое число компонент. Если n_components задано
как 'mle' или числом от 0 до 1 (при svd_solver == 'full'), это
число оценивается по входным данным. В противном случае оно равно значению параметра
n_components или меньшему из значений n_features и n_samples,
если n_components равно None.
int 25
n_features_in_ n_features_in_: int

Количество признаков, обнаруженных во время :term:`fit`.

.. versionadded:: 0.24
int 64
n_samples_ n_samples_: int

Количество образцов в обучающих данных.
int 1797
noise_variance_ noise_variance_: float

Оценённая ковариация шума в соответствии с вероятностной моделью PCA
из работы Tipping и Bishop (1999). См. «Распознавание образов и
машинное обучение» К. Бишопа, 12.2.1, стр. 574 или
http://www.miketipping.com/papers/met-mppca.pdf. Это значение необходимо для
вычисления оценённой ковариации данных и оценки образцов.

Равно среднему значению (min(n_features, n_samples) - n_components)
наименьших собственных значений ковариационной матрицы X.
float64 2.064
singular_values_ singular_values_: ndarray размера (n_components,)

Сингулярные значения, соответствующие каждой из выбранных компонент.
Сингулярные значения равны нормам 2 переменных ``n_components``
в пространстве меньшей размерности.

.. versionadded:: 0.19
ndarray[float64](25,) [567.01,542.25,504.63,...,128.73,124.93,122.58]
25 признаков
pca0
pca1
pca2
pca3
pca4
pca5
pca6
pca7
pca8
pca9
pca10
pca11
pca12
pca13
pca14
pca15
pca16
pca17
pca18
pca19
pca20
pca21
pca22
pca23
pca24
Параметры
C C: float, default=1.0

Обратная сила регуляризации; должна быть положительным числом с плавающей точкой.
Как и в методе опорных векторов, меньшие значения задают более сильную
регуляризацию. Значение `C=np.inf` приводит к логистической регрессии без штрафа.
Наглядный пример влияния настройки параметра `C`
при штрафе L1 см. здесь:
:ref:`sphx_glr_auto_examples_linear_model_plot_logistic_path.py`.
0.01
random_state random_state: int, RandomState instance, default=None

Используется, когда ``solver`` == 'sag', 'saga' или 'liblinear', для перемешивания
данных. Подробности см. в :term:`глоссарии <random_state>`.
42
max_iter max_iter: int, default=100

Максимальное количество итераций, выполняемых решателями для сходимости.
1000
penalty penalty: {'l1', 'l2', 'elasticnet', None}, default='l2'

Укажите норму штрафа:

- `None`: штраф не добавляется;
- `'l2'`: добавляется слагаемое штрафа L2; это вариант по умолчанию;
- `'l1'`: добавляется слагаемое штрафа L1;
- `'elasticnet'`: добавляются слагаемые штрафа L1 и L2.

.. warning::
Некоторые штрафы могут быть несовместимы с некоторыми решателями. См. параметр
`solver` ниже, чтобы узнать о совместимости штрафа и
решателя.

.. versionadded:: 0.19
штраф L1 с решателем SAGA (поддержка 'multinomial' + L1)

.. deprecated:: 1.8
Параметр `penalty` объявлен устаревшим в версии 1.8 и будет удалён в версии 1.10.
Вместо него используйте `l1_ratio` и `C`: `l1_ratio=0` для `penalty='l2'`,
`l1_ratio=1` для `penalty='l1'`, для `penalty='elasticnet'` задайте `l1_ratio` любым числом с плавающей точкой от 0 до 1,
а для `penalty=None` задайте `C=np.inf`.
'deprecated'
l1_ratio l1_ratio: float, default=0.0

Параметр смешивания Elastic-Net, для которого выполняется `0 <= l1_ratio <= 1`. Значение
`l1_ratio=1` задаёт чистый штраф L1, а `l1_ratio=0` — чистый штраф L2.
Любое значение от 0 до 1 задаёт штраф Elastic-Net вида
`l1_ratio * L1 + (1 - l1_ratio) * L2`.

.. warning::
Некоторые значения `l1_ratio`, то есть некоторые штрафы, могут быть несовместимы с
отдельными решателями. См. параметр `solver` ниже, чтобы узнать о совместимости штрафа и решателя.

.. versionchanged:: 1.8
Значение по умолчанию изменено с None на 0.0.

.. deprecated:: 1.8
`None` объявлен устаревшим и будет удалён в версии 1.10. Для указания типа штрафа всегда используйте
`l1_ratio`.
0.0
dual dual: bool, default=False

Двойственная (с ограничениями) или прямая (с регуляризацией; см. также
:ref:`это уравнение <regularized-logistic-loss>`) формулировка. Двойственная формулировка
реализована только для штрафа L2 с решателем liblinear. Предпочтительно задавать `dual=False`,
когда n_samples > n_features.
False
tol tol: float, default=1e-4

Допуск для критерия остановки.
0.0001
fit_intercept fit_intercept: bool, default=True

Указывает, нужно ли добавлять в функцию принятия решения
константу (также называемую смещением или свободным членом).
True
intercept_scaling intercept_scaling: float, default=1

Имеет значение только при использовании решателя `liblinear`
и значении `True` для `self.fit_intercept`. В этом случае `x` становится
`[x, self.intercept_scaling]`,
то есть к вектору объекта добавляется «синтетический» признак с постоянным значением,
равным `intercept_scaling`.
Свободный член становится равен
``intercept_scaling * synthetic_feature_weight``.

.. note::
Вес синтетического признака, как и веса всех остальных признаков,
подвергается регуляризации L1 или L2.
Чтобы уменьшить влияние регуляризации на вес синтетического признака
(и, следовательно, на свободный член), следует увеличить `intercept_scaling`.
1
class_weight class_weight: dict or 'balanced', default=None

Веса классов в формате ``{class_label: weight}``.
Если параметр не задан, предполагается, что вес каждого класса равен единице.

Режим "balanced" использует значения y для автоматической настройки
весов, обратно пропорциональных частотам классов во входных данных,
по формуле ``n_samples / (n_classes * np.bincount(y))``.

Обратите внимание: если задан sample_weight, эти веса будут перемножены с sample_weight (переданным
в метод fit).

.. versionadded:: 0.17
*class_weight='balanced'*
None
solver solver: {'lbfgs', 'liblinear', 'newton-cg', 'newton-cholesky', 'sag', 'saga'}, default='lbfgs'

Алгоритм для задачи оптимизации. По умолчанию используется 'lbfgs'.
При выборе решателя можно учитывать следующие аспекты:

- 'lbfgs' — хороший вариант по умолчанию, поскольку достаточно эффективно работает с широким
классом задач.
- Для задач :term:`многоклассовой классификации <multiclass>` (`n_classes >= 3`) все решатели, кроме
'liblinear', минимизируют полную мультиномиальную функцию потерь; 'liblinear' вызовет
ошибку.
- 'newton-cholesky' — хороший выбор, если
`n_samples` >> `n_features * n_classes`, особенно для категориальных признаков с редкими категориями, закодированных методом one-hot. Учтите, что потребление памяти
этим решателем квадратично зависит от `n_features * n_classes`,
поскольку он явно вычисляет полную матрицу Гессе.
- Для небольших наборов данных хорошо подходит 'liblinear', тогда как 'sag'
и 'saga' быстрее на больших наборах данных;
- 'liblinear' по умолчанию поддерживает только бинарную классификацию. Чтобы применить схему
«один против всех» в многоклассовой задаче, его можно обернуть в
:class:`~sklearn.multiclass.OneVsRestClassifier`.

.. warning::
Выбор алгоритма зависит от выбранного штрафа (`l1_ratio=0`
для штрафа L2, `l1_ratio=1` для штрафа L1 и `0 < l1_ratio < 1` для
Elastic-Net), а также от поддержки многоклассовой (мультиномиальной) классификации:

================= ======================== ======================
solver l1_ratio multinomial multiclass
================= ======================== ======================
'lbfgs' l1_ratio=0 yes
'liblinear' l1_ratio=1 or l1_ratio=0 no
'newton-cg' l1_ratio=0 yes
'newton-cholesky' l1_ratio=0 yes
'sag' l1_ratio=0 yes
'saga' 0<=l1_ratio<=1 yes
================= ======================== ======================

.. note::
Быстрая сходимость 'sag' и 'saga' гарантируется только для признаков
с примерно одинаковым масштабом. Данные можно предварительно обработать
с помощью масштабатора из :mod:`sklearn.preprocessing`.

.. seealso::
Дополнительную информацию о :class:`LogisticRegression`, в частности
таблицу :ref:`Table <logistic_regression_solvers>` со сводкой о поддержке решателями штрафов,
см. в :ref:`руководстве пользователя <Logistic_regression>`.

.. versionadded:: 0.17
Решатель стохастического градиентного спуска с усреднением (SAG). Поддержка мультиномиального режима добавлена
в версии 0.18.
.. versionadded:: 0.19
Решатель SAGA.
.. versionchanged:: 0.22
В версии 0.22 решатель по умолчанию изменён с 'liblinear' на 'lbfgs'.
.. versionadded:: 1.2
Решатель newton-cholesky. Поддержка мультиномиального режима добавлена в версии 1.6.
'lbfgs'
verbose verbose: int, default=0

Для решателей liblinear и lbfgs задайте любое положительное
число, чтобы включить подробный вывод.
0
warm_start warm_start: bool, default=False

Если задано значение True, решение предыдущего вызова fit повторно используется в качестве
начального приближения; в противном случае предыдущее решение просто сбрасывается.
Для решателя liblinear параметр не используется. См. :term:`глоссарий <warm_start>`.

.. versionadded:: 0.17
Поддержка *warm_start* для решателей *lbfgs*, *newton-cg*, *sag*, *saga*.
False
n_jobs n_jobs: int, default=None

Не оказывает никакого влияния.

.. deprecated:: 1.8
`n_jobs` объявлен устаревшим в версии 1.8 и будет удалён в версии 1.10.
None
Атрибуты обученной модели
Имя Тип Значение
classes_ classes_: ndarray формы (n_classes, )

Список меток классов, известных классификатору.
ndarray[int64](10,) [0,1,2,...,7,8,9]
coef_ coef_: ndarray или CSR-матрица формы (1, n_features) или (n_classes, n_features)

Коэффициенты признаков в функции принятия решения.

`coef_` имеет форму (1, n_features), если рассматриваемая задача является бинарной.

По умолчанию массив создаётся плотным, но его можно преобразовать в
разреженный (формат CSR) с помощью :meth:`sparsify` (что может быть полезно
при регуляризации L1, если многие коэффициенты равны нулю), а затем обратно в
плотный с помощью :meth:`densify`.
ndarray[float64](10, 25) [[ 0.08,-0.26, 0.06,...,-0.01,-0.03, 0.01], [ 0.09, 0.17,-0.05,...,-0.02,-0.08, 0.17], [-0.16, 0.08,-0.22,...,-0.01, 0.01, 0. ], ..., [ 0.02, 0.15, 0.18,...,-0.03,-0.01,-0.06], [ 0.01, 0.02,-0.04,...,-0.01, 0.02,-0. ], [-0.25,-0.03, 0.15,...,-0.01,-0.09, 0. ]]
intercept_ intercept_: ndarray формы (1,) или (n_classes,)

Свободный член (также называемый смещением), добавляемый к функции принятия решения.

Если для `fit_intercept` установлено значение False, свободный член равен нулю.
`intercept_` имеет форму (1,), если рассматриваемая задача является бинарной.
ndarray[float64](10,) [-0.69,-0.07,-0.59,...,-0.14, 2.16,-0.35]
n_features_in_ n_features_in_: int

Количество признаков, встречавшихся при :term:`fit`.

.. добавлено в версии:: 0.24
int 25
n_iter_ n_iter_: ndarray формы (1, )

Фактическое количество итераций для всех классов.

.. изменено в версии:: 0.20

В SciPy <= 1.0.0 число итераций lbfgs могло превышать
``max_iter``. Теперь ``n_iter_`` будет показывать не более ``max_iter``.
ndarray[int32](1,) [93]


Визуализация результатов

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

n_components = grid.cv_results_["param_reduce_dim__n_components"]
test_scores = grid.cv_results_["mean_test_score"]

# Create a polars DataFrame for better data manipulation and visualization
results_df = pl.DataFrame(
    {
        "n_components": n_components,
        "mean_test_score": test_scores,
        "std_test_score": grid.cv_results_["std_test_score"],
        "mean_train_score": grid.cv_results_["mean_train_score"],
        "std_train_score": grid.cv_results_["std_train_score"],
        "mean_fit_time": grid.cv_results_["mean_fit_time"],
        "rank_test_score": grid.cv_results_["rank_test_score"],
    }
)

# Sort by number of components
results_df = results_df.sort("n_components")

# Calculate the lower bound threshold
lower = lower_bound(grid.cv_results_)

# Get the best model information
best_index_ = grid.best_index_
best_components = n_components[best_index_]
best_score = grid.cv_results_["mean_test_score"][best_index_]

# Add a column to mark the selected model
results_df = results_df.with_columns(
    pl.when(pl.col("n_components") == best_components)
    .then(pl.lit("Selected"))
    .otherwise(pl.lit("Regular"))
    .alias("model_type")
)

# Get the number of CV splits from the results
n_splits = sum(
    1
    for key in grid.cv_results_.keys()
    if key.startswith("split") and key.endswith("test_score")
)

# Extract individual scores for each split
test_scores = np.array(
    [
        [grid.cv_results_[f"split{i}_test_score"][j] for i in range(n_splits)]
        for j in range(len(n_components))
    ]
)
train_scores = np.array(
    [
        [grid.cv_results_[f"split{i}_train_score"][j] for i in range(n_splits)]
        for j in range(len(n_components))
    ]
)

# Calculate mean and std of test scores
mean_test_scores = np.mean(test_scores, axis=1)
std_test_scores = np.std(test_scores, axis=1)

# Find best score and threshold
best_mean_score = np.max(mean_test_scores)
threshold = best_mean_score - std_test_scores[np.argmax(mean_test_scores)]

# Create a single figure for visualization
fig, ax = plt.subplots(figsize=(12, 8))

# Plot individual points
for i, comp in enumerate(n_components):
    # Plot individual test points
    plt.scatter(
        [comp] * n_splits,
        test_scores[i],
        alpha=0.2,
        color="blue",
        s=20,
        label="Individual test scores" if i == 0 else "",
    )
    # Plot individual train points
    plt.scatter(
        [comp] * n_splits,
        train_scores[i],
        alpha=0.2,
        color="green",
        s=20,
        label="Individual train scores" if i == 0 else "",
    )

# Plot mean lines with error bands
plt.plot(
    n_components,
    np.mean(test_scores, axis=1),
    "-",
    color="blue",
    linewidth=2,
    label="Mean test score",
)
plt.fill_between(
    n_components,
    np.mean(test_scores, axis=1) - np.std(test_scores, axis=1),
    np.mean(test_scores, axis=1) + np.std(test_scores, axis=1),
    alpha=0.15,
    color="blue",
)

plt.plot(
    n_components,
    np.mean(train_scores, axis=1),
    "-",
    color="green",
    linewidth=2,
    label="Mean train score",
)
plt.fill_between(
    n_components,
    np.mean(train_scores, axis=1) - np.std(train_scores, axis=1),
    np.mean(train_scores, axis=1) + np.std(train_scores, axis=1),
    alpha=0.15,
    color="green",
)

# Add threshold lines
plt.axhline(
    best_mean_score,
    color="#9b59b6",  # Purple
    linestyle="--",
    label="Best score",
    linewidth=2,
)
plt.axhline(
    threshold,
    color="#e67e22",  # Orange
    linestyle="--",
    label="Best score - 1 std",
    linewidth=2,
)

# Highlight selected model
plt.axvline(
    best_components,
    color="#9b59b6",  # Purple
    alpha=0.2,
    linewidth=8,
    label="Selected model",
)

# Set titles and labels
plt.xlabel("Number of PCA components", fontsize=12)
plt.ylabel("Score", fontsize=12)
plt.title("Model Selection: Balancing Complexity and Performance", fontsize=14)
plt.grid(True, linestyle="--", alpha=0.7)
plt.legend(
    bbox_to_anchor=(1.02, 1),
    loc="upper left",
    borderaxespad=0,
)

# Set axis properties
plt.xticks(n_components)
plt.ylim((0.85, 1.0))

# # Adjust layout
plt.tight_layout()
Model Selection: Balancing Complexity and Performance

Вывод результатов

Мы выведем информацию о выбранной модели, включая её сложность и качество. Также покажем сводную таблицу всех моделей с помощью polars.

print("Best model selected by the one-standard-error rule:")
print(f"Number of PCA components: {best_components}")
print(f"Accuracy score: {best_score:.4f}")
print(f"Best possible accuracy: {np.max(test_scores):.4f}")
print(f"Accuracy threshold (best - 1 std): {lower:.4f}")

# Create a summary table with polars
summary_df = results_df.select(
    pl.col("n_components"),
    pl.col("mean_test_score").round(4).alias("test_score"),
    pl.col("std_test_score").round(4).alias("test_std"),
    pl.col("mean_train_score").round(4).alias("train_score"),
    pl.col("std_train_score").round(4).alias("train_std"),
    pl.col("mean_fit_time").round(3).alias("fit_time"),
    pl.col("rank_test_score").alias("rank"),
)

# Add a column to mark the selected model
summary_df = summary_df.with_columns(
    pl.when(pl.col("n_components") == best_components)
    .then(pl.lit("*"))
    .otherwise(pl.lit(""))
    .alias("selected")
)

print("\nModel comparison table:")
print(summary_df)
Best model selected by the one-standard-error rule:
Number of PCA components: 25
Accuracy score: 0.9643
Best possible accuracy: 0.9944
Accuracy threshold (best - 1 std): 0.9623

Model comparison table:
shape: (9, 8)
┌──────────────┬────────────┬──────────┬─────────────┬───────────┬──────────┬──────┬──────────┐
│ n_components ┆ test_score ┆ test_std ┆ train_score ┆ train_std ┆ fit_time ┆ rank ┆ selected │
│ ---          ┆ ---        ┆ ---      ┆ ---         ┆ ---       ┆ ---      ┆ ---  ┆ ---      │
│ i64          ┆ f64        ┆ f64      ┆ f64         ┆ f64       ┆ f64      ┆ i32  ┆ str      │
╞══════════════╪════════════╪══════════╪═════════════╪═══════════╪══════════╪══════╪══════════╡
│ 6            ┆ 0.8631     ┆ 0.0241   ┆ 0.8697      ┆ 0.0047    ┆ 0.123    ┆ 9    ┆          │
│ 8            ┆ 0.9037     ┆ 0.0194   ┆ 0.9147      ┆ 0.0028    ┆ 0.112    ┆ 8    ┆          │
│ 10           ┆ 0.9341     ┆ 0.0148   ┆ 0.9493      ┆ 0.0023    ┆ 0.077    ┆ 7    ┆          │
│ 15           ┆ 0.95       ┆ 0.0162   ┆ 0.9662      ┆ 0.0022    ┆ 0.073    ┆ 6    ┆          │
│ 20           ┆ 0.9563     ┆ 0.0144   ┆ 0.9759      ┆ 0.0019    ┆ 0.07     ┆ 5    ┆          │
│ 25           ┆ 0.9643     ┆ 0.0126   ┆ 0.9836      ┆ 0.0014    ┆ 0.067    ┆ 4    ┆ *        │
│ 35           ┆ 0.9685     ┆ 0.0115   ┆ 0.9903      ┆ 0.0013    ┆ 0.068    ┆ 3    ┆          │
│ 45           ┆ 0.9711     ┆ 0.0093   ┆ 0.9926      ┆ 0.001     ┆ 0.07     ┆ 2    ┆          │
│ 55           ┆ 0.9717     ┆ 0.0093   ┆ 0.993       ┆ 0.001     ┆ 0.072    ┆ 1    ┆          │
└──────────────┴────────────┴──────────┴─────────────┴───────────┴──────────┴──────┴──────────┘

Заключение

Правило одного стандартного отклонения помогает выбрать более простую модель (с меньшим количеством компонент PCA), сохраняя при этом качество, статистически сопоставимое с качеством наилучшей модели. Такой подход помогает предотвратить переобучение и повысить интерпретируемость и эффективность модели.

В этом примере мы показали, как реализовать это правило с помощью пользовательской функции refit в GridSearchCV.

Основные выводы:

  1. Правило одного стандартного отклонения служит хорошим ориентиром при выборе более простых моделей
  2. Пользовательские функции refit в GridSearchCV позволяют гибко выбирать стратегии отбора моделей
  3. Визуализация оценок на обучающей и тестовой выборках помогает выявить возможное переобучение

Этот подход можно применять и в других задачах выбора модели, где важно сбалансировать сложность и качество, а также в случаях, когда требуется выбрать «наилучшую» модель с учётом особенностей конкретного сценария использования.

# Display the figure
plt.show()

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

Launch binder
Launch JupyterLite

Download Jupyter notebook: plot_grid_search_refit_callable.ipynb

Download Python source code: plot_grid_search_refit_callable.py

Download zipped: plot_grid_search_refit_callable.zip

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

Построение конвейера: объединение PCA и логистической регрессии

Пользовательская стратегия refit для поиска по сетке с перекрёстной проверкой

Признаки с лагами для прогнозирования временных рядов

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

© 2007–2026 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.9/auto_examples/model_selection/plot_grid_search_refit_callable.html

Spec-Zone.ru

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