- BrainTools - https://www.braintools.ru -

Волков бояться — uplift в прод не катить, или AUF 2.0

Всем привет! Меня зовут Мельников Виктор, я middle data scientist в Альфа-Банке в Управлении по разработке инструментов автоматизации моделирования.

Год назад вышла статья о первой open source библиотеке Альфа-Банка [1] для автоматического построения uplift-моделей Automatic Uplift Framework или же, сокращённо, AUF🐺. В ней мы рассмотрели основной функционал библиотеки с примерами кода. Также в ней можно найти ссылку на ноутбук с примером кода на открытом датасете.

Прошел год, пришла пора рассказать о новшествах, а также о результатах применения библиотеки в Альфа-Банке. Также в конце будет ссылка на обновленный пример кода, с которым ты сможешь сразу начать строить uplift-модели быстро и качественно! Достаточно создать окружение с Python 3.8 и выполнить в нем команду pip install auf. Также доступен исходный код библиотеки на GitHub [2].

Небольшой дисклеймер: как и первая, эта статья также рассказывает именно про библиотеку AUF, а не uplift-моделирование. Ссылки на материалы по uplift-моделированию есть в конце первой статьи [1].

В статье начнём с разбора того, как AutoML помогает превратить сложный поиск инкрементального эффекта в эффективный промышленный процесс. Вспомним основы uplift-моделирования и на практических кейсах покажем, как автоматизация ускорила разработку, позволила внедрить автопереобучение в продакшн и успешно реализовать поддержку мультитритмента. Вы узнаете, в каких сценариях AUF приносит максимум пользы, с какими ограничениями можно столкнуться и как использовать библиотеку для решения задач вашего бизнеса.

Кроме прикладных кейсов, заглянем «под капот» архитектурных обновлений: от рефакторинга оптимизатора до продвинутой аналитики в стиле профи, разберём новые режимы обучения [3], кастомизацию и инструменты глубокого анализа моделей, такие как оценка чувствительности сегментов и сравнение с моделями склонности. В завершение поделимся результатами масштабного рефакторинга кода, который сделал систему стабильнее, и расскажем, как наше видение «умных и свободных» моделей воплощается в жизнь прямо сейчас.

Напомним контекст

Что такое uplift-моделирование?

Допустим, нужно запустить маркетинговую компанию и предложить клиентам новый продукт. В случае банка это может быть, например, кредитная карта с кэшбэком или семейный счет. Можно показать рекламу всей базе, но это дорого, и так мы затронем много клиентов, которым она совсем не интересна, — тем самым рискуя лояльностью. Можно показать рекламу не всем, а случайной группе клиентов, но так мы всё равно прокоммуницируем с большим количеством нецелевых клиентов.

Умный маркетинг работает иначе: нужно найти именно тех клиентов, которые возьмут кредитную карту, только если им её предложить. Нам не интересны те, кто возьмёт карту и без наших усилий или не возьмёт её ни при каких условиях. Именно тут и поможет uplift-моделирование — оно оценивает эффект воздействия на конкретного клиента.

Такие задачи встречаются везде: в ритейле (нужна ли скидка этому покупателю?), в телекоме (позвонить или хватит push?), в медицине (поможет ли этому пациенту данный препарат?). Если хочется разобраться в математике [4] и методах глубже — ссылки на хорошие материалы есть в конце первой статьи (ссылка).

Зачем нам AutoML?

Допустим, ты уже знаешь, что такое uplift, и хочешь построить модель. Ты идёшь в Google, находишь библиотеки (например, scikit-uplift, causalml, EconML) и понимаешь, что это строительные блоки, из которых ещё нужно что-то собрать. Потом отбор признаков, потом подбор гиперпараметров через Optuna, потом визуализация результатов для бизнеса… В итоге одна модель — это 1–2 недели работы. А если бизнес попросит проверить новую гипотезу? Ещё две недели.

Именно отсюда выросла идея AUF — Automatic Uplift Framework. Это open source библиотека Альфа-Банка, которая берёт на себя всю рутину: загрузи выборку, запусти pipeline.run() — и через несколько часов получи готовую модель с полным отчётом о качестве, понятным как DS, так и бизнесу. Ускорение — в 5–10 раз! Вместо двух недель работа займет всего один рабочий день.

