Spec-Zone.ru › scikit-learn

Примечание

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

Построение порога принятия решения для обучения с учетом затрат

После обучения классификатора результаты метода predict представляют собой предсказания меток классов, полученные путем порогового преобразования результата либо decision_function, либо predict_proba. Для бинарного классификатора порог по умолчанию соответствует апостериорной оценке вероятности 0.5 или оценке решения 0.0.

Однако эта стратегия по умолчанию, скорее всего, не оптимальна для поставленной задачи. В качестве примера рассмотрим набор данных о кредитоспособности в Германии «Statlog» [1]. Задача состоит в том, чтобы предсказать, является ли кредит человека «хорошим» или «плохим». Кроме того, предоставлена матрица затрат, задающая стоимость ошибочной классификации. В частности, ошибочно классифицировать «плохой» кредит как «хороший» в среднем в пять раз затратнее, чем ошибочно классифицировать «хороший» кредит как «плохой».

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

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

Ссылки

[1] (1,2,3)

«Statlog (German Credit Data) Data Set», репозиторий машинного обучения UCI, ссылка.

[2] (1,2,3,4,5,6)

Чарльз Элкан, «Основы обучения с учетом затрат», Международная объединенная конференция по искусственному интеллекту. Том 17. № 1. Lawrence Erlbaum Associates Ltd, 2001.

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

Обучение с учетом затрат при постоянных выгодах и затратах

В этом первом разделе мы покажем, как использовать TunedThresholdClassifierCV для обучения с учетом затрат, когда выгоды и затраты, связанные с каждой ячейкой матрицы ошибок, постоянны. Мы рассмотрим задачу, описанную в [2], используя набор данных о кредитоспособности в Германии «Statlog» [1].

Набор данных о кредитоспособности в Германии «Statlog»

Загрузим набор данных о кредитоспособности в Германии из OpenML.

import sklearn
from sklearn.datasets import fetch_openml

sklearn.set_config(transform_output="pandas")

german_credit = fetch_openml(data_id=31, as_frame=True, parser="pandas")
X, y = german_credit.data, german_credit.target

Проверим типы признаков, доступные в X.

X.info()
<class 'pandas.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 20 columns):
 #   Column                  Non-Null Count  Dtype
---  ------                  --------------  -----
 0   checking_status         1000 non-null   category
 1   duration                1000 non-null   int64
 2   credit_history          1000 non-null   category
 3   purpose                 1000 non-null   category
 4   credit_amount           1000 non-null   int64
 5   savings_status          1000 non-null   category
 6   employment              1000 non-null   category
 7   installment_commitment  1000 non-null   int64
 8   personal_status         1000 non-null   category
 9   other_parties           1000 non-null   category
 10  residence_since         1000 non-null   int64
 11  property_magnitude      1000 non-null   category
 12  age                     1000 non-null   int64
 13  other_payment_plans     1000 non-null   category
 14  housing                 1000 non-null   category
 15  existing_credits        1000 non-null   int64
 16  job                     1000 non-null   category
 17  num_dependents          1000 non-null   int64
 18  own_telephone           1000 non-null   category
 19  foreign_worker          1000 non-null   category
dtypes: category(13), int64(7)
memory usage: 68.9 KB

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

y.value_counts()
class
good    700
bad     300
Name: count, dtype: int64

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

Кроме того, целевая переменная представлена строками. Для некоторых метрик (например, точности и полноты) нужно указать интересующую метку, также называемую «положительной меткой». Здесь мы определим цель как предсказание того, является ли образец «плохим» кредитом.

pos_label, neg_label = "bad", "good"

Для проведения анализа разделим набор данных, выполнив одно стратифицированное разбиение.

from sklearn.model_selection import train_test_split

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

Теперь мы готовы спроектировать предиктивную модель и соответствующую стратегию оценки.

Метрики оценки

В этом разделе мы определим набор метрик, которые будем использовать далее. Чтобы увидеть эффект настройки порогового значения, оценим предиктивную модель с помощью ROC-кривой (Receiver Operating Characteristic) и кривой «точность — полнота». Значения, отображаемые на этих графиках, — это доля истинно положительных результатов (TPR), также известная как полнота или чувствительность, и доля ложноположительных результатов (FPR), также известная как специфичность, для ROC-кривой, а также точность и полнота для кривой «точность — полнота».

Из этих четырех метрик scikit-learn не предоставляет функцию-оценщик для FPR. Поэтому нам нужно определить небольшую пользовательскую функцию для ее вычисления.

from sklearn.metrics import confusion_matrix


def fpr_score(y, y_pred, neg_label, pos_label):
    cm = confusion_matrix(y, y_pred, labels=[neg_label, pos_label])
    tn, fp, _, _ = cm.ravel()
    tnr = tn / (tn + fp)
    return 1 - tnr

Как уже отмечалось, «положительная метка» не задана значением «1», и вызов некоторых метрик с этим нестандартным значением приводит к ошибке. Нужно сообщить метрикам, какая метка считается «положительной».

Для этого определим оценщик scikit-learn с помощью make_scorer, передав в него необходимые сведения. Все пользовательские оценщики мы сохраним в словаре. Чтобы использовать их, нужно передать обученную модель, данные и целевую переменную, на которых мы хотим оценить предиктивную модель.

from sklearn.metrics import make_scorer, precision_score, recall_score

tpr_score = recall_score  # TPR and recall are the same metric
scoring = {
    "precision": make_scorer(precision_score, pos_label=pos_label),
    "recall": make_scorer(recall_score, pos_label=pos_label),
    "fpr": make_scorer(fpr_score, neg_label=neg_label, pos_label=pos_label),
    "tpr": make_scorer(tpr_score, pos_label=pos_label),
}

Кроме того, в первоначальном исследовании [1] определена пользовательская бизнес-метрика. «Бизнес-метрикой» мы называем любую функцию метрики, предназначенную для количественной оценки влияния предсказаний (верных или ошибочных) на бизнес-ценность внедрения заданной модели машинного обучения в конкретном прикладном контексте. Для нашей задачи прогнозирования кредитоспособности авторы предлагают пользовательскую матрицу затрат, отражающую тот факт, что классифицировать «плохой» кредит как «хороший» в среднем в 5 раз затратнее, чем наоборот: финансовому учреждению менее затратно отказать в кредите потенциальному клиенту, который не допустил бы просрочки (и тем самым упустить хорошего клиента, который в противном случае выплатил бы кредит и проценты), чем выдать кредит клиенту, который допустит просрочку.

Определим функцию Python, которая взвешивает матрицу ошибок и возвращает общую стоимость. Строки матрицы ошибок содержат количества наблюдаемых классов, а столбцы — количества предсказанных классов. Здесь положительным классом считается «плохой» кредит (вторая строка и второй столбец). Инструменты выбора моделей scikit-learn предполагают, что мы соблюдаем соглашение «чем выше, тем лучше», поэтому следующая матрица выгод назначает отрицательные значения (затраты) двум типам ошибочных предсказаний:

  • выгода -1 за каждый ложноположительный результат (кредит «хороший», помеченный как «плохой»),
  • выгода -5 за каждый ложноотрицательный результат (кредит «плохой», помеченный как «хороший»),
  • выгода 0 за истинно положительный и истинно отрицательный результаты.

Обратите внимание: теоретически, если наша модель откалибрована, а набор данных репрезентативен и достаточно велик, настраивать порог не требуется — его можно безопасно установить равным 1/5 отношения затрат, как указано в уравнении (2) статьи Элкана [2].

import numpy as np


def credit_gain_score(y, y_pred, neg_label, pos_label):
    cm = confusion_matrix(y, y_pred, labels=[neg_label, pos_label])

    gain_matrix = np.array(
        [
            [0, -1],  # -1 gain for false positives
            [-5, 0],  # -5 gain for false negatives
        ]
    )
    return np.sum(cm * gain_matrix)


scoring["credit_gain"] = make_scorer(
    credit_gain_score, neg_label=neg_label, pos_label=pos_label
)

Базовая прогнозная модель

В качестве прогнозной модели мы используем HistGradientBoostingClassifier, которая изначально поддерживает категориальные признаки и пропущенные значения.

from sklearn.ensemble import HistGradientBoostingClassifier

model = HistGradientBoostingClassifier(
    categorical_features="from_dtype", random_state=0
).fit(X_train, y_train)
model
HistGradientBoostingClassifier(random_state=0)
В среде Jupyter повторно выполните эту ячейку, чтобы отобразить представление HTML, или доверьте выполнение блокноту.
На GitHub представление HTML не отображается; попробуйте загрузить эту страницу с помощью nbviewer.org.
Параметры
random_state random_state: int, экземпляр RandomState или None, по умолчанию=None

Генератор псевдослучайных чисел для управления подвыборкой в процессе
разбиения на бины, а также разделением данных на обучающую и проверочную выборки,
если включена ранняя остановка.
Передайте целое число, чтобы получать воспроизводимые результаты при нескольких вызовах функции.
См. :term:`глоссарий <random_state>`.
0
loss loss: {'log_loss'}, по умолчанию='log_loss'

Функция потерь, используемая в процессе бустинга.

Для задач бинарной классификации 'log_loss' также известна как логистическая функция потерь,
биномиальная девианса или бинарная кросс-энтропия. Внутри модели на каждой итерации
бустинга обучается одно дерево, а для вычисления предсказанной вероятности положительного класса
в качестве обратной функции связи используется логистическая сигмоидная функция (expit).

Для задач многоклассовой классификации 'log_loss' также известна как мультиномиальная
девианса или категориальная кросс-энтропия. Внутри модели на каждой итерации
бустинга обучается по одному дереву для каждого класса, а для вычисления предсказанных вероятностей классов
в качестве обратной функции связи используется функция softmax.
'log_loss'
learning_rate learning_rate: float, по умолчанию=0.1

Скорость обучения, также называемая *сжатием*. Используется как
множитель значений листьев. Укажите ``1``, чтобы отключить
сжатие.
0.1
max_iter max_iter: int, по умолчанию=100

Максимальное число итераций процесса бустинга, то есть
максимальное число деревьев для бинарной классификации. Для многоклассовой
классификации на каждой итерации строится `n_classes` деревьев.
100
max_leaf_nodes max_leaf_nodes: int или None, по умолчанию=31

