Примечание
Перейдите в конец, чтобы скачать полный код примера или запустить этот пример в браузере с помощью JupyterLite или Binder.
Сравнение Target Encoder с другими кодировщиками
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()
В этом примере мы используем следующий поднабор числовых и категориальных признаков из набора данных. Целевая переменная принимает непрерывные значения от 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()

Обучение и оценка конвейеров с разными кодировщиками
В этом разделе мы оценим конвейеры с 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
Наконец, оцениваем конвейер с помощью перекрёстной проверки и записываем результаты:
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,
)

При оценке прогностической эффективности на тестовой выборке удаление категорий даёт наихудший результат, а кодирование целевой переменной — наилучший. Это можно объяснить следующим образом:
- Удаление категориальных признаков снижает выразительность конвейера и, как следствие, приводит к недообучению;
- Из-за высокой кардинальности и необходимости сократить время обучения при схеме one-hot-кодирования используется
max_categories=20, что не позволяет признакам чрезмерно разрастаться и может привести к недообучению. - Если бы мы не задали
max_categories=20, схема one-hot-кодирования, скорее всего, привела бы к переобучению конвейера: число признаков резко увеличилось бы из-за редких категорий, которые случайно коррелируют с целевой переменной (только в обучающей выборке); - Порядковое кодирование задаёт произвольный порядок признаков, которые затем обрабатываются как числовые значения моделью
HistGradientBoostingRegressor. Поскольку эта модель группирует числовые признаки в 256 интервалов для каждого признака, многие несвязанные категории могут оказаться в одной группе, что в результате может привести к недообучению всего конвейера; - При использовании кодировщика целевой переменной происходит такое же разбиение на интервалы, но поскольку закодированные значения упорядочены статистически по маргинальной связи с целевой переменной, разбиение на интервалы, используемое моделью
HistGradientBoostingRegressor, оказывается осмысленным и даёт хорошие результаты: сочетание сглаженного кодирования целевой переменной и разбиения на интервалы хорошо регуляризует модель против переобучения, не слишком ограничивая выразительность конвейера.
Общее время выполнения скрипта: (0 минут 23.825 секунды)
Связанные примеры
© 2007–2026 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.9/auto_examples/preprocessing/plot_target_encoder.html