Год назад мы рассказали о первой версии AUF: как устроен пайплайн, какие модели поддерживаются и как запустить всё на одном из открытых датасетов для uplift-моделирования. С тех пор библиотека выросла: появился мультитритмент, поверх AUF было настроено автопереобучение в прод инфраструктуре Банка, а также много других полезных вещей, о которых поговорим дальше.

Главные итоги AUF за год

Волков бояться — uplift в прод не катить, или AUF 2.0 - 1

Ускорение разработки

AUF изначально создавался как внутренняя библиотека для ускорения тестирования новых гипотез и разработки классических аплифт моделей «по кнопке». В среднем за счёт экономии времени на написание кода отбора признаков, обучения моделей и выбора лучшей, а также логирования результатов лучшей модели, разработка ускоряется в 5-10 раз с 5-7 рабочих дней до 4-8 рабочих часов. Важно понимать, что обучение моделей через AUF занимает некоторое время, которое можно использовать под другие задачи, поэтому рост эффективности на самом деле ещё больше.

Волков бояться — uplift в прод не катить, или AUF 2.0 - 2

Внедрение моделей

На данный момент AUF позволил обучить и вывести в промышленное использование уже 4 модели, при этом более 10 моделей находятся в стадии пилота. Все эти модели помогают избежать спама клиентов, сделать персонализированный прайсинг и привлекать новых клиентов, повышая эффективность не только маркетинга, но и всего бизнеса в целом. Примечательно то, что одна из 4 production моделей выведена в особом режиме автопереобучения, о котором сейчас и пойдет речь.

Работа с деградацией моделей в проде

Основная сложность на практике состоит в том, что данные часто меняют своё распределение под влиянием различных факторов. Например, из-за изменения ключевой ставки или в силу сезонности. В таких случаях нужно заново обучить модель на свежих данных, даже если сам таргет не поменялся. Обычно для этого разработчику модели нужно самому заново собрать данные, обучить модель, проверить её качество и вывести в промышленную среду.

Волков бояться — uplift в прод не катить, или AUF 2.0 - 3

Но зачем тогда AutoML? При наличии постоянного процесса сбора свежих данных можно в автоматическом режиме контролировать качество модели. Если метрика ухудшилась, Jenkins сам запустит пайплайн переобучения модели, и если качество новой модели оказалось лучше текущей модели, то модель в production обновится. Человек в этом процессе больше не нужен. Если, конечно, Spark, MLflow, Git, Hadoop, Airflow и вся остальная инфраструктура работают без перебоев =)

Волков бояться — uplift в прод не катить, или AUF 2.0 - 4

Мультитритмент

Что это такое

Представь стандартную задачу: нужно решить, кому из клиентов отправить предложение о новом продукте. Классический uplift здесь отвечает на вопрос «Стоит ли вообще коммуницировать с этим клиентом?» — и это уже огромный шаг вперёд по сравнению с массовой рассылкой всем подряд.

Но на практике вопрос часто стоит иначе: как именно коммуницировать? Звонок — дорогой канал, и если клиент и так откликнется на push-уведомление, тратить на него время оператора колл-центра нерационально. Баннер в приложении — дёшево, но кому-то нужен живой разговор, иначе он просто не обратит внимания [5].

Разным клиентам нужны разные воздействия.

Именно здесь на сцену выходит multitreatment upliift: вместо одного бинарного вопроса «воздействовать / не воздействовать» модель отвечает на вопрос «Какое из нескольких воздействий принесёт наибольший эффект для конкретного клиента?». Это позволяет не просто отсеять нечувствительных клиентов, но и персонализировать канал коммуникации для всех остальных.

Как пользоваться

Хорошая новость: если ты уже работал с AUF, то освоить мультитритмент не составит труда. Никакого нового класса учить не нужно — используется тот же UpliftPipeline с теми же методами load_sample и run.

Единственное отличие — в формате словаря с маппингом групп, который передаётся в метод load_sample. В бинарном случае достаточно было указать контрольную и одну целевую группу. Для мультитритмента нужно передать все группы, при этом ключ 'control' обязателен — именно относительно него будет считаться эффект каждого воздействия.

