Перейти к содержанию

История запросов

Описания формул, параметры и значения по умолчанию: справочник формул.

Рассчитаем признаки по истории запросов в БКИ: количество запросов за окна 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, с полями из таблицы выше.

Выведем первые строки:

print(applications.head().to_string(index=False))
print(requests.head().to_string(index=False))

Например, таблицы могут выглядеть так (значения приведены для иллюстрации):

applications:

 application_id  target
           1001       0
           1002       1
           1003       0

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.