Ответ
Плюсы:
- Сохранение связи с целью: Кодирует категориальный признак числовым значением, напрямую отражающим среднее значение целевой переменной для каждой категории. Это мощный сигнал для моделей.
- Эффективность при многих категориях: Не увеличивает размерность данных, в отличие от One-Hot Encoding, что критично для признаков с сотнями уникальных значений.
- Хорошая совместимость: Особенно эффективен для алгоритмов на основе деревьев (например, Gradient Boosting).
Минусы:
- Риск утечки данных (переобучение): Если кодировать на всей выборке, информация о целевой переменной из обучающих данных «просачивается» в признаки. Это нужно предотвращать с помощью кодирования внутри цикла кросс-валидации.
- Проблема редких категорий: Для категорий с малым числом примеров оценка среднего будет зашумленной. Решается сглаживанием (smoothing), которое смешивает среднее по категории с глобальным средним.
- Обработка новых данных: Для категорий, не встреченных при обучении (OOV), требуется стратегия замены, например, на глобальное среднее.
Пример с использованием кросс-валидации и сглаживания:
import pandas as pd
from sklearn.model_selection import KFold
from category_encoders import TargetEncoder
# Имитация данных
df = pd.DataFrame({'city': ['A', 'B', 'A', 'C', 'B', 'C'], 'target': [10, 20, 12, 5, 22, 3]})
# Важно: кодируем внутри цикла CV для избежания утечки
df['city_encoded'] = 0
kf = KFold(n_splits=5, shuffle=True, random_state=42)
for train_idx, val_idx in kf.split(df):
encoder = TargetEncoder(smoothing=2.0)
df.loc[val_idx, 'city_encoded'] = encoder.fit_transform(
df.loc[val_idx, 'city'],
df.loc[train_idx, 'target']
)
print(df) Ответ 18+ 🔞
А, ну вот, опять про эти ваши кодировки категориальных признаков. Слушай, Target Encoding — это вообще, блядь, хитрая жопа. С одной стороны, гениально просто, а с другой — можно так накосячить, что потом будешь сам от себя охуевать.
Что в нём хорошего, ёпта:
- Смысл есть, а не просто цифры: Он не тупо превращает «Москву» в 1, а «Питер» в 2. Он смотрит, какое в среднем значение целевой переменной (ну, там цена квартиры, вероятность клика — неважно) у каждой категории. И присваивает именно это число. Модель сразу видит: «Ага, "город А" в среднем даёт 100к, а "город Б" — 50к». Сигнал мощный, прямой. Мозги модели не ломает.
- Не раздувает таблицу до овердохуища: У тебя город — 200 уникальных значений. One-Hot сделает 200 новых столбцов. А тут — один столбец, всё аккуратненько. Для алгоритмов вроде бустинга — просто песня.
- Деревья его обожают: Градиентный бустинг на таком коде просто пускает слюни, ему так проще паттерны вылавливать.
А теперь про подводные ебучки, которые всех и губят:
- Утечка данных, ёбаный в рот! Это главная беда. Если ты закодируешь признак по всей обучающей выборке, а потом на этих же данных будешь валидироваться — это пиздец, читерство. Ты информацию из таргета (которая в будущем неизвестна) уже засунул в фичи. Модель будет охуенно на трейне и хуёво в реальности. Поэтому кодировать надо строго внутри кросс-валидации, на фолдах, чтобы для валидационной части данные кодировались только на основе трейна. Иначе будет вам хиросима и никаких сраков.
- Редкие категории — манда с ушами. Допустим, у тебя есть город «Мухосранск», который встретился всего 3 раза, и все три раза таргет был высокий. Среднее получится большое, но оценка — хуйня, случайная. На новых данных такой Мухосранск может дать что угодно. Тут нужно сглаживание (smoothing): смешиваем среднее по категории с глобальным средним по всем данным. Чем меньше примеров в категории — тем больше веса у глобального среднего. Без этого — переобучишься на ровном месте.
- А если пришло что-то новое? Обучил ты модель, закодировал города A, B, C. А в продакшн приехала запись с городом «D», которого ты никогда не видел. Что делать? Обычно заменяют на глобальное среднее (то самое, которое в сглаживании использовалось). Надо эту логику предусмотреть, а то модель встанет колом.
Вот, смотри, как это правильно делать, чтобы не обосраться:
import pandas as pd
from sklearn.model_selection import KFold
from category_encoders import TargetEncoder
# Допустим, у нас такие данные, бля
df = pd.DataFrame({'city': ['A', 'B', 'A', 'C', 'B', 'C'], 'target': [10, 20, 12, 5, 22, 3]})
# ВАЖНО: делаем колонку для закодированных значений
df['city_encoded'] = 0
# Делим на фолды, как полагается
kf = KFold(n_splits=5, shuffle=True, random_state=42)
for train_idx, val_idx in kf.split(df):
# Создаём энкодер СО СГЛАЖИВАНИЕМ, чтобы редкие категории не ебали мозг
encoder = TargetEncoder(smoothing=2.0)
# Кодируем ВАЛИДАЦИОННУЮ часть на основе ТРЕЙНА. Это ключевой момент, ёпта!
df.loc[val_idx, 'city_encoded'] = encoder.fit_transform(
df.loc[val_idx, 'city'], # Что кодируем (валидация)
df.loc[train_idx, 'target'] # На основе чего (только трейн!)
)
print(df)
Вот так, блядь. Инструмент — огонь, но доверия к нему — ебать ноль, если не понимаешь, где тут подвох. Сделал всё по уму — получил прирост. Накосячил с утечкой — будешь потом неделю дебажить, почему на лидерборде хуйня, а не скор. Волнение ебать.