Temporal leakage в feature store - один из самых дорогих способов получить отличную offline-метрику и бесполезную модель в production. Проблема не в том, что фича плохая, а в том, что на train она знает больше, чем модель знала бы в момент принятия решения.
Предсказываем churn на датуt, а в фичах используемtransactions_last_30d, посчитанный после backfill’а из таблицы, куда транзакции доехали с задержкой или были пересчитаны с учетом будущих исправлений.
Offline все красиво. Online - просадка.
1. Point-in-time join - базовая защита
Для каждой строки обучения есть
prediction_time. Фичи должны быть взяты в том состоянии, в котором они были доступны на этот момент.Важно различать:
-
event_time - когда событие реально произошло;-
ingestion_time / created_at - когда оно попало в систему;-
available_at - когда фича стала доступна модели;-
prediction_time - момент прогноза.Правильный join должен учитывать не только
event_time <= prediction_time, но и available_at <= prediction_time:WITH ranked_features AS (
SELECT
l.entity_id,
l.prediction_time,
f.feature_value,
ROW_NUMBER() OVER (
PARTITION BY l.entity_id, l.prediction_time
ORDER BY f.event_time DESC
) AS rn
FROM labels l
JOIN features f
ON f.entity_id = l.entity_id
AND f.event_time <= l.prediction_time
AND f.available_at <= l.prediction_time
)
SELECT *
FROM ranked_features
WHERE rn = 1;
Если нет
available_at, вы часто не можете доказать, что leakage отсутствует.2. Backfill’ы - скрытый источник утечки
Backfill опасен тем, что создает иллюзию исторической полноты.
Например, сегодня вы пересчитали фичу за прошлый год:
- исправили старые события;
- добавили данные из нового источника;
- поменяли business logic;
- подтянули late-arriving events;
- использовали справочник, которого тогда еще не было.
В результате train получает историю, которой на самом деле не существовало в момент прогноза.
Корректный backfill должен отвечать на вопрос:
Какую фичу модель увидела бы тогда, если бы пайплайн работал с теми же задержками, источниками и правилами доступности?
Если ответ неизвестен, это не
historical truth, а reconstructed truth. Для обучения моделей это разные вещи.3. Проверка каузальности фичей
Перед обучением каждую фичу стоит прогнать через causality review.
Минимальный чеклист:
1. Фича доступна до
prediction_time?Не событие произошло, а именно значение фичи было доступно.
2. Нет ли в фиче label proxy?
Например,
days_since_last_payment_failed для задачи дефолта может быть почти прямым следствием будущего таргета.3. Окно агрегации строго в прошлом?
last_7d должно означать [t-7d, t), а не календарную неделю, которая включает будущее относительно t.4. Нет ли future-aware справочников?
Сегменты, статусы, лимиты, antifraud-флаги и CRM-атрибуты часто обновляются задним числом.
5. Учитывается ли latency источника?
Если данные приезжают через 6 часов, то для прогноза в 10:00 нельзя использовать событие в 09:55, даже если
event_time подходит.Вывод:
В production ML фича считается валидной не тогда, когда она исторически верна, а тогда, когда доказуемо доступна модели в момент принятия решения.
