Признаки и препроцессинг данных
Есть правило, которое интервьюеры любят повторять: признаки важнее модели. Одна сильная фича даёт больше, чем смена алгоритма и неделя тюнинга. Поэтому спрашивают про кодирование категорий, пропуски и агрегаты - и очень внимательно слушают, прозвучит ли слово «утечка».
Это тема, где теорию не спрячешь за библиотекой: ответы сразу выдают, готовил ли ты данные руками.
// Типовые формулировки: «как закодируешь категорию с десятью тысячами значений?», «что делать с пропусками?», «как считать агрегаты по истории пользователя?».
Категории: от простого способа к опасному
One-hot - самый честный вариант: на каждое значение категории заводим свой столбец с нулём или единицей. Пока значений десятки, лучше ничего не надо. Но представь категорию «город» с десятью тысячами значений - получится десять тысяч столбцов. Линейные модели это ещё переживут за счёт разреженных матриц, а деревьям станет совсем плохо.
Тогда берут target encoding: заменяют категорию средним значением целевой переменной по ней. Приём мощный и ровно настолько же опасный, потому что без защиты категория буквально узнаёт собственный ответ. Защит нужно две. Сглаживание к общему среднему - чтобы категория, встретившаяся дважды, не считалась знатоком. И расчёт out-of-fold - чтобы среднее для конкретной строки считалось без учёта её самой.
// Бустинги умеют это сами: CatBoost делает такое кодирование из коробки и следит за порядком, чтобы объект не подглядывал в свой ответ. Часто это проще и безопаснее, чем городить руками.
- кардинальность
- сколько разных значений у категории; от неё и зависит выбор способа кодирования
- target encoding
- заменить категорию средним таргета по ней; только со сглаживанием и out-of-fold
Пропуски и кривые распределения
Пропуск - чаще сигнал, чем дыра. Человек не указал доход не случайно, и сам факт умолчания может значить больше, чем значение. Поэтому рабочий приём такой: добавь отдельный признак «здесь было пусто», а само значение заполни медианой или константой. Деревья извлекают пользу из факта пропуска сами, линейным моделям нужна аккуратная подстановка.
Числовые признаки для линейных моделей просят внимания. Масштабирование обязательно, иначе признак в миллионах задавит признак в единицах. Логарифм выпрямляет тяжёлые хвосты - доходы, чеки, длительности. Разбиение на корзины и сплайны добавляют нелинейность там, где прямой не хватает. Деревьям всё это безразлично: им важен только порядок значений, а не сами значения.
// Удалять строки с пропусками - почти всегда проигрыш. Теряешь объём и вносишь перекос, если пропуски неслучайны. А они редко случайны.
История и агрегаты: окно смотрит только назад
Главный источник сигнала в табличных задачах - агрегаты по истории, а вовсе не исходные поля. Средний чек пользователя, число заказов за последние тридцать дней, сколько дней прошло с последнего визита. Именно они обычно и вытягивают качество.
И здесь железное правило, нарушение которого стоит дороже всего: агрегат считается по данным строго до момента предсказания. Окно смотрит назад и никогда вперёд.
Календарь разворачивают в циклические признаки через синус и косинус часа или дня недели - чтобы для модели «23:00» и «01:00» оказались соседями, а не крайностями шкалы. Лаги и скользящие средние переносят прошлые значения целевой переменной в признаки текущего момента.
// Агрегат «за всё время», посчитанный одним запросом по всей таблице, включает в себя и день предсказания. Это утечка будущего - самая тихая и самая частая из всех.
- лаг-признак
- значение из прошлого (вчера, неделю назад), приделанное к текущему моменту
Как отвечать: «Как закодируешь категориальную фичу с 10 000 значений?»
One-hot на такой кардинальности взорвёт размерность, поэтому беру target encoding: заменяю категорию средним таргета, сглаживаю к общему среднему, чтобы редкие значения не переоценивались, и считаю всё out-of-fold - иначе категория узнает собственный ответ, и метрика на валидации будет просто враньём. Совсем редкие значения слил бы в отдельную группу «прочее». А если модель CatBoost, отдам категорию как есть: он делает ровно это из коробки и аккуратнее, чем я руками.
Названы обе защиты, а не только сам приём. Именно на пропущенном out-of-fold собеседование по этой теме обычно и заканчивается.
На чём валят
- −Target encoding без out-of-fold - самая частая утечка на собесе: категория знает собственный таргет.
- −One-hot на тысячах значений: взрыв размерности, и особенно тяжело деревьям.
- −Агрегат «за всё время», включающий день предсказания: утечка будущего прямо в признак.
- −Удалять строки с пропусками вместо подстановки: минус объём данных и перекос, если пропуски неслучайны.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 15, остальные разбираются в тренажёре.
- В признаке «доход» 30% пропусков. Чем плоха бездумная замена всех пропусков нулём?A)Ноль — осмысленное значение дохода: модель перепутает «неизвестно» и «нет дохода», а статистики признака исказятсяB)Модель с нулями обучится, но заметно медленнееC)Ничем: деревья и бустинг нечувствительны к способу заполнения — сплиты сами отделят нули от настоящих значений доходаD)Заполнять пропуски запрещено — такие строки удаляют
показать ответ и разбор
+A)Ноль — осмысленное значение дохода: модель перепутает «неизвестно» и «нет дохода», а статистики признака исказятся// разбор: Замена должна отличать «значения нет» от «значение равно нулю». Треть выборки с нулевым доходом сдвигает среднее, ломает линейные зависимости и создаёт ложный кластер. Практика: медиана/мода + бинарный индикатор пропуска; для деревьев индикатор часто ценнее самой замены — пропуск бывает информативен.
- Для линейной модели категорию «город» закодировали числами: Москва = 1, Питер = 2, Казань = 3. В чём проблема?A)Линейные модели не принимают целочисленные признакиB)Label encoding создаёт слишком много колонокC)Проблемы нет: кодировка компактнее one-hot, а ложный порядок городов модель всё равно проигнорируетD)Модель выучит ложный порядок и «расстояния» между городами — нужен one-hot или таргет-кодировка
показать ответ и разбор
+D)Модель выучит ложный порядок и «расстояния» между городами — нужен one-hot или таргет-кодировка// разбор: Число навязывает порядок и метрику: для линейной модели «Казань = 3» означает «втрое больше Москвы» по этой оси — бессмыслица для номинальной категории. One-hot делает категории независимыми; при высокой кардинальности — target encoding со сглаживанием. Деревьям label encoding вредит меньше: они режут порогами, хотя и им проще с осмысленной кодировкой.
- Зачем логарифмируют сильно скошенные признаки (доход, цены, площади) перед линейной моделью?A)Логарифм убирает пропуски и выбросыB)Сжимает тяжёлый хвост: зависимость становится ближе к линейной, а экстремальные значения меньше тянут решениеC)Логарифм обязателен для сходимости градиентного спускаD)Чтобы распределение признака стало строго нормальным: без этого оценки МНК теряют состоятельность и доверять им не получится
показать ответ и разбор
+B)Сжимает тяжёлый хвост: зависимость становится ближе к линейной, а экстремальные значения меньше тянут решение// разбор: Для лог-нормальных величин типа дохода эффект обычно мультипликативный: «+10%», а не «+10 000 ₽». Логарифм превращает умножение в сложение — линейная модель начинает описывать реальность, выбросы прижимаются. МНК нормальности признаков не требует (предположения — про остатки), а нули лечат через log1p.
- Час события (0–23) подали в линейную модель как обычное число. Чем это плохо и как правильно?A)Ничем: час — обычное число, модель разберётсяB)Корректный способ — one-hot на 24 бинарные колонки, чтобы каждый час был независимC)23:00 и 00:00 окажутся «максимально далеко» друг от друга; цикличность кодируют парой sin/cosD)Часы надо перевести в минуты — растёт точность признака
показать ответ и разбор
+C)23:00 и 00:00 окажутся «максимально далеко» друг от друга; цикличность кодируют парой sin/cos// разбор: Время циклично: полночь соседствует с 23:00, а по числовой оси между ними 23 «часа» расстояния. Пара sin(2πh/24), cos(2πh/24) кладёт часы на окружность — соседние часы близки, линейная модель ловит плавные суточные паттерны. One-hot тоже рабочий (но 24 колонки и нет непрерывности), деревьям же часто хватает сырого часа — они режут диапазоны порогами.
- В признаке есть экстремальные выбросы. Какой скейлер устойчивее и почему?A)StandardScaler: среднее и стандартное отклонение устойчивы к выбросамB)MinMaxScaler: выбросы аккуратно сожмутся в границы [0, 1]C)Никакой: выбросы удаляют до масштабированияD)RobustScaler по медиане и IQR: квантили почти не двигаются от экстремальных значений
показать ответ и разбор
+D)RobustScaler по медиане и IQR: квантили почти не двигаются от экстремальных значений// разбор: Среднее и std сами утекают за выбросами, а в MinMax один выброс задаёт границу диапазона — и вся остальная масса сжимается в узкую полоску. Медиана и межквартильный размах меняются от пары экстремумов пренебрежимо — поэтому RobustScaler. Альтернативы: winsorization (обрезка хвостов по квантилям) или лог-преобразование.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.