OneHotEncoder падает на новой категории: как подготовить табличную модель к инференсу
Табличная модель обучалась на заявках из сайта и почты. Через месяц появляется канал «партнёр». API получает корректную строку, но предсказание падает на преобразовании категории: по умолчанию OneHotEncoder считает незнакомое значение ошибкой. Менять модель наугад после первого такого запроса опасно: разные способы обработки нового значения несут разный смысл для прогноза.
Почему словарь категорий зафиксирован
При fit кодировщик создаёт выходные столбцы по значениям, встреченным в обучении. Для сайта и почты это два индикатора. На новом запросе добавить третий столбец нельзя: обученная модель ждёт прежнюю размерность и прежний порядок признаков. Поэтому нужно заранее определить, куда попадёт незнакомая категория. Это часть контракта модели, как и порядок входных полей; про второй риск есть отдельный разбор.
В OneHotEncoder вариант handle_unknown="ignore" даёт для неизвестного значения нули во всех столбцах данного поля. Вариант infrequent_if_exist отправляет его в специальную группу редких значений, но только если такая группа возникла при обучении. Посмотрим на оба исхода.
import numpy as np
from sklearn.preprocessing import OneHotEncoder
train = np.array([["сайт"], ["сайт"], ["почта"], ["сайт"]])
new = np.array([["партнёр"]])
ignore = OneHotEncoder(handle_unknown="ignore", sparse_output=False).fit(train)
rare = OneHotEncoder(handle_unknown="infrequent_if_exist",
min_frequency=2, sparse_output=False).fit(train)
print("ignore:", ignore.transform(new).tolist())
print("с редкой группой:", rare.transform(new).tolist())
print("поля:", rare.get_feature_names_out().tolist())
assert ignore.transform(new).sum() == 0
assert rare.transform(new).sum() == 1В примере ignore создаёт строку [[0.0, 0.0]]. Кодировщик с группой редких значений отдаёт один активный индикатор для нового партнёрского канала: почта встречалась один раз и сформировала эту группу. Если бы редких значений в обучении не оказалось, infrequent_if_exist обработал бы неизвестное значение как ignore. Проверки в коде фиксируют разницу.
Как выбрать политику для сервиса
Нули удобны, когда отсутствие известного индикатора действительно означает «прочий источник» и модель видела похожие ситуации. Но если применяется drop="first", нулевая комбинация может совпасть с базовой категорией, что усложнит трактовку. Группа редких значений даёт явное место для «прочих», если в обучении были редкие каналы и их поведение достаточно похоже на будущие новые. Никакая из этих настроек не узнает конверсию партнёрского канала до появления реальных меток.
Оцените выбранное правило на валидации, имитирующей новые значения: например, отложите один небольшой канал целиком и проверьте качество именно на нём. Не обучайте словарь на полном датасете до разделения. Иначе канал, которого в будущем модель знать не могла, окажется заранее известным кодировщику, а эксперимент перестанет проверять реальный сценарий. Если новые категории часто появляются со временем, разделите данные по датам и отслеживайте долю запросов, попавших в обработку неизвестного значения.
Кодировщик стоит хранить в одном Pipeline с моделью. Тогда обучение и API используют одинаковый словарь и одинаковые выходные столбцы. После переобучения сравните схемы признаков между версиями: изменение редких групп может изменить то, что означает каждый индикатор. Для действующего сервиса полезно логировать долю новых значений без персональных данных и заранее определить, когда она требует переобучения.
Для проверки контракта добавьте в набор входов строку с известной частой категорией, известной редкой категорией и совсем новым значением. Пропустите их через сохранённый кодировщик, а не через свежий экземпляр из ноутбука. Выведите get_feature_names_out() вместе с результатом: так видно, к какому индикатору привязано значение. Если категориальных полей несколько, проверьте каждое отдельно. Один общий тест «API вернул 200» не покажет, что новый канал заявок превратился в нулевой вектор.
На курсе «ML Engineer / Data Scientist: табличные модели в продакшн» вы проходите кодирование категориальных признаков, проверку валидации, обучение табличных моделей и сборку batch/REST-инференса. Это путь от выбора политики для новой категории до проверки её в рабочем запросе. Откройте программу курса.
Продолжить на практике
- ML Engineer / Data Scientist: табличные модели в продакшн ↗
Практический курс для тех, кто хочет получить навыки ML Engineer / Data Scientist на реальных табличных задачах. В курсе Вы не просто обучите CatBoost/LightGBM, а соберёте полноценный production-style пайплайн: подготовка данных, feature engineering (генерация признаков), корректная валидация, защита от leakage (утечек), тюнинг через Optuna, интерпретация через SHAP, batch-инференс и REST API для предсказаний.