После вызова run() пайплайн сам определит, что перед ним задача мультитритмента, обучит соответствующие модели и выдаст аналитику в привычном формате. На выходе для каждого клиента будет скор по каждому из воздействий — и ты сможешь выбрать оптимальный канал.

# Map unified base columns names to custom names from dataframe
base_cols_mapper = {
	'id': "id",
	'treatment': 'treatment',
	'target': 'outcome',
	'segm': None
}

# Map treatment groups from base_cols_mapper["treatment"] to numbers
treatment_groups_mapper = {
	'control': 0,
	'treatment_1': 1,
	'treatment_2': 2,
	'treatment_3': 3,
	'treatment_4': 4,
}


pipeline.load_sample(
	df,
	base_cols_mapper,
	treatment_groups_mapper
)

После выполнения этого кода сначала выведется статистика по конверсиям в каждой группе воздействия и результат проверки гипотезы о том, значимо ли отличие от контрольной группы:

Волков бояться — uplift в прод не катить, или AUF 2.0 - 5

Затем аналогично пайплайну с бинарным воздействием выведется статистика по полученным после разбиения на train-val-test подвыборкам:

Волков бояться — uplift в прод не катить, или AUF 2.0 - 6

Ограничения

Мультитритмент-аплифт — это активно развивающаяся область, и было бы нечестно делать вид, что все вопросы здесь уже решены. Поэтому сразу скажем прямо: в текущей версии AUF реализован базовый вариант мультитритмента.

Что это означает на практике: поддерживаются все основные мультитритмент-модели (включая расширения S-, T- и X-learner на несколько групп), однако метрика качества считается по бинаризованному воздействию. То есть при оценке модели каждый тритмент сравнивается с контролем по отдельности, а не в рамках единой многоклассовой метрики. Это рабочий и интерпретируемый подход, но он не учитывает конкуренцию между тритментами напрямую.

Почему так? Потому что единой общепринятой метрики для оценки мультитритмент-аплифта в академическом сообществе пока нет. Разные статьи предлагают разные подходы, и мы не хотели навязывать один из них как «правильный».

Если занимаешься этой темой и знаешь свежие работы или подходы к оценке мультитритмент-моделей — напиши в комментариях, мы будем очень рады! Это именно тот случай, когда обратная связь от сообщества напрямую влияет на развитие библиотеки.

Обновление функционала AUF

За год библиотека значительно преобразилась изменилась и снаружи, и изнутри. Часть изменений заметны сразу: новые параметры, графики, возможности. Часть работает под капотом и делает код чище, а библиотеку — надёжнее.

Чтобы не превращать этот раздел в changelog, разобьём всё на три смысловых блока.

  • «Учим модели как умные и свободные» — о том, как теперь можно тонко настроить процесс подбора моделей под конкретную задачу.

  • «Анализируем модели как профи» — о новых инструментах, которые помогают понять, что модель нашла и стоит ли ей доверять.

  • «Архитектурные изменения» — о рефакторинге, который не виден пользователю, но делает библиотеку лучше как продукт, а также о документации проекта.

Учим модели как умные и свободные

Обучение моделей и подбор гиперпараметров — это сердце любого AutoML-фреймворка. В первой версии AUF этот процесс был рабочим, но немного прямолинейным. За год мы собрали много фидбека от коллег и поняли: чтобы строить действительно крутые модели, пайплайну нужна гибкость. Каждое изменение иллюстрируется примером параметров pipeline.run(), отвечающих за это.

Кастомизация обучения

Раньше для всех моделей из переданного списка использовались одни и те же настройки. Время обучения задавалось одним числом (например, 300 секунд), а количество топ-признаков — одним списком (например, [20, 50, 100]).

Что это значило на практике? Пайплайн честно брал S-learner, T-learner и X-learner и учил их сначала на 20, потом на 50, а в конце на 100 лучших признаках, выделяя на каждую итерацию ровно по 5 минут. Но ведь X-learner учит внутри себя целых 4 модели, а S-learner — только одну! Очевидно, что X-learner’у нужно больше времени на подбор гиперпараметров, а признаков, возможно, стоит дать поменьше, чтобы он не переобучился.

Теперь параметры feature_nums и timeout_estimator можно задавать в виде словаря, где ключи — это названия моделей. Это позволяет ювелирно настроить пайплайн под тяжесть алгоритмов. Ключ словарей должны совпадать с указанными в списке classes_for_train названиями классов моделей.

