Spec-Zone.ru › scikit-learn

Примечание

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

Внутренняя перекрёстная валидация Target Encoder

TargetEncoder заменяет каждую категорию категориального признака на условное среднее значение целевой переменной для этой категории. Этот метод полезен в случаях, когда существует сильная связь между категориальным признаком и целевой переменной. Чтобы предотвратить переобучение, TargetEncoder.fit_transform использует внутренний механизм перекрёстной валидации для кодирования обучающих данных, которые будут использоваться последующей моделью. Этот механизм включает разделение данных на k фолдов и кодирование каждого фолда с использованием кодировок, полученных из других k-1 фолдов. В этом примере мы демонстрируем важность процедуры перекрёстной валидации для предотвращения переобучения.

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

Создание синтетических данных

Для этого примера мы создаём набор данных с тремя категориальными признаками:

  • информативный признак со средней кардинальностью («informative»)
  • неинформативный признак со средней кардинальностью («shuffled»)
  • неинформативный признак с высокой кардинальностью («near_unique»)

Сначала мы генерируем информативный признак:

import numpy as np

from sklearn.preprocessing import KBinsDiscretizer

n_samples = 50_000

rng = np.random.RandomState(42)
y = rng.randn(n_samples)
noise = 0.5 * rng.randn(n_samples)
n_categories = 100

kbins = KBinsDiscretizer(
    n_bins=n_categories,
    encode="ordinal",
    strategy="uniform",
    random_state=rng,
    subsample=None,
)
X_informative = kbins.fit_transform((y + noise).reshape(-1, 1))

# Remove the linear relationship between y and the bin index by permuting the
# values of X_informative:
permuted_categories = rng.permutation(n_categories)
X_informative = permuted_categories[X_informative.astype(np.int32)]

Неинформативный признак со средней кардинальностью генерируется путём перестановки информативного признака и удаления связи с целевой переменной:

X_shuffled = rng.permutation(X_informative)

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

X_near_unique_categories = rng.choice(
    int(0.9 * n_samples), size=n_samples, replace=True
).reshape(-1, 1)

Наконец, мы собираем набор данных и выполняем разделение на обучающую и тестовую выборки:

import pandas as pd

from sklearn.model_selection import train_test_split

X = pd.DataFrame(
    np.concatenate(
        [X_informative, X_shuffled, X_near_unique_categories],
        axis=1,
    ),
    columns=["informative", "shuffled", "near_unique"],
)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

Обучение регрессора Риджа

В этом разделе мы обучаем регрессор Риджа на наборе данных с кодированием и без него и исследуем влияние кодирования по целевой переменной с внутренним перекрёстным валидацией. Сначала мы видим, что модель Риджа, обученная на исходных признаках, будет иметь низкую производительность. Это связано с тем, что мы переставили порядок информативного признака, что означает, что X_informative неинформативен в исходном виде:

import sklearn
from sklearn.linear_model import Ridge

# Configure transformers to always output DataFrames
sklearn.set_config(transform_output="pandas")

ridge = Ridge(alpha=1e-6, solver="lsqr", fit_intercept=False)

raw_model = ridge.fit(X_train, y_train)
print("Raw Model score on training set: ", raw_model.score(X_train, y_train))
print("Raw Model score on test set: ", raw_model.score(X_test, y_test))
Raw Model score on training set:  0.0049896314219659565
Raw Model score on test set:  0.004577621581492997

Далее, мы создаём конвейер с кодировщиком по целевой переменной и моделью Риджа. Конвейер использует TargetEncoder.fit_transform, который использует перекрёстную валидацию. Мы видим, что модель хорошо подстраивается под данные и обобщается на тестовой выборке:

from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import TargetEncoder

model_with_cf = make_pipeline(TargetEncoder(random_state=0), ridge)
model_with_cf.fit(X_train, y_train)
print("Model with CF on train set: ", model_with_cf.score(X_train, y_train))
print("Model with CF on test set: ", model_with_cf.score(X_test, y_test))
Model with CF on train set:  0.8000184677460305
Model with CF on test set:  0.7927845601690917

Коэффициенты линейной модели показывают, что большая часть веса приходится на признак с индексом столбца 0, который является информативным признаком

import matplotlib.pyplot as plt
import pandas as pd

plt.rcParams["figure.constrained_layout.use"] = True

coefs_cf = pd.Series(
    model_with_cf[-1].coef_, index=model_with_cf[-1].feature_names_in_
).sort_values()
ax = coefs_cf.plot(kind="barh")
_ = ax.set(
    title="Target encoded with cross fitting",
    xlabel="Ridge coefficient",
    ylabel="Feature",
)
Target encoded with cross fitting

Хотя TargetEncoder.fit_transform использует внутренний механизм перекрёстной валидации для обучения кодирований для обучающей выборки, TargetEncoder.transform сам по себе этого не делает. Он использует всю обучающую выборку для обучения кодирований и преобразования категориальных признаков. Таким образом, мы можем использовать TargetEncoder.fit в сочетании с TargetEncoder.transform, чтобы отключить перекрёстную валидацию. Это кодирование затем передаётся модели Риджа.

target_encoder = TargetEncoder(random_state=0)
target_encoder.fit(X_train, y_train)
X_train_no_cf_encoding = target_encoder.transform(X_train)
X_test_no_cf_encoding = target_encoder.transform(X_test)

model_no_cf = ridge.fit(X_train_no_cf_encoding, y_train)

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

print(
    "Model without CF on training set: ",
    model_no_cf.score(X_train_no_cf_encoding, y_train),
)
print(
    "Model without CF on test set: ",
    model_no_cf.score(
        X_test_no_cf_encoding,
        y_test,
    ),
)
Model without CF on training set:  0.858486250088675
Model without CF on test set:  0.6338211367102258

Модель Риджа переобучается, потому что она присваивает гораздо больший вес неинформативным признакам с чрезвычайно высокой кардинальностью («near_unique») и средней кардинальностью («shuffled»), чем когда модель использовала перекрёстную валидацию для кодирования признаков.

coefs_no_cf = pd.Series(
    model_no_cf.coef_, index=model_no_cf.feature_names_in_
).sort_values()
ax = coefs_no_cf.plot(kind="barh")
_ = ax.set(
    title="Target encoded without cross fitting",
    xlabel="Ridge coefficient",
    ylabel="Feature",
)
Target encoded without cross fitting

Заключение

Этот пример демонстрирует важность внутренней TargetEncoder’s взаимной подгонки. Важно использовать TargetEncoder.fit_transform для кодирования данных обучения перед передачей их в модель машинного обучения. Когда TargetEncoder является частью Pipeline, а конвейер подгоняется, конвейер корректно вызовет TargetEncoder.fit_transform и использует взаимную подгонку при кодировании обучающих данных.

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

Launch binder
Launch JupyterLite

Download Jupyter notebook: plot_target_encoder_cross_val.ipynb

Download Python source code: plot_target_encoder_cross_val.py

Download zipped: plot_target_encoder_cross_val.zip

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

Сравнение Target Encoder с другими кодировщиками

HuberRegressor против Ridge на наборе данных с сильными выбросами

График коэффициентов Ridge в зависимости от регуляризации

Коэффициенты Ridge в зависимости от L2 регуляризации

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

Spec-Zone.ru

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