История запросов
Описания формул, параметры и значения по умолчанию: справочник формул.
Рассчитаем признаки по истории запросов в БКИ: количество запросов за
окна 1, 7, 30, 90, 365, 730 и 1095 дней, распределения категорий и агрегаты поля sum.
Результат — таблица отобранных признаков с одной строкой на заявку.
В примере используется таблица истории запросов, связанная с заявками по
application_id. Сопоставьте названия колонок ниже с полями своей выгрузки.
Далее считаем, что данные уже загружены в pandas DataFrame.
Колонки исходной таблицы
| Колонка | Тип в источнике | Как использовать |
|---|---|---|
request_date |
Date32 |
Дата прошлого запроса другой организации в БКИ, отражённого в текущем отчёте. Используется для расчёта давности и временных окон. Точность — день. |
extra__cred_partner_type |
Int32 |
Код категории: передать в cat_features, чтобы не обрабатывать как числовую величину. Значения сверить со справочником источника. |
extra__request_owner |
Int32 |
Код категории: передать в cat_features. Значения сверить со справочником источника. |
report_date |
DateTime('UTC') |
Дата и время формирования выбранного отчёта; в этом примере — момент прогноза. |
type |
Int32 |
Код категории: передать в cat_features. |
code |
String |
Смысл и справочник кодов определяются источником; не трактовать как числовую величину. |
sum |
Float64 |
Числовое поле. Перед денежными агрегациями уточнить смысл, единицы измерения и обработку валют. |
currency |
String |
Категория валюты. Суммы разных валют нельзя складывать без согласованного преобразования. |
Момент расчёта — report_date, дата формирования выбранного отчёта БКИ.
Для этого примера считаем, что отчёт сразу доступен системе: разницей между
формированием и получением пренебрегаем. Это пример скоринга после получения
отчёта, а не обязательно в момент первоначального создания заявки.
1. Посмотрите исходные данные
Предположим, у вас уже загружены две таблицы:
applications: одна строка на заявку, колонкиapplication_idиtarget;requests: история запросов из выбранного отчёта, связанная с заявкой поapplication_id, с полями из таблицы выше.
Выведем первые строки:
Например, таблицы могут выглядеть так (значения приведены для иллюстрации):
applications:
requests:
application_id request_date report_date extra__cred_partner_type extra__request_owner type code sum currency
1001 2026-09-01 2026-09-20 12:00:00 3 0 1 2 15000.0 RUB
1001 2026-09-15 2026-09-20 12:00:00 1 0 1 3 50000.0 RUB
1002 2026-09-19 2026-09-20 12:00:00 3 1 1 2 10000.0 RUB
Для отбора признаков нужна историческая выборка с известным target
обоих классов. Несколько строк выше показывают только структуру таблиц.
2. Присоедините таргет к истории запросов
CAT_FEATURES = [
"extra__cred_partner_type", "extra__request_owner",
"type", "code", "currency",
]
prepared = requests.merge(
applications[["application_id", "target"]],
on="application_id", how="left", validate="many_to_one",
)
print(prepared.head().to_string(index=False))
В prepared у каждой строки запроса появится таргет соответствующей заявки.
Если он уже есть в requests, достаточно prepared = requests.copy().
Числовые коды из CAT_FEATURES будут обрабатываться как категории.
Пример рассчитан на подготовленные данные: обе даты имеют тип datetime
и согласованный часовой пояс, sum — числовой тип, суммы выражены в одной
валюте, а для каждого запроса найдена заявка с таргетом. Точность
request_date — день: порядок запросов внутри дня по ней определить нельзя.
3. Выберите один из двух вариантов запуска
Пакет должен быть установлен и активирован.
Оба варианта используют одну и ту же таблицу prepared из шага 2.
Выполняйте один вариант: запускать оба подряд для расчёта не требуется.
Вариант А: все формулы одной строкой
formulas="all" включает объединение наборов basic и advanced,
включая временные окна, квантили, тренды и взвешенные агрегаты.
from featminer import one_to_many_pipeline
features = one_to_many_pipeline(
df=prepared,
aggregation_key="application_id",
target_col="target",
cat_features=CAT_FEATURES,
event_times=("request_date",),
prediction_time="report_date",
cutoff_by="request_date",
formulas="all",
open_browser=False,
)
print(features.shape)
print(features.iloc[:5, :6].to_string())
Что означают параметры запуска
| Настройка | Что означает в этом примере |
|---|---|
aggregation_key="application_id" |
Ключ агрегации: строки истории объединяются в одну группу для каждой заявки, и признаки рассчитываются отдельно для неё. Это ключ заявки, а не клиента: у одного клиента может быть несколько заявок. |
target_col="target" |
Оценивать и отбирать признаки по бинарному таргету заявки. |
cat_features=CAT_FEATURES |
Категориальные колонки: extra__cred_partner_type, extra__request_owner, type, code, currency. Их значения используются как категории, даже если коды хранятся числами. |
event_times=("request_date",) |
Использовать даты запросов для временных формул. |
prediction_time="report_date" |
Отсчитывать давность и окна от даты формирования отчёта. |
cutoff_by="request_date" |
Исключить запросы с датой позже момента выбранного отчёта. |
formulas="all" |
Включить все формулы, в том числе все стандартные окна и квантили. |
Указать только даты недостаточно для включения всех временных формул.
Оконные формулы не входят в стандартный набор "basic", но входят в
"all". В варианте А полный набор выбран одной строкой; в варианте Б
ниже он раскрыт явным списком. И наоборот: если выбрать временную формулу, но
не задать необходимые даты, pipeline может пропустить её с предупреждением
и продолжить работу. Успешный запуск не означает, что были рассчитаны окна.
request_date — дата прошлого обращения другой организации в БКИ.
Такие обращения логируются в бюро и отражаются в истории запросов текущего
отчёта. report_date — дата формирования этого отчёта.
Поэтому временные окна считаются по request_date относительно report_date:
например, окно 30 дней охватывает запросы других организаций за последние
30 дней перед формированием отчёта. Параметр cutoff_by="request_date"
оставляет строки с request_date <= report_date. Для корректной истории
прошлых запросов это условие уже должно выполняться; здесь фильтр служит
дополнительной проверкой хронологии, а не определяет момент получения отчёта.
Вариант Б: тот же полный набор явно
Ниже раскрыт набор all версии 2026.10.6.1: 43 вида формул,
115 экземпляров с учётом параметров. Это не число итоговых признаков:
каждая формула может применяться к разным колонкам и категориям.
Каждый вид формулы перечислен отдельно. Удалите ненужную строку или
поменяйте параметры в четырёх списках. Строки с * добавляют отдельный
экземпляр формулы для каждого значения соответствующего списка.
from featminer import one_to_many_pipeline
from featminer.formulas import (
Fraction,
Count,
Max,
Sum,
Mean,
Min,
Nunique,
Std,
First,
Last,
NumMax,
NumMin,
Kurtosis,
Skew,
Mode,
EventRange,
FirstCategory,
LastCategory,
IntervalMax,
IntervalMean,
IntervalMin,
IntervalStd,
Trend,
TimeSinceFirstMaximum,
TimeSinceFirstMinimum,
TimeSinceLastMaximum,
TimeSinceLastMinimum,
SameHorizonDifferentColumnRatio,
SameColumnDifferentHorizonRatio,
Quantile,
Slope,
Ewa,
EwaFraction,
Ews,
EwsCount,
EwmaTrend,
WindowSum,
WindowCount,
WindowFraction,
WindowMean,
WindowMax,
WindowMin,
WindowStd,
)
WINDOW_DAYS = (1, 7, 30, 90, 365, 730, 1095)
QUANTILES = (0.01, 0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95, 0.99)
LAST_K = (0, 10, 100)
HALF_LIFE_DAYS = (1, 7, 30, 90, 365)
FORMULAS = (
# Агрегации, категории, временные характеристики и отношения.
Fraction(),
Count(),
Max(),
Sum(),
Mean(),
Min(),
Nunique(),
Std(),
First(),
Last(),
NumMax(),
NumMin(),
Kurtosis(),
Skew(),
Mode(),
EventRange(),
FirstCategory(),
LastCategory(),
IntervalMax(),
IntervalMean(),
IntervalMin(),
IntervalStd(),
Trend(),
TimeSinceFirstMaximum(),
TimeSinceFirstMinimum(),
TimeSinceLastMaximum(),
TimeSinceLastMinimum(),
SameHorizonDifferentColumnRatio(),
SameColumnDifferentHorizonRatio(),
# Квантили и тренды по последним событиям (0 — вся история).
*(Quantile(q=q) for q in QUANTILES),
*(Slope(last_k=k) for k in LAST_K),
# Экспоненциальное взвешивание: период полураспада в днях.
*(Ewa(half_life_days=d) for d in HALF_LIFE_DAYS),
*(EwaFraction(half_life_days=d) for d in HALF_LIFE_DAYS),
*(Ews(half_life_days=d) for d in HALF_LIFE_DAYS),
*(EwsCount(half_life_days=d) for d in HALF_LIFE_DAYS),
*(EwmaTrend(half_life_days=d) for d in HALF_LIFE_DAYS),
# Все виды оконных формул, каждое окно настраивается в WINDOW_DAYS.
*(WindowSum(days=d) for d in WINDOW_DAYS),
*(WindowCount(days=d) for d in WINDOW_DAYS),
*(WindowFraction(days=d) for d in WINDOW_DAYS),
*(WindowMean(days=d) for d in WINDOW_DAYS),
*(WindowMax(days=d) for d in WINDOW_DAYS),
*(WindowMin(days=d) for d in WINDOW_DAYS),
*(WindowStd(days=d) for d in WINDOW_DAYS),
)
features = one_to_many_pipeline(
df=prepared,
aggregation_key="application_id",
target_col="target",
cat_features=CAT_FEATURES,
event_times=("request_date",),
prediction_time="report_date",
cutoff_by="request_date",
formulas=FORMULAS,
open_browser=False,
)
print(features.shape)
print(features.iloc[:5, :6].to_string())
Например, оставьте WINDOW_DAYS = (7, 30, 90) для короткой истории,
QUANTILES = (0.25, 0.5, 0.75) для трёх квантилей или удалите строку
*(WindowStd(days=d) for d in WINDOW_DAYS), если эта формула не нужна.
LAST_K управляет числом последних событий для Slope, а
HALF_LIFE_DAYS — скоростью уменьшения веса старых событий.
После таких изменений явный набор уже будет отличаться от all.
При обновлении библиотеки состав all может расширяться. Явный список
остаётся тем, который вы указали в коде. Полный набор обычно требует
больше времени, чем базовый или выбранные вручную формулы.
Окна отсчитываются от report_date, а не от сегодняшнего дня и не от
последнего запроса. Временной расчёт имеет точность исходных дат.
На выходе остаются только признаки, прошедшие отбор по таргету. Включение всех окон не гарантирует, что признак для каждого окна останется: он может оказаться слабым, постоянным или дублировать другой. Конкретные названия и количество итоговых колонок зависят от выборки.
4. Верните признаки в таблицу заявок
result = applications.merge(
features.drop(columns="target").reset_index(),
on="application_id", how="left", validate="one_to_one",
)
print(result.iloc[:5, :8].to_string())
Левое соединение сохраняет заявки без строк истории, в том числе после временной фильтрации. Отсутствие отчёта и подтверждённое отсутствие запросов — разные ситуации: не заменяйте все пропуски нулями автоматически.
По умолчанию FeatMiner сохраняет HTML-отчёт и Python-код расчёта отобранных
признаков в featminer-report/. Этот код можно применять к новым данным без
повторного отбора по таргету, сохранив ту же подготовку отчётов, дат и валют.
Подробнее: временные параметры и API one_to_many_pipeline.