preprocessor, model, calibrator = pipeline.run(
	classes_for_train = [
    	"SoloModel", "TwoModels", "AufXLearner",
	],
	feature_nums = {
    	"SoloModel": [10, 20], "TwoModels": [10, 20], "AufXLearner": [5, 10],
	},
	timeout_estimator = {
    	"SoloModel": 10, "TwoModels": 10, "AufXLearner": 10,
	},
)

Трекинг переобучения

Кроме того, при подборе гиперпараметров моделей, пайплайн теперь учитывает штраф за переобучение. Функция штрафа работает так: оценивается разница метрик между трейном и валидацией, и модели, которые сильнее подогнались под обучающую выборку, оказываются ниже в итоговом рейтинге.

Режимы обучения

Иногда данных много и хочется выжать максимум качества. А иногда выборка содержит всего 10 000 объектов, и нужно быстро построить лёгкую модель для проверки гипотезы.

Для управления этим процессом мы добавили параметр training_mode, который отвечает за «силу» подбора гиперпараметров. Доступны три режима: light, medium и hard. Чем «тяжелее» режим, тем шире сетка перебираемых параметров для Optuna, и тем дольше будет идти обучение до сходимости.

preprocessor, model, calibrator = pipeline.run(
	…,
	training_mode="medium",
)

Теперь, если собрать всё вместе, конфиг запуска pipeline.run() будет выглядеть примерно так:

preprocessor, model, calibrator = pipeline.run(
	max_val_roc_auc_treatment = 0.6,
	early_stopping = 10,
	max_abs_feature_correlation = 0.9,
	n_features_candidates = 30,
	classes_for_train = [
    	"SoloModel", "TwoModels", "AufXLearner",
	],
	feature_nums = {
    	"SoloModel": [10, 20], "TwoModels": [10, 20], "AufXLearner": [5, 10],
	},
	timeout_estimator = {
    	"SoloModel": 10, "TwoModels": 10, "AufXLearner": 10,
	},
	opt_metric = 'qini_auc',
	training_mode="medium",
	n_uplift_bins=10,
)

Анализируем модели как профи

Наверное, это самый важный блок изменений. Обучить модель — это полдела. Куда сложнее доказать бизнесу, что она действительно работает и принесёт деньги. Теперь из анализа модели в AUF можно получить заметно больше информации, полезной при планировании реальной маркетинговой кампании.

Расширенный uplift_by_percentile

Если ты работал с библиотекой scikit-uplift, то наверняка знаешь функцию uplift_by_percentile. Она разбивает выборку на бакеты (чаще всего на 10 децилей) по убыванию предсказанного аплифта, и показывает метрики в каждом из них.

Мы расширили эту таблицу — теперь в ней появились два новых столбца. Они показывают процент целевых действий (продаж, сделок, кликов) в контрольной и целевой группах, попавших в каждый бакет.

Зачем это нужно? Представь, что верхний бакет (клиенты с самым высоким аплифтом) содержит 60% всех органических сделок — то есть тех, которые произошли бы и без коммуникации. Возможно, стоит оставить этих клиентов в покое и не рисковать падением маржинальности или лояльности от лишнего спама 🙂.

Волков бояться — uplift в прод не катить, или AUF 2.0 - 7

Эта же информация теперь выводится накопительным итогом по нескольким порогам отсечения — как в виде таблицы, так и в виде наглядного графика для всей выборки.

Волков бояться — uplift в прод не катить, или AUF 2.0 - 8

Анализ чувствительности top vs bottom

Ещё одним важным инструментом стал график конверсий в контрольной и целевой группах, выбранных по модели. Он строится просто: мы берём X% клиентов с наибольшим прогнозным аплифтом (top, которому мы отправим коммуникацию) и сравниваем их со всеми остальными (bottom, которому мы НЕ отправим коммуникацию).

График наглядно показывает чувствительность к коммуникации найденного сегмента относительно остальной базы. Часто именно этот график — то самое доказательство, которое нужно увидеть бизнесу для принятия решения о запуске кампании. Он отвечает на вопрос: «Насколько сильно вырастет конверсия, если мы возьмём в работу именно этот топ-сегмент, а не случайных людей?»

