Какие проблемы возникают при join'ах фич с историей?
Answer from AI
sobes.tech AI
Что хотят услышать интервьюеры:
При join'ах фич с историей чаще всего возникают утечки таргета, ошибки во времени и дубли строк. Важно понимать, что данные для обучения должны соответствовать состоянию объекта на момент предсказания, а не после него. Также нужно уметь контролировать гранулярность, лаги и пропуски в истории.
Определение:
Join фич с историей — это объединение текущего состояния объекта с его прошлым поведением, событиями или агрегатами за предшествующий период. Основная сложность в том, что при неправильном соединении легко добавить в признаки информацию из будущего или исказить число наблюдений.
Типовые проблемы:
- leakage, когда в признаки попадает информация после момента прогноза;
- некорректное окно по времени, если history joining делается без учета timestamp;
- many-to-many join, который размножает строки;
- несоответствие гранулярности, например, дневные фичи присоединяют к событию на уровне транзакции;
- пропуски или неоднозначность при отсутствии данных на нужную дату.
Пример использования:
Например, нужно предсказать отток клиента на дату 2024-06-01. В признаки можно добавить число покупок за последние 30 дней, но нельзя использовать покупки, совершенные после 2024-06-01.
import pandas as pd
events = pd.DataFrame({
"user_id": [1, 1, 1, 2, 2],
"event_time": pd.to_datetime([
"2024-05-01", "2024-05-20", "2024-06-05",
"2024-05-10", "2024-06-03"
]),
"amount": [100, 50, 200, 80, 120]
})
snapshot = pd.DataFrame({
"user_id": [1, 2],
"snapshot_time": pd.to_datetime(["2024-06-01", "2024-06-01"])
})
# Корректно: берем только события строго до snapshot_time
joined = snapshot.merge(events, on="user_id", how="left")
joined = joined[joined["event_time"] < joined["snapshot_time"]]
features = (
joined.groupby("user_id", as_index=False)
.agg(purchases_30d=("amount", "sum"))
)
print(features)
Пояснение кода:
Код показывает безопасный паттерн: сначала задается момент среза (snapshot_time), затем из истории отбираются только события раньше этого момента. После этого строится агрегат по прошлым событиям, который можно использовать как фичу. Если убрать фильтр по времени, в признаки попадет покупка от 2024-06-05, хотя на момент 2024-06-01 ее еще не было.
Ключевые моменты:
- Всегда фиксировать time cutoff: фичи должны быть доступны на момент предсказания.
- Проверять, что join не создает дубли и не меняет число строк неожиданно.
- Следить за granularity: уровень агрегации истории должен совпадать с уровнем объекта.
- Использовать временные фильтры и лаги, а не просто join по ключу.
- Отдельно валидировать отсутствие leakage на train/validation split.
- Для event-based данных часто безопаснее сначала строить агрегаты по окнам, а потом присоединять их к snapshot-таблице.