Максимальное число листьев для каждого дерева. Должно быть строго
больше 1. Если указано None, максимальное ограничение отсутствует.
31
max_depth max_depth: int или None, по умолчанию=None

Максимальная глубина каждого дерева. Глубина дерева — это число
рёбер от корня до самого глубокого листа.
По умолчанию глубина не ограничена.
None
min_samples_leaf min_samples_leaf: int, по умолчанию=20

Минимальное число объектов в листе. Для небольших наборов данных, содержащих
менее нескольких сотен объектов, рекомендуется уменьшить это значение,
так как иначе будут строиться только очень неглубокие деревья.
20
l2_regularization l2_regularization: float, по умолчанию=0

Параметр регуляризации L2, штрафующий листья с малыми гессианами.
Укажите ``0``, чтобы отключить регуляризацию (значение по умолчанию).
0.0
max_features max_features: float, по умолчанию=1.0

Доля случайно выбранных признаков в каждом разбиении узла.
Это один из видов регуляризации: при меньших значениях деревья становятся менее эффективными
моделями, что может предотвратить переобучение.
Если заданы ограничения взаимодействия через `interaction_cst`, при подвыборке учитываются только
разрешённые признаки.

.. добавлено в версии:: 1.4
1.0
max_bins max_bins: int, по умолчанию=255

Максимальное число бинов для непустых значений. Перед
обучением каждый признак входного массива `X` разбивается на целочисленные
бины, что значительно ускоряет этап обучения.
Для признаков с небольшим числом уникальных значений может использоваться меньше
``max_bins`` бинов. Помимо бинов ``max_bins``, всегда резервируется ещё один бин
для пропущенных значений. Значение не должно превышать 255.
255
categorical_features categorical_features: array-like из {bool, int, str} формы (n_features) или формы (n_categorical_features,), по умолчанию='from_dtype'

Указывает категориальные признаки.

- None: ни один признак не считается категориальным.
- array-like логических значений: логическая маска, указывающая категориальные признаки.
- array-like целых чисел: целочисленные индексы категориальных
признаков.
- array-like строк: названия категориальных признаков (предполагается, что обучающие
данные содержат названия признаков).
- `"from_dtype"`: столбцы датафрейма с dtype "Categorical" и "Enum"
считаются категориальными признаками. Входные данные должны быть датафреймом,
поддерживаемым narwhals (или совместимым с ним): должна работать функция :func:`narwhals.from_native`.
Это относится, например, к датафреймам pandas и polars.

Для каждого категориального признака должно быть не более `max_bins` уникальных
категорий. Отрицательные значения категориальных признаков, закодированные числовыми
типами данных, считаются пропущенными. Все категориальные значения
преобразуются в числа с плавающей точкой. Это означает, что категориальные значения
1.0 и 1 считаются одной и той же категорией.

Подробнее см. в :ref:`руководстве пользователя <categorical_support_gbdt>`.

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

.. изменено в версии:: 1.2
Добавлена поддержка названий признаков.

.. изменено в версии:: 1.4
Добавлен вариант `"from_dtype"`.

.. изменено в версии:: 1.6
Значение по умолчанию изменено с `None` на `"from_dtype"`.
'from_dtype'
monotonic_cst monotonic_cst: array-like целых чисел формы (n_features) или dict, по умолчанию=None

Монотонные ограничения для каждого признака задаются следующими
целочисленными значениями:

- 1: монотонное возрастание
- 0: без ограничений
- -1: монотонное убывание

Если передан словарь с ключами str, сопоставьте признаки и монотонные ограничения по имени.
Если передан массив, признаки сопоставляются с ограничениями по позиции. Пример использования см. в
:ref:`monotonic_cst_features_names`.

Ограничения применимы только к задачам бинарной классификации и задаются
для вероятности положительного класса.
Подробнее см. в :ref:`руководстве пользователя <monotonic_cst_gbdt>`.

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

.. изменено в версии:: 1.2
Добавлена поддержка словаря ограничений с названиями признаков в качестве ключей.
None
interaction_cst interaction_cst: {"pairwise", "no_interactions"} или последовательность списков/кортежей/множеств целых чисел, по умолчанию=None

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

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

Строки "pairwise" и "no_interactions" — это сокращённые обозначения
для разрешения только попарных взаимодействий или полного запрета взаимодействий соответственно.

Например, если всего имеется 5 признаков, `interaction_cst=[{0, 1}]`
эквивалентно `interaction_cst=[{0, 1}, {2, 3, 4}]`
и означает, что каждая ветвь дерева будет разбиваться либо только
по признакам 0 и 1, либо только по признакам 2, 3 и 4.

Пример использования `interaction_cst` см. в :ref:`этом примере<ice-vs-pdp>`.

.. добавлено в версии:: 1.2
None
warm_start warm_start: bool, по умолчанию=False

Если задано ``True``, используется решение предыдущего вызова fit
и в ансамбль добавляются новые оцениватели. Чтобы результаты были корректными,
оцениватель следует повторно обучать только на тех же данных.
См. :term:`глоссарий <warm_start>`.
False
early_stopping early_stopping: 'auto' или bool, по умолчанию='auto'

Если задано 'auto', ранняя остановка включается, когда размер выборки превышает
10000 или когда в `fit` переданы `X_val` и `y_val`. Если задано True, ранняя остановка
включена; в противном случае она отключена.

.. добавлено в версии:: 0.23
'auto'
scoring scoring: str, вызываемый объект или None, по умолчанию='loss'

Метод оценки, используемый для ранней остановки. Применяется, только если включён параметр `early_stopping`.
Варианты:

- str: варианты см. в :ref:`scoring_string_names`.
- вызываемый объект: объект-оценщик (например, функция) с сигнатурой
``scorer(estimator, X, y)``. Подробнее см. в :ref:`scoring_callable`.
- `None`: используется :ref:`точность <accuracy_score>`.
- 'loss': ранняя остановка проверяется относительно значения функции потерь.
'loss'
validation_fraction validation_fraction: int, float или None, по умолчанию=0.1

Доля (или абсолютный размер) обучающих данных, выделяемая
в качестве проверочных данных для ранней остановки. Если указано None, ранняя остановка выполняется на
обучающих данных.
Значение игнорируется, если ранняя остановка не выполняется, например
при `early_stopping=False`, или если в fit переданы `X_val` и `y_val`.
0.1
n_iter_no_change n_iter_no_change: int, по умолчанию=10

Используется для определения момента «ранней остановки». Обучение
останавливается, если ни одна из последних ``n_iter_no_change`` оценок не лучше
оценки на ``n_iter_no_change - 1``-й позиции с конца, с учётом заданного
допуска. Используется, только если применяется ранняя остановка.
10
tol tol: float, по умолчанию=1e-7

Абсолютный допуск, используемый при сравнении оценок. Чем выше
допуск, тем вероятнее ранняя остановка: при большем допуске
последующим итерациям сложнее считаться улучшением
относительно базовой оценки.
1e-07
verbose verbose: int, по умолчанию=0

Уровень подробности вывода. Если значение не равно нулю, выводится информация о
процессе обучения. ``1`` выводит только сводную информацию, ``2`` — сведения для каждой
итерации.
0
class_weight class_weight: dict или 'balanced', по умолчанию=None

Веса, связанные с классами, в формате `{class_label: weight}`.
Если значение не задано, предполагается, что вес каждого класса равен единице.
Режим "balanced" использует значения y для автоматической корректировки
весов, обратно пропорциональных частотам классов во входных данных,
по формуле `n_samples / (n_classes * np.bincount(y))`.
Если задан `sample_weight`, эти веса перемножаются с весами объектов (переданными
методу fit).

.. добавлено в версии:: 1.2
None
Атрибуты обученной модели
Имя Тип Значение
classes_ classes_: массив, форма = (n_classes,)

Метки классов.
ndarray[object](2,) ['bad','good']
do_early_stopping_ do_early_stopping_: bool

Показывает, использовалась ли ранняя остановка при обучении.
bool False
feature_names_in_ feature_names_in_: ndarray формы (`n_features_in_`,)

Названия признаков, обнаруженных при :term:`fit`. Определяется, только если `X`
содержит названия признаков, все из которых являются строками.

.. добавлено в версии:: 1.0
ndarray[object](20,) ['checking_status','duration','credit_history',...,'num_dependents', 'own_telephone','foreign_worker']
is_categorical_ is_categorical_: ndarray формы (n_features,) или None

Логическая маска категориальных признаков. Равно ``None``, если категориальных признаков нет.
ndarray[bool](20,) [ True,False, True,...,False, True, True]
n_features_in_ n_features_in_: int

Число признаков, обнаруженных при :term:`fit`.

.. добавлено в версии:: 0.24
int 20
n_iter_ n_iter_: int

Число итераций, выбранное с помощью ранней остановки в зависимости от
параметра `early_stopping`. В противном случае соответствует max_iter.
int 100
n_trees_per_iteration_ n_trees_per_iteration_: int

Число деревьев, строящихся на каждой итерации. Для бинарной классификации оно равно 1,
а для многоклассовой классификации — ``n_classes``.
int 1
train_score_ train_score_: ndarray формы (n_iter_+1,)

Оценки на обучающих данных для каждой итерации. Первый элемент
содержит оценку ансамбля до первой итерации. Оценки
вычисляются в соответствии с параметром ``scoring``. Если ``scoring``
не равен 'loss', оценки вычисляются на подмножестве размером не более 10 000
объектов. Пуст, если ранняя остановка не выполнялась.
ndarray[float64](0,) []
validation_score_ validation_score_: ndarray формы (n_iter_+1,)

Оценки на отложенных проверочных данных для каждой итерации. Первый
элемент содержит оценку ансамбля до первой итерации.
Оценки вычисляются в соответствии с параметром ``scoring``. Массив пуст,
если ранняя остановка не выполнялась или если ``validation_fraction`` равен None.
ndarray[float64](0,) []


Мы оцениваем качество нашей прогнозной модели с помощью ROC-кривой и кривой Precision-Recall.

import matplotlib.pyplot as plt