Волков бояться — uplift в прод не катить, или AUF 2.0 - 9

Сравнение с моделью склонности

Этот пункт стоит особо выделить. Модель склонности служит бейзлайном в аплифт-моделировании, с которым мы будем сравнивать лучшую обученную аплифт-модель. Ведь если метрики модели склонности не сильно хуже и достаточно её одной, то можно избежать кучи сложностей с проведением пилотов по сбору данных для обучения аплифт-модели и последующим мониторингом качества.

В AUF появилось несколько способов сравнить аплифт-модель с моделью склонности:

  1. ROC AUC на тестовой выборке. Это позволяет напрямую оценить аплифт-модель как модель склонности: для ранжирования объектов и построения ROC-кривой используется сам аплифт, а не его слагаемые из определения. Заметим, что в этом способе обучать модель склонности не нужно! Так можно оценить, насколько сильно аплифт-модель обусловлена на склонность.

  2. Различные корреляции (Пирсона, Спирмена, Кендалла). Это быстро вычислимый, полностью численный и достаточно интерпретируемый способ сравнить связь двух величин — скора модели склонности и скора аплифт-модели.

  3. Визуальный scatter plot. Если чисел недостаточно, можно посмотреть явно на распределение прогнозов двух моделей, чтобы оценить, насколько однозначно они связаны. В идеале на любой небольшой диапазон склонности должно приходиться некоторый достаточно широкий диапазон значений аплифта. Ведь чувствительность != склонность, и одинаково склонные клиенты могут по-разному реагировать [6] на коммуникацию или другое воздействие.

  4. Таблица метрик. Для модели склонности теперь доступна таблица с метриками ровно в том же виде, как и для лучшей аплифт-модели.

Волков бояться — uplift в прод не катить, или AUF 2.0 - 10
Волков бояться — uplift в прод не катить, или AUF 2.0 - 11

Аналитика вне pipeline

Не раз пользователи AUF внутри Альфа-Банка обращались с вопросом: как можно воспроизвести аналитику, которую пайплайн делает внутри себя, но вне пайплайна?

Теперь такая возможность есть! Функция evaluate позволяет провести анализ любой модели на любой выборке (содержащей все необходимые для модели признаки) любым видом аналитики, доступным в AUF.

Теперь не нужно изучать методы отрисовки графиков внутри пайплайна! Достаточно просто вызвать одну функцию, указав в параметрах модель, выборку и тип аналитики.

from auf.pipeline.evaluation import evaluate_model

evaluate_model(
    base_cols_mapper=base_cols_mapper,
    treatment_groups_mapper=treatment_groups_mapper,
    data=df2,
    preprocessor=preprocessor,
    model=model,
    evaluation_types = [
        'target_info',
        'metrics_table',
        # 'buckets_table',        # можно выбрать любое
        # 'tops_table',           # количество аналитики
        # "buckets_qini_plots",   # качества модели, типы
        # "target_ratios_plots",  # которой указаны здесь
    ],
    n_uplift_bins: int = 10,
)

Результатом такого запуска будет пара таблиц:

Волков бояться — uplift в прод не катить, или AUF 2.0 - 12

Архитектурные изменения

На этом описание продуктовых нововведений заканчивается. Но за год мы не только добавляли новые фичи, но и активно переписывали то, что уже было. Часть этих изменений не видна при простом вызове pipeline.run(), но именно они делают библиотеку стабильной и удобной для развития.

Докстринги везде

Начнём с самого приятного для разработчиков: теперь каждый модуль, класс, метод класса и функция обладают понятной и подробной docstring. В них есть не только описание параметров и возвращаемых значений, но и примеры использования. Пользоваться библиотекой стало сильно проще — больше не нужно лезть в исходники, чтобы понять, какой формат данных ожидает метод. IDE сама всё подскажет.

Рефакторинг оптимизатора

Оптимизатор гиперпараметров (под капотом которого работает Optuna) тоже пережил перестройку. Теперь в нем всего 3 objective-функции: для модели склонности, для модели аплифт с бинарным воздействием, а также для модели аплифт с несколькими воздействиями. Кроме того, код генерации модели и создания сеток параметров также был преобразован для большей модульности.

Рефакторинг класса модели и инференса

