Spec-Zone.ru › scikit-learn

Примечание

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

Сравнение кодировщика целевых значений с другими кодировщиками

Кодировщик целевых значений TargetEncoder использует значение целевой переменной для кодирования каждого категориального признака. В этом примере мы сравним три различных подхода к обработке категориальных признаков: TargetEncoder, OrdinalEncoder, OneHotEncoder и удаление категории.

Примечание

fit(X, y).transform(X) не равно fit_transform(X, y), поскольку в fit_transform для кодирования используется схема кросс-валидации. Подробности см. в Руководстве пользователя.

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

Загрузка данных из OpenML

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

from sklearn.datasets import fetch_openml

wine_reviews = fetch_openml(data_id=42074, as_frame=True)

df = wine_reviews.frame
df.head()
country description designation points price province region_1 region_2 variety winery
0 US Этот потрясающий виноград, 100% сортовой, родом из... Martha's Vineyard 96 235.0 California Napa Valley Napa Cabernet Sauvignon Heitz
1 Spain Сочные ароматы инжира, ежевики и черной смородины... Carodorum Selección Especial Reserva 96 110.0 Northern Spain Toro NaN Tinta de Toro Bodega Carmen Rodríguez
2 US Мак Уотсон чтит память вина, когда-то... Special Selected Late Harvest 96 90.0 California Knights Valley Sonoma Sauvignon Blanc Macauley
3 US Это вино простояло 20 месяцев в 30% новых французских бочках, ... Reserve 96 65.0 Oregon Willamette Valley Willamette Valley Pinot Noir Ponzi
4 France Это лучшее вино из La Bégude, названное в честь... La Brûlade 95 66.0 Provence Bandol NaN Provence red blend Domaine de la Bégude


В этом примере мы используем следующие подмножества числовых и категориальных признаков в данных. Целевые значения — это непрерывные значения от 80 до 100:

numerical_features = ["price"]
categorical_features = [
    "country",
    "province",
    "region_1",
    "region_2",
    "variety",
    "winery",
]
target_name = "points"

X = df[numerical_features + categorical_features]
y = df[target_name]

_ = y.hist()
plot target encoder

Обучение и оценка конвейеров с различными кодировщиками

В этом разделе мы оценим конвейеры с использованием HistGradientBoostingRegressor с различными стратегиями кодирования. Сначала мы перечислим используемые кодировщики для предварительной обработки категориальных признаков:

from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, OrdinalEncoder, TargetEncoder

categorical_preprocessors = [
    ("drop", "drop"),
    ("ordinal", OrdinalEncoder(handle_unknown="use_encoded_value", unknown_value=-1)),
    (
        "one_hot",
        OneHotEncoder(handle_unknown="ignore", max_categories=20, sparse_output=False),
    ),
    ("target", TargetEncoder(target_type="continuous")),
]

Далее мы оценим модели с помощью кросс-валидации и запишем результаты:

from sklearn.ensemble import HistGradientBoostingRegressor
from sklearn.model_selection import cross_validate
from sklearn.pipeline import make_pipeline

n_cv_folds = 3
max_iter = 20
results = []


def evaluate_model_and_store(name, pipe):
    result = cross_validate(
        pipe,
        X,
        y,
        scoring="neg_root_mean_squared_error",
        cv=n_cv_folds,
        return_train_score=True,
    )
    rmse_test_score = -result["test_score"]
    rmse_train_score = -result["train_score"]
    results.append(
        {
            "preprocessor": name,
            "rmse_test_mean": rmse_test_score.mean(),
            "rmse_test_std": rmse_train_score.std(),
            "rmse_train_mean": rmse_train_score.mean(),
            "rmse_train_std": rmse_train_score.std(),
        }
    )


for name, categorical_preprocessor in categorical_preprocessors:
    preprocessor = ColumnTransformer(
        [
            ("numerical", "passthrough", numerical_features),
            ("categorical", categorical_preprocessor, categorical_features),
        ]
    )
    pipe = make_pipeline(
        preprocessor, HistGradientBoostingRegressor(random_state=0, max_iter=max_iter)
    )
    evaluate_model_and_store(name, pipe)

Поддержка категориальных признаков в исходном формате

В этом разделе мы создаем и оцениваем конвейер, который использует поддержку категориальных признаков в исходном формате в HistGradientBoostingRegressor, который поддерживает до 255 уникальных категорий. В нашем наборе данных большинство категориальных признаков имеют более 255 уникальных категорий:

n_unique_categories = df[categorical_features].nunique().sort_values(ascending=False)
n_unique_categories
winery      14810
region_1     1236
variety       632
province      455
country        48
region_2       18
dtype: int64

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

high_cardinality_features = n_unique_categories[n_unique_categories > 255].index
low_cardinality_features = n_unique_categories[n_unique_categories <= 255].index
mixed_encoded_preprocessor = ColumnTransformer(
    [
        ("numerical", "passthrough", numerical_features),
        (
            "high_cardinality",
            TargetEncoder(target_type="continuous"),
            high_cardinality_features,
        ),
        (
            "low_cardinality",
            OrdinalEncoder(handle_unknown="use_encoded_value", unknown_value=-1),
            low_cardinality_features,
        ),
    ],
    verbose_feature_names_out=False,
)