from sklearn.metrics import PrecisionRecallDisplay, RocCurveDisplay

fig, axs = plt.subplots(nrows=1, ncols=2, figsize=(14, 6))

PrecisionRecallDisplay.from_estimator(
    model, X_test, y_test, pos_label=pos_label, ax=axs[0], name="GBDT"
)
axs[0].plot(
    scoring["recall"](model, X_test, y_test),
    scoring["precision"](model, X_test, y_test),
    marker="o",
    markersize=10,
    color="tab:blue",
    label="Default cut-off point at a probability of 0.5",
)
axs[0].set_title("Precision-Recall curve")
axs[0].legend()

RocCurveDisplay.from_estimator(
    model,
    X_test,
    y_test,
    pos_label=pos_label,
    ax=axs[1],
    name="GBDT",
    plot_chance_level=True,
)
axs[1].plot(
    scoring["fpr"](model, X_test, y_test),
    scoring["tpr"](model, X_test, y_test),
    marker="o",
    markersize=10,
    color="tab:blue",
    label="Default cut-off point at a probability of 0.5",
)
axs[1].set_title("ROC curve")
axs[1].legend()
_ = fig.suptitle("Evaluation of the vanilla GBDT model")
Evaluation of the vanilla GBDT model, Precision-Recall curve, ROC curve

Напомним, что эти кривые показывают статистические характеристики прогнозной модели при разных пороговых значениях. Для кривой Precision-Recall отображаются точность и полнота, а для ROC-кривой — TPR (то же, что и полнота) и FPR.

Здесь разным пороговым значениям соответствуют разные оценки апостериорной вероятности в диапазоне от 0 до 1. По умолчанию model.predict использует пороговое значение, равное оценке вероятности 0.5. Метрики для такого порогового значения отмечены на кривых синими точками: они соответствуют статистическим характеристикам модели при использовании model.predict.

Однако напомним, что исходная цель состояла в минимизации затрат (или максимизации выгоды), определяемых бизнес-метрикой. Мы можем вычислить значение бизнес-метрики:

print(f"Business defined metric: {scoring['credit_gain'](model, X_test, y_test)}")
Business defined metric: -209

На этом этапе мы ещё не знаем, может ли другое пороговое значение обеспечить большую выгоду. Чтобы найти оптимальное значение, нужно вычислить затраты и выгоду по бизнес-метрике для всех возможных пороговых значений и выбрать наилучшее. Реализовывать эту стратегию вручную может быть довольно утомительно, но нам поможет класс TunedThresholdClassifierCV. Он автоматически вычисляет затраты и выгоду для всех возможных пороговых значений и оптимизирует scoring.

Настройка порогового значения

Для настройки порогового значения мы используем TunedThresholdClassifierCV. Нужно указать бизнес-метрику, которую следует оптимизировать, и метку положительного класса. Внутри алгоритма оптимальное пороговое значение выбирается так, чтобы максимизировать бизнес-метрику с помощью перекрёстной проверки. По умолчанию используется стратифицированная перекрёстная проверка с 5 блоками.

from sklearn.model_selection import TunedThresholdClassifierCV

tuned_model = TunedThresholdClassifierCV(
    estimator=model,
    scoring=scoring["credit_gain"],
    store_cv_results=True,  # necessary to inspect all results
)
tuned_model.fit(X_train, y_train)
print(f"{tuned_model.best_threshold_=:0.2f}")
tuned_model.best_threshold_=0.03

Построим ROC-кривые и кривые Precision-Recall для базовой и настроенной моделей. Также отметим пороговые значения, которые использует каждая модель. Поскольку этот код будет использоваться далее повторно, определим функцию для построения графиков.

def plot_roc_pr_curves(vanilla_model, tuned_model, *, title):
    fig, axs = plt.subplots(nrows=1, ncols=3, figsize=(21, 6))

    linestyles = ("dashed", "dotted")
    markerstyles = ("o", ">")
    colors = ("tab:blue", "tab:orange")
    names = ("Vanilla GBDT", "Tuned GBDT")
    for idx, (est, linestyle, marker, color, name) in enumerate(
        zip((vanilla_model, tuned_model), linestyles, markerstyles, colors, names)
    ):
        decision_threshold = getattr(est, "best_threshold_", 0.5)
        PrecisionRecallDisplay.from_estimator(
            est,
            X_test,
            y_test,
            pos_label=pos_label,
            ax=axs[0],
            name=name,
            curve_kwargs={"linestyle": linestyle, "color": color},
        )
        axs[0].plot(
            scoring["recall"](est, X_test, y_test),
            scoring["precision"](est, X_test, y_test),
            marker,
            markersize=10,
            color=color,
            label=f"Cut-off point at probability of {decision_threshold:.2f}",
        )
        RocCurveDisplay.from_estimator(
            est,
            X_test,
            y_test,
            pos_label=pos_label,
            curve_kwargs={"linestyle": linestyle, "color": color},
            ax=axs[1],
            name=name,
            plot_chance_level=idx == 1,
        )
        axs[1].plot(
            scoring["fpr"](est, X_test, y_test),
            scoring["tpr"](est, X_test, y_test),
            marker,
            markersize=10,
            color=color,
            label=f"Cut-off point at probability of {decision_threshold:.2f}",
        )

    axs[0].set_title("Precision-Recall curve")
    axs[0].legend()
    axs[1].set_title("ROC curve")
    axs[1].legend()

    axs[2].plot(
        tuned_model.cv_results_["thresholds"],
        tuned_model.cv_results_["scores"],
        color="tab:orange",
    )
    axs[2].plot(
        tuned_model.best_threshold_,
        tuned_model.best_score_,
        "o",
        markersize=10,
        color="tab:orange",
        label="Optimal cut-off point for the business metric",
    )
    axs[2].legend()
    axs[2].set_xlabel("Decision threshold (probability)")
    axs[2].set_ylabel("Objective score (using cost-matrix)")
    axs[2].set_title("Objective score as a function of the decision threshold")
    fig.suptitle(title)
title = "Comparison of the cut-off point for the vanilla and tuned GBDT model"
plot_roc_pr_curves(model, tuned_model, title=title)
Comparison of the cut-off point for the vanilla and tuned GBDT model, Precision-Recall curve, ROC curve, Objective score as a function of the decision threshold

Первое замечание: обе модели классификации имеют в точности одинаковые ROC-кривые и кривые Precision-Recall. Это ожидаемо, поскольку по умолчанию классификатор обучается на одних и тех же данных. В одном из следующих разделов мы подробнее рассмотрим доступные варианты повторного обучения модели и перекрёстной проверки.

Второе замечание: пороговые значения базовой и настроенной моделей различаются. Чтобы понять, почему настроенная модель выбрала именно это пороговое значение, можно посмотреть на график справа, где показана целевая оценка, совпадающая с нашей бизнес-метрикой. Видно, что оптимальный порог соответствует максимальному значению целевой оценки. Максимум достигается при пороге принятия решения, значительно меньшем 0.5: настроенная модель обеспечивает гораздо более высокую полноту за счёт существенно меньшей точности. Она гораздо охотнее присваивает метку класса «bad» большей доле людей.

Теперь можно проверить, приводит ли выбор этого порогового значения к более высокой оценке на тестовой выборке:

print(f"Business defined metric: {scoring['credit_gain'](tuned_model, X_test, y_test)}")
Business defined metric: -143

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

Рассмотрение переобучения модели и кросс-валидации

В приведённом выше эксперименте мы использовали настройки по умолчанию для TunedThresholdClassifierCV. В частности, пороговое значение подбирается с помощью стратифицированной кросс-валидации с 5 блоками. Кроме того, после выбора порогового значения базовая прогнозная модель повторно обучается на всём обучающем наборе данных.

Эти две стратегии можно изменить, задав параметры refit и cv. Например, можно передать обученный estimator и установить cv="prefit" — в этом случае пороговое значение будет найдено на всём наборе данных, переданном во время обучения. Кроме того, можно отключить повторное обучение базового классификатора, задав refit=False. Попробуем провести такой эксперимент.

model.fit(X_train, y_train)
tuned_model.set_params(cv="prefit", refit=False).fit(X_train, y_train)
print(f"{tuned_model.best_threshold_=:0.2f}")
tuned_model.best_threshold_=0.25

Затем оценим нашу модель тем же способом, что и ранее:

title = "Tuned GBDT model without refitting and using the entire dataset"
plot_roc_pr_curves(model, tuned_model, title=title)
Tuned GBDT model without refitting and using the entire dataset, Precision-Recall curve, ROC curve, Objective score as a function of the decision threshold

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

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

Если кросс-валидация обходится слишком дорого, можно использовать в качестве альтернативы единственное разделение на обучающую и тестовую выборки, задав параметру cv вещественное число из диапазона [0, 1]. Данные разделяются на обучающую и тестовую выборки. Рассмотрим этот вариант:

tuned_model.set_params(cv=0.75).fit(X_train, y_train)
TunedThresholdClassifierCV(cv=0.75,
                           estimator=HistGradientBoostingClassifier(random_state=0),
                           refit=False,
                           scoring=make_scorer(credit_gain_score, response_method='predict', neg_label=good, pos_label=bad),
                           store_cv_results=True)
В среде Jupyter повторно запустите эту ячейку, чтобы отобразить HTML-представление, или доверьте работу ноутбуку.
На GitHub HTML-представление не отображается; попробуйте загрузить эту страницу с помощью nbviewer.org.
Параметры
estimator estimator: экземпляр оценщика

Обученный или необученный классификатор, для которого требуется оптимизировать
порог принятия решения, используемый во время `predict`.
HistGradientB...andom_state=0)
scoring scoring: строка или вызываемый объект, по умолчанию="balanced_accuracy"

Целевая метрика для оптимизации. Возможны следующие варианты:

- str: строка, соответствующая функции оценки для бинарной классификации,
см. варианты в :ref:`scoring_string_names`.
- callable: вызываемый объект оценки (например, функция) с сигнатурой
``scorer(estimator, X, y)``. Подробнее см. :ref:`scoring_callable`.
make_scorer(c...pos_label=bad)
cv cv: int, float, генератор кросс-валидации, итерируемый объект или "prefit", по умолчанию=None

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