Мы полностью переработали базовый класс модели. Теперь он стал умнее:

  1. Хранит внутри себя все группы воздействий в случае мультитритмента, чтобы понимать, как именно считать предикты.

  2. Содержит в себе препроцессор данных, чтобы скорить сырые данные без ручной подготовки.

  3. Имеет единую логику [7] predict, которая сама разбирается, какую модель она сейчас вызывает, чтобы использование S-learner, T-learner и даже мультитритмент моделей моделей было унифицировано.

  4. А для удобной работы в проде мы добавили специальный класс для инференса модели напрямую из MLflow.

Кроме того, мы удалили устаревшие метрики и дефолтные модели без подбора гиперпараметров, поскольку на практике все используют только метод run с использованием optuna. Библиотека стала строже, понятнее и полностью готова к работе в production-среде.

Заключение

За этот год AUF прошёл путь от экспериментального внутреннего инструмента до зрелой библиотеки, которая крутится в production-среде и приносит реальные деньги. Мы добавили поддержку мультитритмента, научили пайплайн гибко настраивать обучение под разные модели, расширили аналитику и навели порядок под капотом.

Но главное — мы доказали на практике, что AutoML в uplift-моделировании работает. Он не заменяет дата-саентиста, но забирает на себя всю рутину, освобождая время для проверки гипотез и общения с бизнесом. А в связке с настроенной инфраструктурой позволяет моделям переобучаться в проде без участия человека.

Что дальше?

Uplift-моделирование — это всё ещё молодая и активно развивающаяся область, в которой много нерешённых вопросов (особенно в оценке мультитритмента). Поэтому мы открыты к диалогу!

  1. Попробуй AUF в своих задачах. Установить библиотеку можно одной командой в окружении с Python 3.8: pip install auf.

  2. Изучи пример. Мы обновили ноутбук с примером использования AUF и выложили его на GitHub, чтобы ты мог пощупать новые фичи на открытых данных прямо в браузере.

  3. Ставь звёздочки и контрибьють. Исходный код лежит на GitHub. Если найдёшь баг или захочешь добавить свою фичу — ждём твои pull requests.

  4. Делись опытом [8]. Смело пиши свои вопросы и идеи по применению AUF в комментариях к этой статье. А если знаешь крутые свежие научные статьи, доклады или выступления по теме мультитритмента — обязательно делись ссылками! Это поможет сделать инструмент лучше и удобнее для всех нас.

До встречи в комментариях! 🐺

Полезные ссылки

Благодарности

Этот проект не развился бы и не появился бы на свет без активной поддержки множества коллег, помогающими с самыми разными вопросами разработки, тестирования и развития AUF.

Хочется сказать спасибо всем причастным:

  • Константину Четину, Анастасии Бондаревой и Александру Матвиюку за поддержку и тщательное код-ревью проекта

  • Дмитрию Светлову, Даниилу Лескевичу, Николаю Крамаренко и Дарье Садыковой за активное вовлечение в развитие AUF и поиск новых применений uplift-моделирования в Банке

  • Анастасии Герасименко как самому активному пользователю, тестировщику, багсерчеру и багфиксеру всея AUF

Да прибудет с вами AUF!

Автор: dcamvik2020

Источник [10]


Сайт-источник BrainTools: https://www.braintools.ru

Путь до страницы источника: https://www.braintools.ru/article/29191

URLs in this post:

[1] о первой open source библиотеке Альфа-Банка: https://habr.com/ru/companies/alfa/articles/895002/

[2] библиотеки на GitHub: https://github.com/Alfa-Advanced-Analytics/auf

[3] обучения: http://www.braintools.ru/article/5125

[4] математике: http://www.braintools.ru/article/7620

[5] внимания: http://www.braintools.ru/article/7595

[6] реагировать: http://www.braintools.ru/article/1549

[7] логику: http://www.braintools.ru/article/7640

[8] опытом: http://www.braintools.ru/article/6952

[9] Обновленный пример использования AUF: https://github.com/Alfa-Advanced-Analytics/auf/blob/main/examples/binary_treatment_megafon.ipynb

[10] Источник: https://habr.com/ru/companies/alfa/articles/1024090/?utm_campaign=1024090&utm_source=habrahabr&utm_medium=rss

www.BrainTools.ru

Rambler's Top100