# The output of the of the preprocessor must be set to pandas so the
# gradient boosting model can detect the low cardinality features.
mixed_encoded_preprocessor.set_output(transform="pandas")
mixed_pipe = make_pipeline(
    mixed_encoded_preprocessor,
    HistGradientBoostingRegressor(
        random_state=0, max_iter=max_iter, categorical_features=low_cardinality_features
    ),
)
mixed_pipe
Pipeline(steps=[('columntransformer',
                 ColumnTransformer(transformers=[('numerical', 'passthrough',
                                                  ['price']),
                                                 ('high_cardinality',
                                                  TargetEncoder(target_type='continuous'),
                                                  Index(['winery', 'region_1', 'variety', 'province'], dtype='object')),
                                                 ('low_cardinality',
                                                  OrdinalEncoder(handle_unknown='use_encoded_value',
                                                                 unknown_value=-1),
                                                  Index(['country', 'region_2'], dtype='object'))],
                                   verbose_feature_names_out=False)),
                ('histgradientboostingregressor',
                 HistGradientBoostingRegressor(categorical_features=Index(['country', 'region_2'], dtype='object'),
                                               max_iter=20, random_state=0))])
В среде Jupyter, пожалуйста, перезапустите эту ячейку, чтобы отобразить HTML-представление, или доверьтесь блокноту.
На GitHub HTML-представление не может быть отображено, попробуйте загрузить эту страницу с nbviewer.org.
Pipeline(steps=[('columntransformer',
                 ColumnTransformer(transformers=[('numerical', 'passthrough',
                                                  ['price']),
                                                 ('high_cardinality',
                                                  TargetEncoder(target_type='continuous'),
                                                  Index(['winery', 'region_1', 'variety', 'province'], dtype='object')),
                                                 ('low_cardinality',
                                                  OrdinalEncoder(handle_unknown='use_encoded_value',
                                                                 unknown_value=-1),
                                                  Index(['country', 'region_2'], dtype='object'))],
                                   verbose_feature_names_out=False)),
                ('histgradientboostingregressor',
                 HistGradientBoostingRegressor(categorical_features=Index(['country', 'region_2'], dtype='object'),
                                               max_iter=20, random_state=0))])
ColumnTransformer(transformers=[('numerical', 'passthrough', ['price']),
                                ('high_cardinality',
                                 TargetEncoder(target_type='continuous'),
                                 Index(['winery', 'region_1', 'variety', 'province'], dtype='object')),
                                ('low_cardinality',
                                 OrdinalEncoder(handle_unknown='use_encoded_value',
                                                unknown_value=-1),
                                 Index(['country', 'region_2'], dtype='object'))],
                  verbose_feature_names_out=False)
['price']
passthrough
Index(['winery', 'region_1', 'variety', 'province'], dtype='object')
TargetEncoder(target_type='continuous')
Index(['country', 'region_2'], dtype='object')
OrdinalEncoder(handle_unknown='use_encoded_value', unknown_value=-1)
HistGradientBoostingRegressor(categorical_features=Index(['country', 'region_2'], dtype='object'),
                              max_iter=20, random_state=0)


Наконец, мы оцениваем конвейер с помощью кросс-валидации и записываем результаты:

evaluate_model_and_store("mixed_target", mixed_pipe)

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

В этом разделе мы отображаем результаты, строя графики тестовых и обучающих оценок:

import matplotlib.pyplot as plt
import pandas as pd

results_df = (
    pd.DataFrame(results).set_index("preprocessor").sort_values("rmse_test_mean")
)

fig, (ax1, ax2) = plt.subplots(
    1, 2, figsize=(12, 8), sharey=True, constrained_layout=True
)
xticks = range(len(results_df))
name_to_color = dict(
    zip((r["preprocessor"] for r in results), ["C0", "C1", "C2", "C3", "C4"])
)

for subset, ax in zip(["test", "train"], [ax1, ax2]):
    mean, std = f"rmse_{subset}_mean", f"rmse_{subset}_std"
    data = results_df[[mean, std]].sort_values(mean)
    ax.bar(
        x=xticks,
        height=data[mean],
        yerr=data[std],
        width=0.9,
        color=[name_to_color[name] for name in data.index],
    )
    ax.set(
        title=f"RMSE ({subset.title()})",
        xlabel="Encoding Scheme",
        xticks=xticks,
        xticklabels=data.index,
    )
RMSE (Test), RMSE (Train)

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

  • Отбрасывание категориальных признаков делает конвейер менее выразительным и, как следствие, приводит к недообучению;
  • Из-за высокой кардинальности и для сокращения времени обучения схема кодирования «один-из-n» использует max_categories=20, что предотвращает чрезмерное расширение признаков, что может привести к недообучению.
  • Если бы мы не установили max_categories=20, схема кодирования «один-из-n» могла бы привести к переобучению, поскольку количество признаков взрывается при появлении редких категорий, случайно коррелирующих с целевой переменной (только на обучающем наборе);
  • Порядковое кодирование навязывает произвольный порядок признакам, которые затем обрабатываются как числовые значения HistGradientBoostingRegressor. Поскольку эта модель группирует числовые признаки в 256 бинов на признак, многие не связанные категории могут быть сгруппированы вместе, и в результате общий конвейер может недообучиться;
  • При использовании кодировщика целевых переменных происходит та же группировка по бинам, но поскольку закодированные значения статистически упорядочены по маргинальной ассоциации с целевой переменной, группировка по бинам, используемая HistGradientBoostingRegressor, имеет смысл и приводит к хорошим результатам: сочетание сглаженного кодирования целевых переменных и группировки по бинам работает как хорошая стратегия регуляризации против переобучения, не слишком ограничивая выразительность конвейера.

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

Launch binder
Launch JupyterLite

Download Jupyter notebook: plot_target_encoder.ipynb

Download Python source code: plot_target_encoder.py

Download zipped: plot_target_encoder.zip

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

Поддержка категориальных признаков в градиентном бустинге

Внутренняя кросс-валидация кодировщика целевых переменных

ColumnTransformer с разнородными типами данных

Основные моменты выпуска scikit-learn 1.4

© 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.html

Spec-Zone.ru

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