* `None` — использовать стратифицированную K-блочную кросс-валидацию с 5 блоками по умолчанию;
* целое число — задать число блоков в стратифицированной k-блочной кросс-валидации;
* вещественное число — задать единственное случайное разбиение. Вещественное число должно
находиться в диапазоне (0, 1) и обозначает размер проверочной выборки;
* объект, используемый в качестве генератора кросс-валидации;
* итерируемый объект, возвращающий разделения на обучающую и тестовую выборки;
* `"prefit"` — отключить кросс-валидацию.

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

.. warning::
Использование `cv="prefit"` и передача одного и того же набора данных для обучения `estimator`
и подбора порогового значения может привести к нежелательному переобучению. Пример см.
в :ref:`TunedThresholdClassifierCV_no_cv`.

Этот параметр следует использовать только в том случае, если набор данных для обучения `estimator`
отличается от набора, используемого для подбора порогового значения (при вызове
:meth:`TunedThresholdClassifierCV.fit`).
0.75
refit refit: bool, по умолчанию=True

Нужно ли повторно обучать классификатор на всём обучающем наборе после
нахождения порога принятия решения.
Обратите внимание: если при кросс-валидации задано более
одного разбиения, принудительная установка `refit=False` вызовет ошибку. Аналогично, установка `refit=True`
в сочетании с `cv="prefit"` вызовет ошибку.
False
store_cv_results store_cv_results: bool, по умолчанию=False

Сохранять ли все оценки и пороговые значения, вычисленные в процессе кросс-валидации.
True
response_method response_method: {"auto", "decision_function", "predict_proba"}, по умолчанию="auto"

Методы классификатора `estimator`, соответствующие функции принятия
решения, для которой требуется найти порог. Возможны следующие значения:

* если задано `"auto"`, для каждого классификатора выполняется попытка вызвать
`"predict_proba"` или `"decision_function"` именно в таком порядке;
* в противном случае — один из методов `"predict_proba"` или `"decision_function"`.
Если классификатор не реализует метод, возникнет ошибка.
'auto'
thresholds thresholds: int или объект, подобный массиву, по умолчанию=100

Количество пороговых значений принятия решения, используемых при дискретизации выходных данных
метода классификатора `method`. Чтобы задать пороговые значения вручную,
передайте объект, подобный массиву.
100
n_jobs n_jobs: int, по умолчанию=None

Количество параллельно выполняемых задач. Если `cv` задаёт стратегию
кросс-валидации, обучение и оценка для каждого разделения данных
выполняются параллельно. ``None`` означает 1, если только не используется контекст
:obj:`joblib.parallel_backend`. ``-1`` означает использование всех
процессоров. Подробнее см. :term:`Глоссарий <n_jobs>`.
None
random_state random_state: int, экземпляр RandomState или None, по умолчанию=None

Управляет случайностью кросс-валидации, если `cv` задано вещественным числом.
См. :term:`Глоссарий <random_state>`.
None
Обученные атрибуты
Имя Тип Значение
best_score_ best_score_: float или None

Оптимальное значение целевой метрики, вычисленное для `best_threshold_`.
float64 -336
best_threshold_ best_threshold_: float

Новое пороговое значение принятия решения.
float64 0.01994
classes_ classes_: ndarray формы (n_classes,)

Метки классов.
ndarray[object](2,) ['bad','good']
cv_results_ cv_results_: dict или None

Словарь с оценками и пороговыми значениями, вычисленными в процессе
кросс-валидации. Существует только при `store_cv_results=True`. Ключи — `"thresholds"` и `"scores"`.
dict {'scores': array([-394.,... -840.]), 'th...ds': array([1.40e-...01, 9.80e-01])}
estimator_ estimator_: экземпляр оценщика

Обученный классификатор, используемый при прогнозировании.
HistGradientBoostingClassifier HistGradientB...andom_state=0)
feature_names_in_ feature_names_in_: ndarray формы (`n_features_in_`,)

Названия признаков, которые были доступны во время :term:`обучения`. Определён только в том случае,
если базовый оценщик предоставляет такой атрибут при обучении.
ndarray[object](20,) ['checking_status','duration','credit_history',...,'num_dependents', 'own_telephone','foreign_worker']
n_features_in_ n_features_in_: int

Количество признаков, доступных во время :term:`обучения`. Определён только в том случае,
если базовый оценщик предоставляет такой атрибут при обучении.
int 20
Параметры
random_state random_state: int, RandomState instance or None, default=None

Генератор псевдослучайных чисел для управления подвыборкой при
разбиении на бины, а также разделением данных на обучающую и проверочную
выборки при включённой ранней остановке.
Передайте целое число, чтобы получать воспроизводимые результаты при нескольких вызовах функции.
См. :term:`Глоссарий <random_state>`.
0
loss loss: {'log_loss'}, default='log_loss'

Функция потерь, используемая в процессе бустинга.

В задачах бинарной классификации 'log_loss' также называется логистической функцией потерь,
биномиальным отклонением или бинарной кросс-энтропией. Внутри модели на каждой итерации
бустинга обучается одно дерево, а для вычисления предсказанной вероятности положительного
класса в качестве обратной функции связи используется логистическая сигмоидальная функция (expit).

В задачах многоклассовой классификации 'log_loss' также называется мультиномиальным
отклонением или категориальной кросс-энтропией. Внутри модели на каждой итерации бустинга
обучается по одному дереву для каждого класса, а для вычисления предсказанных вероятностей
классов в качестве обратной функции связи используется функция softmax.
'log_loss'
learning_rate learning_rate: float, default=0.1

Скорость обучения, также называемая *сжатием*. Она используется как
множитель для значений в листьях. Используйте ``1``, чтобы отключить
сжатие.
0.1
max_iter max_iter: int, default=100

Максимальное число итераций процесса бустинга, то есть
максимальное число деревьев для бинарной классификации. Для многоклассовой
классификации на каждой итерации строится `n_classes` деревьев.
100
max_leaf_nodes max_leaf_nodes: int or None, default=31

Максимальное число листьев для каждого дерева. Должно быть строго
больше 1. Если значение равно None, максимальное ограничение отсутствует.
31
max_depth max_depth: int or None, default=None

Максимальная глубина каждого дерева. Глубина дерева — это число
рёбер от корня до самого глубокого листа.
По умолчанию глубина не ограничена.
None
min_samples_leaf min_samples_leaf: int, default=20

Минимальное число выборок в листе. Для небольших наборов данных, содержащих
менее нескольких сотен выборок, рекомендуется уменьшить это значение,
поскольку в противном случае будут строиться только очень неглубокие деревья.
20
l2_regularization l2_regularization: float, default=0

Параметр L2-регуляризации, штрафующий листья с малыми значениями гессиана.
Используйте ``0``, чтобы отключить регуляризацию (значение по умолчанию).
0.0
max_features max_features: float, default=1.0

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

.. versionadded:: 1.4
1.0
max_bins max_bins: int, default=255

Максимальное число бинов для непустых значений. Перед
обучением каждый признак входного массива `X` разбивается на бины
с целочисленными значениями, что значительно ускоряет этап обучения.
Для признаков с небольшим числом уникальных значений может использоваться меньше
бинов, чем ``max_bins``. Помимо ``max_bins`` бинов всегда
резервируется ещё один бин для пропущенных значений. Значение не должно превышать 255.
255
categorical_features categorical_features: array-like of {bool, int, str} of shape (n_features) or shape (n_categorical_features,), default='from_dtype'

Указывает категориальные признаки.

- None : ни один признак не будет считаться категориальным.
- массивоподобный объект из значений boolean : булева маска, указывающая категориальные признаки.
- массивоподобный объект из целых чисел : целочисленные индексы категориальных
признаков.
- массивоподобный объект из строк: имена категориальных признаков (предполагается, что обучающие
данные содержат имена признаков).
- `"from_dtype"`: столбцы датафрейма с типом данных "Categorical" и "Enum" считаются
категориальными признаками. На вход должен подаваться датафрейм, поддерживаемый narwhals
(или совместимый с ним): функция :func:`narwhals.from_native` должна
работать. Это, например, относится к датафреймам pandas и polars.

Для каждого категориального признака должно быть не более `max_bins` уникальных
категорий. Отрицательные значения категориальных признаков, закодированных числовыми
типами данных, считаются пропущенными. Все категориальные значения
преобразуются в числа с плавающей точкой. Это означает, что категориальные значения
1.0 и 1 считаются одной и той же категорией.

Подробнее см. в :ref:`Руководстве пользователя <categorical_support_gbdt>`.

.. versionadded:: 0.24

.. versionchanged:: 1.2
Добавлена поддержка имён признаков.

.. versionchanged:: 1.4
Добавлен параметр `"from_dtype"`.

.. versionchanged:: 1.6
Значение по умолчанию изменено с `None` на `"from_dtype"`.
'from_dtype'
monotonic_cst monotonic_cst: array-like of int of shape (n_features) or dict, default=None

Монотонное ограничение для каждого признака задаётся следующими
целочисленными значениями:

- 1: монотонное возрастание
- 0: без ограничений
- -1: монотонное убывание

Если передан словарь с ключами типа str, сопоставьте признаки с монотонными ограничениями по имени.
Если передан массив, признаки сопоставляются с ограничениями по позиции. Пример использования см. в
:ref:`monotonic_cst_features_names`.

Ограничения применимы только к бинарной классификации и задаются
для вероятности положительного класса.
Подробнее см. в :ref:`Руководстве пользователя <monotonic_cst_gbdt>`.

.. versionadded:: 0.23

.. versionchanged:: 1.2
Добавлена поддержка словаря ограничений с именами признаков в качестве ключей.
None
interaction_cst interaction_cst: {"pairwise", "no_interactions"} or sequence of lists/tuples/sets of int, default=None

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

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

Строки "pairwise" и "no_interactions" — это сокращённые обозначения
для разрешения только попарных взаимодействий и полного запрета взаимодействий соответственно.

Например, если всего имеется 5 признаков, `interaction_cst=[{0, 1}]`
эквивалентно `interaction_cst=[{0, 1}, {2, 3, 4}]`
и означает, что каждая ветвь дерева будет разбиваться либо только
по признакам 0 и 1, либо только по признакам 2, 3 и 4.

Пример использования `interaction_cst` см. в :ref:`этом примере<ice-vs-pdp>`.

.. versionadded:: 1.2
None
warm_start warm_start: bool, default=False

Если установлено значение ``True``, повторно используется результат предыдущего вызова fit,
а в ансамбль добавляются новые оцениватели. Чтобы результаты были корректными,
оцениватель следует повторно обучать только на тех же данных.
См. :term:`глоссарий <warm_start>`.
False
early_stopping early_stopping: 'auto' or bool, default='auto'

При значении 'auto' ранняя остановка включается, если размер выборки превышает
10000 или если в `fit` переданы `X_val` и `y_val`. При значении True ранняя остановка
включена, в противном случае она отключена.

.. versionadded:: 0.23
'auto'
scoring scoring: str or callable or None, default='loss'

Метод оценки, используемый для ранней остановки. Используется только при включённой
ранней остановке. Возможные значения:

- str: варианты см. в :ref:`scoring_string_names`.
- callable: вызываемый объект-оценщик (например, функция) с сигнатурой
``scorer(estimator, X, y)``. Подробнее см. в :ref:`scoring_callable`.
- `None`: используется :ref:`точность <accuracy_score>`.
- 'loss': ранняя остановка проверяется по значению функции потерь.
'loss'
validation_fraction validation_fraction: int or float or None, default=0.1

Доля (или абсолютный размер) обучающих данных, выделяемая
в проверочную выборку для ранней остановки. Если значение равно None, ранняя остановка выполняется на
обучающих данных.
Значение игнорируется, если ранняя остановка не выполняется, например
при `early_stopping=False`, или если в fit переданы `X_val` и `y_val`.
0.1
n_iter_no_change n_iter_no_change: int, default=10

Используется для определения момента «ранней остановки». Процесс обучения
останавливается, если ни одна из последних ``n_iter_no_change`` оценок не лучше,
чем оценка на ``n_iter_no_change - 1``-ю позицию с конца, с учётом некоторого
допуска. Используется только при выполнении ранней остановки.
10
tol tol: float, default=1e-7

Абсолютный допуск, используемый при сравнении оценок. Чем выше
допуск, тем вероятнее ранняя остановка: при большем допуске
последующим итерациям сложнее считаться улучшением
относительно эталонной оценки.
1e-07
verbose verbose: int, default=0

Уровень подробности вывода. Если значение не равно нулю, выводится информация о
процессе обучения. ``1`` выводит только сводную информацию, ``2`` — информацию для каждой
итерации.
0
class_weight class_weight: dict or 'balanced', default=None

Веса классов в формате `{class_label: weight}`.
Если значение не задано, предполагается, что веса всех классов равны единице.
Режим "balanced" использует значения y для автоматической корректировки
весов обратно пропорционально частотам классов во входных данных
по формуле `n_samples / (n_classes * np.bincount(y))`.
Если задан `sample_weight`, эти веса перемножаются с весами выборок (переданными
через метод fit).

.. versionadded:: 1.2
None
Обученные атрибуты
Имя Тип Значение
classes_ classes_: array, shape = (n_classes,)

Метки классов.
ndarray[object](2,) ['bad','good']
do_early_stopping_ do_early_stopping_: bool

Показывает, используется ли ранняя остановка во время обучения.
bool False
feature_names_in_ feature_names_in_: ndarray of shape (`n_features_in_`,)

Имена признаков, полученные во время :term:`fit`. Определяется только в том случае, если `X`
содержит имена признаков, представленные строками.

.. versionadded:: 1.0
ndarray[object](20,) ['checking_status','duration','credit_history',...,'num_dependents', 'own_telephone','foreign_worker']
is_categorical_ is_categorical_: ndarray, shape (n_features, ) or None

Булева маска категориальных признаков. Равно ``None``, если категориальных
признаков нет.
ndarray[bool](20,) [ True,False, True,...,False, True, True]
n_features_in_ n_features_in_: int

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

.. versionadded:: 0.24
int 20
n_iter_ n_iter_: int

Число итераций, выбранное с помощью ранней остановки в зависимости от
параметра `early_stopping`. В противном случае соответствует max_iter.
int 100
n_trees_per_iteration_ n_trees_per_iteration_: int

Число деревьев, строящихся на каждой итерации. Для бинарной классификации оно равно 1,
а для многоклассовой классификации — ``n_classes``.
int 1
train_score_ train_score_: ndarray, shape (n_iter_+1,)

Оценки на обучающих данных для каждой итерации. Первый элемент
содержит оценку ансамбля до первой итерации. Оценки
вычисляются в соответствии с параметром ``scoring``. Если ``scoring``
не равно 'loss', оценки вычисляются на подмножестве не более чем из 10 000
выборок. Пусто, если ранняя остановка не выполняется.
ndarray[float64](0,) []
validation_score_ validation_score_: ndarray, shape (n_iter_+1,)

Оценки на отложенных проверочных данных для каждой итерации. Первый
элемент содержит оценку ансамбля до первой итерации.
Оценки вычисляются в соответствии с параметром ``scoring``. Пусто, если
ранняя остановка не выполняется или если ``validation_fraction`` равно None.
ndarray[float64](0,) []


title = "Tuned GBDT model without refitting and using the entire dataset"
plot_roc_pr_curves(model, tuned_model, title=title)
Tuned GBDT model without refitting and using the entire dataset, Precision-Recall curve, ROC curve, Objective score as a function of the decision threshold

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

Ещё одно наблюдение касается ROC-кривой и кривой Precision-Recall настроенной модели. Как и ожидалось, эти кривые отличаются от кривых исходной модели, поскольку базовый классификатор обучался на подмножестве данных, предоставленных при обучении, а проверочная выборка была зарезервирована для настройки порогового значения.

Обучение с учетом затрат, когда выгоды и затраты непостоянны

Как указано в [2], в реальных задачах выгоды и затраты, как правило, непостоянны. В этом разделе мы используем пример, аналогичный приведенному в [2], для задачи обнаружения мошенничества в записях транзакций по кредитным картам.

Набор данных о кредитных картах

credit_card = fetch_openml(data_id=1597, as_frame=True, parser="pandas")
credit_card.frame.info()
<class 'pandas.DataFrame'>
RangeIndex: 284807 entries, 0 to 284806
Data columns (total 30 columns):
 #   Column  Non-Null Count   Dtype
---  ------  --------------   -----
 0   V1      284807 non-null  float64
 1   V2      284807 non-null  float64
 2   V3      284807 non-null  float64
 3   V4      284807 non-null  float64
 4   V5      284807 non-null  float64
 5   V6      284807 non-null  float64
 6   V7      284807 non-null  float64
 7   V8      284807 non-null  float64
 8   V9      284807 non-null  float64
 9   V10     284807 non-null  float64
 10  V11     284807 non-null  float64
 11  V12     284807 non-null  float64
 12  V13     284807 non-null  float64
 13  V14     284807 non-null  float64
 14  V15     284807 non-null  float64
 15  V16     284807 non-null  float64
 16  V17     284807 non-null  float64
 17  V18     284807 non-null  float64
 18  V19     284807 non-null  float64
 19  V20     284807 non-null  float64
 20  V21     284807 non-null  float64
 21  V22     284807 non-null  float64
 22  V23     284807 non-null  float64
 23  V24     284807 non-null  float64
 24  V25     284807 non-null  float64
 25  V26     284807 non-null  float64
 26  V27     284807 non-null  float64
 27  V28     284807 non-null  float64
 28  Amount  284807 non-null  float64
 29  Class   284807 non-null  category
dtypes: category(1), float64(29)
memory usage: 63.3 MB

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

columns_to_drop = ["Class"]
data = credit_card.frame.drop(columns=columns_to_drop)
target = credit_card.frame["Class"].astype(int)

Сначала проверим распределение классов в наборах данных.

target.value_counts(normalize=True)
Class
0    0.998273
1    0.001727
Name: proportion, dtype: float64

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

target.value_counts()
Class
0    284315
1       492
Name: count, dtype: int64

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

fraud = target == 1
amount_fraud = data["Amount"][fraud]
_, ax = plt.subplots()
ax.hist(amount_fraud, bins=30)
ax.set_title("Amount of fraud transaction")
_ = ax.set_xlabel("Amount (€)")
Amount of fraud transaction

Решение задачи с помощью бизнес-метрики

Теперь создадим бизнес-метрику, зависящую от суммы каждой транзакции. Мы определяем матрицу затрат аналогично [2]. Принятие законной транзакции приносит прибыль в размере 2% от ее суммы. Однако принятие мошеннической транзакции приводит к убытку, равному сумме транзакции. Как указано в [2], выгоду и убыток, связанные с отказом (от мошеннических и законных транзакций), непросто определить. Здесь мы считаем, что отказ от законной транзакции приводит к убытку в размере 5€, а отказ от мошеннической транзакции приносит выгоду в размере 50€. Таким образом, определим следующую функцию для вычисления общей выгоды от принятого решения:

def business_metric(y_true, y_pred, amount):
    mask_true_positive = (y_true == 1) & (y_pred == 1)
    mask_true_negative = (y_true == 0) & (y_pred == 0)
    mask_false_positive = (y_true == 0) & (y_pred == 1)
    mask_false_negative = (y_true == 1) & (y_pred == 0)
    fraudulent_refuse = mask_true_positive.sum() * 50
    fraudulent_accept = -amount[mask_false_negative].sum()
    legitimate_refuse = mask_false_positive.sum() * -5
    legitimate_accept = (amount[mask_true_negative] * 0.02).sum()
    return fraudulent_refuse + fraudulent_accept + legitimate_refuse + legitimate_accept

На основе этой бизнес-метрики мы создаем оценщик scikit-learn, который вычисляет бизнес-метрику для обученного классификатора и тестового набора. Для этого мы используем фабрику make_scorer. Переменная amount — это дополнительные метаданные, которые передаются оценщику; чтобы учесть эту информацию, необходимо использовать маршрутизацию метаданных.

sklearn.set_config(enable_metadata_routing=True)
business_scorer = make_scorer(business_metric).set_score_request(amount=True)

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

amount = credit_card.frame["Amount"].to_numpy()
from sklearn.model_selection import train_test_split

data_train, data_test, target_train, target_test, amount_train, amount_test = (
    train_test_split(
        data, target, amount, stratify=target, test_size=0.5, random_state=42
    )
)

Сначала оценим несколько базовых стратегий, которые будут служить ориентиром. Напомним, что класс «0» соответствует законным транзакциям, а класс «1» — мошенническим.

from sklearn.dummy import DummyClassifier

always_accept_policy = DummyClassifier(strategy="constant", constant=0)
always_accept_policy.fit(data_train, target_train)
benefit = business_scorer(
    always_accept_policy, data_test, target_test, amount=amount_test
)
print(f"Benefit of the 'always accept' policy: {benefit:,.2f}€")
Benefit of the 'always accept' policy: 221,445.07€

Стратегия, считающая все транзакции законными, принесла бы прибыль около 220,000€. Аналогично оценим классификатор, который предсказывает, что все транзакции являются мошенническими.

always_reject_policy = DummyClassifier(strategy="constant", constant=1)
always_reject_policy.fit(data_train, target_train)
benefit = business_scorer(
    always_reject_policy, data_test, target_test, amount=amount_test
)
print(f"Benefit of the 'always reject' policy: {benefit:,.2f}€")
Benefit of the 'always reject' policy: -698,490.00€

Такая стратегия повлекла бы катастрофические убытки — около 670,000€. Это ожидаемо, поскольку подавляющее большинство транзакций являются законными, а стратегия отклоняла бы их, неся существенные затраты.

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

Начнем с логистической регрессии, использующей порог принятия решения по умолчанию, равный 0.5. Здесь мы настраиваем гиперпараметр C логистической регрессии с помощью корректного правила оценки (логарифмической функции потерь), чтобы вероятностные предсказания модели, возвращаемые методом predict_proba, были максимально точными независимо от выбранного значения порога принятия решения.

from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

logistic_regression = make_pipeline(StandardScaler(), LogisticRegression())
param_grid = {"logisticregression__C": np.logspace(-6, 6, 13)}
model = GridSearchCV(logistic_regression, param_grid, scoring="neg_log_loss").fit(
    data_train, target_train
)
model
GridSearchCV(estimator=Pipeline(steps=[('standardscaler', StandardScaler()),
                                       ('logisticregression',
                                        LogisticRegression())]),
             param_grid={'logisticregression__C': array([1.e-06, 1.e-05, 1.e-04, 1.e-03, 1.e-02, 1.e-01, 1.e+00, 1.e+01,
       1.e+02, 1.e+03, 1.e+04, 1.e+05, 1.e+06])},
             scoring='neg_log_loss')
В среде Jupyter повторно выполните эту ячейку, чтобы отобразить HTML-представление, или доверьте ноутбуку.
На GitHub HTML-представление не отображается; попробуйте открыть эту страницу с помощью nbviewer.org.
Параметры
estimator estimator: объект оценщика

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

Словарь, в котором ключами являются имена параметров (`str`), а значениями — списки
проверяемых вариантов параметров, либо список таких
словарей. В последнем случае проверяются сетки, заданные каждым словарем
в списке. Это позволяет выполнять поиск по любой последовательности
вариантов параметров.
{'logisticregression__C': array([1.e-06...e+05, 1.e+06])}
scoring scoring: str, вызываемый объект, список, кортеж или словарь, по умолчанию=None

Стратегия оценки эффективности модели, проверенной с помощью перекрестной проверки, на
тестовом наборе.

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

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

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

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

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

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

.. versionchanged:: v0.20
Значение `n_jobs` по умолчанию изменено с 1 на None
None
refit refit: bool, str или вызываемый объект, по умолчанию=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:`this example
<sphx_glr_auto_examples_model_selection_plot_grid_search_refit_callable.py>`.

.. versionchanged:: 0.20
Добавлена поддержка вызываемого объекта.
True
cv cv: int, генератор перекрестной проверки или итерируемый объект, по умолчанию=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.
None
verbose verbose: int, по умолчанию=0

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

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

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

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

Значение оценки, назначаемое в случае ошибки при обучении оценщика.
Если задано значение 'raise', ошибка будет вызвана. Если задано числовое значение,
вызывается FitFailedWarning. Этот параметр не влияет на этап повторного обучения,
который всегда будет вызывать ошибку.
nan
return_train_score return_train_score: bool, по умолчанию=False

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

.. versionadded:: 0.19

.. versionchanged:: 0.21
Значение по умолчанию изменено с ``True`` на ``False``
False
Обученные атрибуты
Имя Тип Значение
best_estimator_ best_estimator_: оценщик

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

Подробнее о допустимых значениях см. описание параметра ``refit``.
Pipeline Pipeline(step...t64(100.0)))])
best_index_ best_index_: int

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

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

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

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

При оценке по нескольким метрикам доступен только в том случае, если задан ``refit``.
dict {'lo..._C': np.float64(100.0)}
best_score_ best_score_: float

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

При оценке по нескольким метрикам доступен только в том случае, если задан ``refit``.

Этот атрибут недоступен, если ``refit`` является функцией.
float64 -0.003994
classes_ classes_: ndarray формы (n_classes,)

Метки классов. Атрибут присутствует только в том случае, если задан ``refit`` и
базовый оценщик является классификатором.
ndarray[int64](2,) [0,1]
cv_results_ cv_results_: словарь маскированных или обычных массивов NumPy

Словарь, в котором ключи являются заголовками столбцов, а значения — столбцами; его можно
импортировать в ``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.2 , ... 0.24, 0.24]), 'me...me': array([0.02, ... 0.02, 0.02]), 'me...re': array([-0.01,...-0. , -0. ]), 'pa..._C': masked_array(...l_value=1e+20), ...}
feature_names_in_ feature_names_in_: ndarray формы (`n_features_in_`,)

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

.. versionadded:: 1.0
ndarray[object](29,) ['V1','V2','V3',...,'V27','V28','Amount']
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 29
n_splits_ n_splits_: int

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

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

Присутствует только в том случае, если ``refit`` не равен False.

.. versionadded:: 0.20
float 0.3153
scorer_ scorer_: функция или словарь

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

При оценке по нескольким метрикам этот атрибут содержит проверенный
словарь ``scoring``, связывающий ключ оценщика с вызываемым объектом-оценщиком.
_Scorer make_scorer(l...redict_proba')
Параметры
copy copy: bool, default=True

Если False, попытаться избежать копирования и выполнить масштабирование на месте.
Это не гарантируется в каждом случае; например, если данные
не являются массивом NumPy или матрицей scipy.sparse CSR, всё равно
может быть возвращена копия.
True
with_mean with_mean: bool, default=True

Если True, центрировать данные перед масштабированием.
Это не работает (и вызывает исключение) при попытке применить параметр к
разреженным матрицам, поскольку центрирование требует создания плотной
матрицы, которая в типичных случаях может быть слишком большой, чтобы
поместиться в памяти.
True
with_std with_std: bool, default=True

Если True, масштабировать данные до единичной дисперсии (или, что эквивалентно,
единичного стандартного отклонения).
True
Обученные атрибуты
Имя Тип Значение
feature_names_in_ feature_names_in_: ndarray формы (`n_features_in_`,)

Имена признаков, обнаруженных при :term:`fit`. Определён только в том случае, если `X`
содержит имена признаков, все из которых являются строками.

.. versionadded:: 1.0
ndarray[object](29,) ['V1','V2','V3',...,'V27','V28','Amount']
mean_ mean_: ndarray формы (n_features,) или None

Среднее значение каждого признака в обучающем наборе.
Равно ``None``, если ``with_mean=False`` и ``with_std=False``.
ndarray[float64](29,) [ 0. ,-0. ,-0.01,..., 0. , 0. ,88.35]
n_features_in_ n_features_in_: int

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

.. versionadded:: 0.24
int 29
n_samples_seen_ n_samples_seen_: int или ndarray формы (n_features,)

Количество образцов, обработанных оценивателем для каждого признака.
Если отсутствующие образцы нет, ``n_samples_seen`` будет целым числом;
иначе это будет массив типа int. Если используются
`sample_weights`, значение будет числом с плавающей точкой (при отсутствии пропущенных данных)
или массивом типа float, содержащим сумму весов, учтённых на данный момент.
Сбрасывается при новых вызовах fit, но увеличивается при вызовах
``partial_fit``.
float64 1.424e+05
scale_ scale_: ndarray формы (n_features,) или None

Масштабирование данных для каждого признака, необходимое для достижения нулевого среднего и единичной
дисперсии. Обычно вычисляется с помощью `np.sqrt(var_)`. Если
дисперсия равна нулю, достичь единичной дисперсии невозможно, и данные остаются
без изменений, коэффициент масштабирования равен 1. `scale_` равно `None`,
если `with_std=False`.

.. versionadded:: 0.17
*scale_*
ndarray[float64](29,) [ 1.97, 1.66, 1.53,..., 0.41, 0.31,256.68]
var_ var_: ndarray формы (n_features,) или None

Дисперсия каждого признака в обучающем наборе. Используется для вычисления
`scale_`. Равно ``None``, если ``with_mean=False`` и
``with_std=False``.
ndarray[float64](29,) [ 3.86, 2.75, 2.34,..., 0.17, 0.1 ,65885.14]
29 признаков
V1
V2
V3
V4
V5
V6
V7
V8
V9
V10
V11
V12
V13
V14
V15
V16
V17
V18
V19
V20
V21
V22
V23
V24
V25
V26
V27
V28
Amount
Параметры
C C: float, default=1.0

Обратная сила регуляризации; должно быть положительным числом с плавающей точкой.
Как и в машинах опорных векторов, меньшие значения задают более сильную
регуляризацию. `C=np.inf` приводит к логистической регрессии без штрафа.
Визуальный пример влияния настройки параметра `C`
при штрафе L1 см. здесь:
:ref:`sphx_glr_auto_examples_linear_model_plot_logistic_path.py`.
np.float64(100.0)
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`. Для `penalty='l2'` задайте `l1_ratio=0`,
для `penalty='l1'` — `l1_ratio=1`, для `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`,
если `self.fit_intercept` имеет значение `True`. В этом случае `x` становится
`[x, self.intercept_scaling]`,
то есть к вектору экземпляра добавляется «синтетический» признак с постоянным значением,
равным `intercept_scaling`.
Свободный член становится равным
``intercept_scaling * synthetic_feature_weight``.

.. note::
Вес синтетического признака, как и веса всех остальных признаков,
подвергается регуляризации L1 или L2.
Чтобы уменьшить влияние регуляризации на вес синтетического признака
(и, следовательно, на свободный член), необходимо увеличить `intercept_scaling`.
1
class_weight class_weight: dict или '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
random_state random_state: int, экземпляр RandomState, default=None

Используется для перемешивания данных, если ``solver`` == 'sag', 'saga' или 'liblinear'.
Подробности см. в :term:`глоссарии <random_state>`.
None
solver solver: {'lbfgs', 'liblinear', 'newton-cg', 'newton-cholesky', 'sag', 'saga'}, default='lbfgs'

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

- 'lbfgs' — хороший вариант по умолчанию, поскольку он достаточно хорошо работает для широкого
класса задач.
- Для задач :term:`многоклассовой классификации` (`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 мультиномиальная многоклассовая классификация
================= ======================== ======================
'lbfgs' l1_ratio=0 да
'liblinear' l1_ratio=1 или l1_ratio=0 нет
'newton-cg' l1_ratio=0 да
'newton-cholesky' l1_ratio=0 да
'sag' l1_ratio=0 да
'saga' 0<=l1_ratio<=1 да
================= ======================== ======================

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

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

.. 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'
max_iter max_iter: int, default=100

Максимальное количество итераций, выполняемых решателями для достижения сходимости.
100
verbose verbose: int, default=0

Для решателей liblinear и lbfgs задайте положительное значение verbose,
чтобы включить подробный вывод.
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](2,) [0,1]
coef_ coef_: ndarray или матрица CSR формы (1, n_features) или (n_classes, n_features)

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

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

По умолчанию создаётся плотный массив, но его можно преобразовать в
разреженный (формат CSR) с помощью :meth:`sparsify` (это может быть полезно
при регуляризации L1, если многие коэффициенты равны нулю), а затем обратно в
плотный с помощью :meth:`densify`.
ndarray[float64](1, 29) [[ 0.1 , 0.02, 0.1 ,...,-0.3 ,-0.05, 0.18]]
feature_names_in_ feature_names_in_: ndarray формы (`n_features_in_`,)

Имена признаков, обнаруженных при :term:`fit`. Определён только в том случае, если `X`
содержит имена признаков, все из которых являются строками.

.. versionadded:: 1.0
ndarray[object](29,) ['V1','V2','V3',...,'V27','V28','Amount']
intercept_ intercept_: ndarray формы (1,) или (n_classes,)

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

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

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

.. versionadded:: 0.24
int 29
n_iter_ n_iter_: ndarray формы (1, )

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

.. versionchanged:: 0.20

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


print(
    "Benefit of logistic regression with default threshold: "
    f"{business_scorer(model, data_test, target_test, amount=amount_test):,.2f}€"
)
Benefit of logistic regression with default threshold: 244,919.87€

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

Настройка порога принятия решения

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

tuned_model = TunedThresholdClassifierCV(
    estimator=model.best_estimator_,
    scoring=business_scorer,
    thresholds=100,
    n_jobs=2,
)

Поскольку для нашей бизнес-оценочной функции требуется сумма каждой транзакции, эту информацию нужно передать в метод fit. TunedThresholdClassifierCV автоматически передает эти метаданные используемой оценочной функции.

tuned_model.fit(data_train, target_train, amount=amount_train)
TunedThresholdClassifierCV(estimator=Pipeline(steps=[('standardscaler',
                                                      StandardScaler()),
                                                     ('logisticregression',
                                                      LogisticRegression(C=np.float64(100.0)))]),
                           n_jobs=2,
                           scoring=make_scorer(business_metric, response_method='predict'))
В среде Jupyter повторно выполните эту ячейку, чтобы отобразить HTML-представление, или доверьте работу с блокнотом.
На GitHub HTML-представление не отображается; попробуйте открыть эту страницу с помощью nbviewer.org.
Параметры
estimator estimator: экземпляр оценщика

Классификатор (обученный или нет), для которого требуется оптимизировать
порог принятия решения, используемый во время `predict`.
Pipeline(step...t64(100.0)))])
scoring scoring: строка или вызываемый объект, по умолчанию="balanced_accuracy"

Целевая метрика для оптимизации. Может иметь одно из следующих значений:

- str: строка, связанная с функцией оценки для бинарной классификации;
варианты см. в :ref:`scoring_string_names`.
- callable: вызываемый объект оценщика (например, функция) с сигнатурой
``scorer(estimator, X, y)``. Подробности см. в :ref:`scoring_callable`.
make_scorer(b...hod='predict')
n_jobs n_jobs: целое число, по умолчанию=None

Количество задач, выполняемых параллельно. Если `cv` задает стратегию
перекрестной проверки, обучение и оценка для каждой части данных
выполняются параллельно. Значение ``None`` означает 1, если только не используется
контекст :obj:`joblib.parallel_backend`. Значение ``-1`` означает использование всех
процессоров. Дополнительные сведения см. в :term:`Глоссарии <n_jobs>`.
2
response_method response_method: {"auto", "decision_function", "predict_proba"}, по умолчанию="auto"

Методы классификатора `estimator`, соответствующие функции
принятия решения, для которой требуется найти порог. Возможные значения:

* если указано `"auto"`, для каждого классификатора по очереди
вызывается `"predict_proba"` или `"decision_function"`.
* в противном случае — одно из значений `"predict_proba"` или `"decision_function"`.
Если классификатор не реализует этот метод, будет вызвана
ошибка.
'auto'
thresholds thresholds: целое число или массивоподобный объект, по умолчанию=100

Количество порогов принятия решения, используемых при дискретизации результата
метода классификатора `method`. Передайте массивоподобный объект, чтобы вручную задать пороги,
которые следует использовать.
100
cv cv: целое число, число с плавающей точкой, генератор перекрестной проверки, итерируемый объект или "prefit", по умолчанию=None

Определяет стратегию разбиения для перекрестной проверки при обучении классификатора.
Для cv возможны следующие значения:

* `None` — использовать стратифицированную перекрестную проверку k-блоками с 5 блоками по умолчанию;
* целое число — задать количество блоков в стратифицированной перекрестной проверке k-блоками;
* число с плавающей точкой — задать единственное разбиение с перемешиванием. Число с плавающей точкой должно
находиться в диапазоне (0, 1) и обозначать размер проверочной выборки;
* объект, используемый в качестве генератора перекрестной проверки;
* итерируемый объект, возвращающий разбиения на обучающие и тестовые данные;
* `"prefit"` — пропустить перекрестную проверку.

Различные стратегии перекрестной проверки, которые можно использовать здесь,
описаны в :ref:`Руководстве пользователя <cross_validation>`.

.. warning::
Использование `cv="prefit"` и передача одного и того же набора данных для обучения `estimator`
и настройки точки отсечения может привести к нежелательному переобучению. Пример см.
в :ref:`TunedThresholdClassifierCV_no_cv`.

Этот параметр следует использовать только в том случае, если набор данных, использованный для обучения `estimator`,
отличается от набора, использованного для настройки точки отсечения (при вызове
:meth:`TunedThresholdClassifierCV.fit`).
None
refit refit: логическое значение, по умолчанию=True

Следует ли повторно обучить классификатор на всем обучающем наборе после
определения порога принятия решения.
Обратите внимание: если установить `refit=False` при перекрестной проверке более чем с
одним разбиением, возникнет ошибка. Аналогично, при использовании `refit=True`
в сочетании с `cv="prefit"` возникнет ошибка.
True
random_state random_state: целое число, экземпляр RandomState или None, по умолчанию=None

Управляет случайностью перекрестной проверки, если `cv` — число с плавающей точкой.
См. :term:`Глоссарий <random_state>`.
None
store_cv_results store_cv_results: логическое значение, по умолчанию=False

Следует ли сохранять все оценки и пороги, вычисленные в процессе
перекрестной проверки.
False
Атрибуты обученной модели
Имя Тип Значение
best_score_ best_score_: число с плавающей точкой или None

Оптимальное значение целевой метрики, вычисленное при `best_threshold_`.
float64 5.057e+04
best_threshold_ best_threshold_: число с плавающей точкой

Новый порог принятия решения.
float64 0.0303
classes_ classes_: ndarray формы (n_classes,)

Метки классов.
ndarray[int64](2,) [0,1]
estimator_ estimator_: экземпляр оценщика

Обученный классификатор, используемый при прогнозировании.
Pipeline Pipeline(step...t64(100.0)))])
feature_names_in_ feature_names_in_: ndarray формы (`n_features_in_`,)

Имена признаков, обнаруженных во время :term:`fit`. Определен только в том случае, если
базовый оценщик предоставляет такой атрибут при обучении.
ndarray[object](29,) ['V1','V2','V3',...,'V27','V28','Amount']
n_features_in_ n_features_in_: целое число

Количество признаков, обнаруженных во время :term:`fit`. Определено только в том случае, если
базовый оценщик предоставляет такой атрибут при обучении.
int 29
Параметры
steps steps: список кортежей

Список кортежей (имя шага, оценщик), которые объединяются
в последовательность. Для совместимости с API scikit-learn все шаги
должны определять `fit`. Все шаги, кроме последнего, также должны определять `transform`. Дополнительные сведения см.
в :ref:`Объединение оценщиков <combining_estimators>`.
[('standardscaler', ...), ('logisticregression', ...)]
transform_input transform_input: список строк, по умолчанию=None

Имена параметров :term:`метаданных`, которые должны быть преобразованы конвейером
перед передачей шагу, который их использует.

Это позволяет преобразовывать некоторые входные аргументы ``fit`` (кроме ``X``)
с помощью шагов конвейера вплоть до шага, которому они требуются.
Требование задается с помощью :ref:`маршрутизации метаданных <metadata_routing>`.
Например, это можно использовать для передачи проверочного набора через конвейер.

Этот параметр можно задать, только если включена маршрутизация метаданных. Ее
можно включить с помощью ``sklearn.set_config(enable_metadata_routing=True)``.

.. versionadded:: 1.6
None
memory memory: строка или объект с интерфейсом joblib.Memory, по умолчанию=None

Используется для кэширования обученных преобразователей конвейера. Последний шаг
никогда не кэшируется, даже если это преобразователь. По умолчанию кэширование
не выполняется. Если указана строка, она задает путь к каталогу
кэширования. Включение кэширования приводит к созданию копий преобразователей
перед обучением. Поэтому экземпляр преобразователя, переданный
конвейеру, нельзя проверить напрямую. Для просмотра оценщиков внутри конвейера используйте атрибут ``named_steps``
или ``steps``. Кэширование
преобразователей полезно, если обучение занимает много времени. Пример включения кэширования см.
в :ref:`sphx_glr_auto_examples_neighbors_plot_caching_nearest_neighbors.py`.
None
verbose verbose: логическое значение, по умолчанию=False

Если значение True, по завершении каждого шага выводится время, затраченное на его
обучение.
False
Атрибуты обученной модели
Имя Тип Значение
classes_ classes_: ndarray формы (n_classes,)

Метки классов. Существует только в том случае, если последний шаг конвейера —
классификатор.
ndarray[int64](2,) [0,1]
feature_names_in_ feature_names_in_: ndarray формы (`n_features_in_`,)

Имена признаков, обнаруженных во время :term:`fit`. Определен только в том случае, если
базовый оценщик предоставляет такой атрибут при обучении.

.. versionadded:: 1.0
ndarray[object](29,) ['V1','V2','V3',...,'V27','V28','Amount']
n_features_in_ n_features_in_: целое число

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

.. versionadded:: 0.24
int 29
Параметры
copy copy: bool, default=True

Если False, пытается избежать копирования и вместо этого выполнить масштабирование на месте.
Это не всегда гарантированно выполняется на месте; например, если данные
не являются массивом NumPy или разреженной матрицей scipy.sparse CSR, может быть возвращена
копия.
True
with_mean with_mean: bool, default=True

Если True, центрировать данные перед масштабированием.
Это не работает (и вызовет исключение) при использовании
разреженных матриц, поскольку центрирование подразумевает создание плотной
матрицы, которая в обычных случаях использования, скорее всего, будет слишком большой для размещения в
памяти.
True
with_std with_std: bool, default=True

Если True, масштабировать данные до единичной дисперсии (или, что равносильно,
единичного стандартного отклонения).
True
Атрибуты обученной модели
Имя Тип Значение
feature_names_in_ feature_names_in_: ndarray of shape (`n_features_in_`,)

Названия признаков, использованных при :term:`обучении`. Определяется только в том случае, если `X`
содержит названия признаков, представленные строками.

.. versionadded:: 1.0
ndarray[object](29,) ['V1','V2','V3',...,'V27','V28','Amount']
mean_ mean_: ndarray of shape (n_features,) or None

Среднее значение каждого признака в обучающем наборе.
Равно ``None``, если ``with_mean=False`` и ``with_std=False``.
ndarray[float64](29,) [ 0. ,-0. ,-0.01,..., 0. , 0. ,88.35]
n_features_in_ n_features_in_: int

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

.. versionadded:: 0.24
int 29
n_samples_seen_ n_samples_seen_: int or ndarray of shape (n_features,)

Количество обработанных оценивателем образцов для каждого признака.
Если пропущенных образцов нет, ``n_samples_seen`` будет целым числом, иначе — массивом типа int. Если
используются `sample_weights`, значение будет числом с плавающей точкой (если пропущенных данных нет)
или массивом типа float, содержащим сумму весов, учтённых на данный момент.
Сбрасывается при новых вызовах fit, но увеличивается при вызовах
``partial_fit``.
float64 1.424e+05
scale_ scale_: ndarray of shape (n_features,) or None

Масштабирование данных относительно каждого признака для достижения нулевого среднего и единичной
дисперсии. Обычно вычисляется с помощью `np.sqrt(var_)`. Если
дисперсия равна нулю, достичь единичной дисперсии невозможно, поэтому данные остаются
без изменений, а коэффициент масштабирования равен 1. `scale_` равно `None`,
если `with_std=False`.

.. versionadded:: 0.17
*scale_*
ndarray[float64](29,) [ 1.97, 1.66, 1.53,..., 0.41, 0.31,256.68]
var_ var_: ndarray of shape (n_features,) or None

Дисперсия каждого признака в обучающем наборе. Используется для вычисления
`scale_`. Равно ``None``, если ``with_mean=False`` и
``with_std=False``.
ndarray[float64](29,) [ 3.86, 2.75, 2.34,..., 0.17, 0.1 ,65885.14]
29 признаков
V1
V2
V3
V4
V5
V6
V7
V8
V9
V10
V11
V12
V13
V14
V15
V16
V17
V18
V19
V20
V21
V22
V23
V24
V25
V26
V27
V28
Amount
Параметры
C C: float, default=1.0

Обратная сила регуляризации; должно быть положительным числом с плавающей точкой.
Как и в методе опорных векторов, меньшие значения задают более сильную
регуляризацию. `C=np.inf` соответствует логистической регрессии без штрафа.
Наглядный пример влияния настройки параметра `C`
при штрафе L1 см. здесь:
:ref:`sphx_glr_auto_examples_linear_model_plot_logistic_path.py`.
np.float64(100.0)
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`. Для `penalty='l2'` задайте `l1_ratio=0`,
для `penalty='l1'` — `l1_ratio=1`, для `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
random_state random_state: int, RandomState instance, default=None

Используется для перемешивания данных, если ``solver`` == 'sag', 'saga' или 'liblinear'. Подробности см. в :term:`глоссарии <random_state>`.
None
solver solver: {'lbfgs', 'liblinear', 'newton-cg', 'newton-cholesky', 'sag', 'saga'}, default='lbfgs'

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

- 'lbfgs' — хороший вариант по умолчанию, поскольку он достаточно эффективно работает для широкого
класса задач.
- Для задач :term:`многоклассовой классификации` (`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), а также от поддержки многоклассовой классификации (multinomial):

================= ======================== ======================
solver l1_ratio многоклассовая классификация multinomial
================= ======================== ======================
'lbfgs' l1_ratio=0 да
'liblinear' l1_ratio=1 или l1_ratio=0 нет
'newton-cg' l1_ratio=0 да
'newton-cholesky' l1_ratio=0 да
'sag' l1_ratio=0 да
'saga' 0<=l1_ratio<=1 да
================= ======================== ======================

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

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

.. 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'
max_iter max_iter: int, default=100

Максимальное количество итераций, выполняемых решателями до сходимости.
100
verbose verbose: int, default=0

Для решателей liblinear и lbfgs задайте любое положительное значение verbose,
чтобы включить подробный вывод.
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 of shape (n_classes, )

Список меток классов, известных классификатору.
ndarray[int64](2,) [0,1]
coef_ coef_: ndarray or CSR matrix of shape (1, n_features) or (n_classes, n_features)

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

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

По умолчанию создаётся плотный массив, но его можно преобразовать в
разреженный (формат CSR) с помощью :meth:`sparsify` (это может быть полезно
при регуляризации L1, когда многие коэффициенты равны нулю), а затем снова преобразовать в
плотный с помощью :meth:`densify`.
ndarray[float64](1, 29) [[ 0.1 , 0.02, 0.1 ,...,-0.3 ,-0.05, 0.18]]
feature_names_in_ feature_names_in_: ndarray of shape (`n_features_in_`,)

Названия признаков, использованных при :term:`обучении`. Определяется только в том случае, если `X`
содержит названия признаков, представленные строками.

.. versionadded:: 1.0
ndarray[object](29,) ['V1','V2','V3',...,'V27','V28','Amount']
intercept_ intercept_: ndarray of shape (1,) or (n_classes,)

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

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

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

.. versionadded:: 0.24
int 29
n_iter_ n_iter_: ndarray of shape (1, )

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

.. versionchanged:: 0.20

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


Мы видим, что настроенный порог принятия решения значительно отличается от значения по умолчанию 0.5:

print(f"Tuned decision threshold: {tuned_model.best_threshold_:.2f}")
Tuned decision threshold: 0.03
print(
    "Benefit of logistic regression with a tuned threshold: "
    f"{business_scorer(tuned_model, data_test, target_test, amount=amount_test):,.2f}€"
)
Benefit of logistic regression with a tuned threshold: 249,433.39€

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

Ручная настройка порога принятия решений вместо его подбора

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

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

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

from sklearn.frozen import FrozenEstimator
from sklearn.model_selection import FixedThresholdClassifier

model_fixed_threshold = FixedThresholdClassifier(
    estimator=FrozenEstimator(model), threshold=tuned_model.best_threshold_
)
business_score = business_scorer(
    model_fixed_threshold, data_test, target_test, amount=amount_test
)
print(f"Benefit of logistic regression with a tuned threshold:  {business_score:,.2f}€")
Benefit of logistic regression with a tuned threshold:  249,433.39€

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

Наконец, оценка самого (среднего) бизнес-показателя может быть ненадежной, особенно если число точек данных в классе меньшинства очень мало. Любое влияние на бизнес, оцененное с помощью кросс-валидации бизнес-показателя на исторических данных (офлайн-оценка), в идеале следует подтвердить A/B-тестированием на актуальных данных (онлайн-оценка). Однако обратите внимание, что тестирование моделей методом A/B выходит за рамки самой библиотеки scikit-learn.

В завершение отключим флаг конфигурации маршрутизации метаданных:

.. GENERATED FROM PYTHON SOURCE LINES 693-694
sklearn.set_config(enable_metadata_routing=False)

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

Launch binder
Launch JupyterLite

Download Jupyter notebook: plot_cost_sensitive_learning.ipynb

Download Python source code: plot_cost_sensitive_learning.py

Download zipped: plot_cost_sensitive_learning.zip

Связанные примеры

Апостериорный подбор порогового значения функции принятия решений

Основные нововведения scikit-learn 1.5

Precision-Recall

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

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

Spec-Zone.ru

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