Как именно пол, возраст или семейное положение пользователей влияют на наши продуктовые метрики? 

Ответить на подобные вопросы помогает решение задач в духе «сегментация чего-либо по имеющимся данным».

Классические подходы аналитиков (анализ зависимостей отдельных переменных, группировка по всем потенциальным переменным) в таких случаях могут быть сложны и требовать больших трудозатрат. 

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

Под катом рассказываем о том, как у нас в Сравни устроен подобный сервис, принципах его работы и деталях технической реализации.


Привет! Меня зовут Марк, я Analytics Developer в Сравни. Однажды нам в команде продуктовой аналитики потребовалось выяснить, какие социально-демографические характеристики пользователей из нашей базы (пол, возраст, семейное положение, работа и т.п.) больше всего влияют на одну из метрик продукта (далее — MTR, от слова metric). 

Из всех возможных путей решения задачи мы выбрали сделать свой собственный инструмент на базе ML. Почему так, как сервис работает и что там под капотом —  рассказываю в этой статье.

Надеюсь, наша история будет полезна для продуктовых и data-аналитиков, интересна для продактов и всех, кто интересуется вопросами сегментации и в целом анализа данных.

Классическая сегментация: привычно, но тяжеловесно 

Как выглядели бы типичные подходы аналитика при такой задаче? 

  1. Анализ зависимостей отдельных переменных

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

  1. Группировка по всем потенциальным переменным

Более радикально настроенный аналитик может попробовать группировать данные сразу по множеству интересных признаков (возраст, город, доход и т.д.), получив много мелких сегментов, каждый со своим MTR. Дальше он начинает вручную сжимать эту информацию до нескольких репрезентативных сегментов.

Оба подхода сложны и требуют значительных временных затрат. Особенно остро проблема проявляется в следующих ситуациях:

  • Численные поля. Как разделить, например, возраст на оптимальные интервалы?

  • Гранулярные категориальные признаки. Как объединить города в оптимальные группы?

  • Изменение метрик. Заказчик может попросить сегментацию по какой-то другой метрике; тогда вся работа начинается с нуля.

Итого: с классическими подходами к сегментации у аналитика есть все шансы на тяжелый день, полный монотонной ручной работы.

Обращаемся к ML-технологиям

Размышляя над тем, как упростить решение задачи, мы пришли к идее использовать некий специальный инструмент. Требовался сервис, который:

  • Полноценно справляется с задачами по сегментированию

  • Похож на привычный аналитику инструментарий вроде BI-инструментов (PowerBI, Superset). 

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

Выбор подходящей технологии не вызвал особых затруднений — можно сказать, тут нам повезло. Популярная ML-модель «решающее дерево» отлично справляется с задачей разделения данных на сегменты в контексте некоторой целевой метрики. Однако популярные BI-системы не слишком-то поддерживают интеграцию с ML-алгоритмами.

Значит, необходимо было самостоятельно написать инструмент (сервис), который содержал бы всю нужную нам функциональность. 

Как устроен наш самописный ML-инструмент

С учётом вышеуказанных требований остановились на следующем наборе технологий: 

  1. Веб-фреймворк

Нужен UI, который бы обеспечил для аналитика знакомый интерфейс BI-инструментов.
Наш выбор: Streamlit — популярный веб-фреймворк на Python, который как раз заточен под разработку аналитических приложений.

  1. Работа с данными

Нужен некоторый движок, на котором мы бы смогли провести препроцессинг данных перед их отправкой в ML-модель для сегментации. Фильтрация, сортировка, группировка с агрегациями и всё такое.

Наш выбор: Polars — набирающая популярность Blazingly fast библиотека для работы с датафреймами, которую мы ранее использовали в проектах компании и очень полюбили. В первую очередь, за выразительный API и действительно высокую скорость работы с такими данными (десятками миллионов строк), на которых тот же Pandas либо работал бы неприлично долго, либо попросту упал с какой-нибудь ошибкой.

Отличной альтернативой для работы с данными является «темная лошадка» в виде DuckDB. Это полноценная локальная OLAP база данных, по скорости не уступающая Polars. При этом она позволяет управлять данными в том числе через привычный аналитикам SQL-код — и решает проблему хранения данных «близко» к сервису, о которой я рассказываю ниже. Выбор в пользу Polars мы сделали в целях экономии времени: по этой технологии в компании уже была устоявшаяся экспертиза. 

  1. Сегментация

Нужен некоторый алгоритм/модель, которая могла бы автоматически сегментировать данные в контексте определенной метрики (следовательно, имеем задачу обучения с учителем).

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

  1. Визуализация результатов

Результаты нужно показать пользователю в виде чартов. Наш выбор: встроенные чарты Streamlit и Plotly, с которым у Streamlit настроена интеграция.

Сегментируем пользователей, изучаем результаты

Давайте посмотрим на наш инструмент в работе — для примера возьмем конкретную задачу с сегментацией.

Так выглядит начальная панель у пользователя:

Глобально на дашборде есть два раздела: 

  1. Предварительная фильтрация данных

  2. Тут все стандартно, как в BI-системах. Пользователь может отсечь ненужные сегменты путем фильтрации данных по определённым полям. Например, на скрине ниже мы настроили фильтры на отбор холостых мужчин от 18 до 60 лет.

  1. Настройка параметров сегментирования

Тут при помощи виджетов-селекторов пользователь может составить задачу сегментирования. Возвращаясь к нашему кейсу: давайте настроим сегментирование в контексте целевой метрики по ряду фич (возраст, пол, образование и т.д.). На графиках мы хотим увидеть значение целевой метрики, и также дополнить ее информацией о размере сегмента. Помимо этого мы можем управлять параметрами сегментации через параметры решающего дерева. Здесь мы указали, что хотим получить максимум 7 сегментов, при этом чтобы доля каждого сегмента составляла не менее 5% от общего размера.

Получаем следующий аутпут:

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

Таким образом пользователь может увидеть, как тот или иной атрибут клиента влияет на метрику в отдельности.

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

В кейсе мы видим: больше всего на метрику продукта влияет возраст. А вот пол, на фоне остальных критериев, можно сказать, не влияет вовсе.

Детали технической реализации

Рассмотрим ключевые архитектурные особенности приложения. 

  • Формирование дашбордов

Сегодня популярен подход «что-то as code», имеющий свои достоинства и недостатки. Изначально мы хотели сделать сервис, в котором можно было бы исключительно силами UI-интерфейса создавать новые чарты и дашборды, как это реализовано в BI-инструментах. Но со временем отбросили идею в пользу создания и администрирования дашбордов «as python code». 

Простая, понятная структура и синтаксис Streamlit этому способствовали; сама же библиотека забирает на себя кучу работы в плане отрисовки всего функционала, параллельного доступа к сервису, сессии пользователей и т.д.

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

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

  • Хранение данных

Для плавной работы дашборда держать данные нужно «близко» к сервису, чтобы он имел к ним быстрый доступ. Мы сделали абстрактный класс, который позволяет сохранять произвольные Polars-датафреймы в некоторой «базе данных», откуда можно быстро считать данные в оперативную память для обработки. 

Из реализаций этого класса на текущий момент есть обертка над локальной файловой системой, которая монтируется к Docker-контейнеру с сервисом и позволяет хранить и обрабатывать датафреймы в .parquet файлах, а метаинформацию — в .json файлах.

  • Получение данных

Это абстрагированный процесс, основная задача которого — забрать данные из какого-либо источника и сформировать из них Polars-датафрейм с последующим сохранением его в локальную БД из предыдущего пункта.

Реализации этого процесса у нас выражены в виде специальных классов, отражающих абстракции датасетов, по одному на каждый тип источника данных. Так как основная аналитическая база данных в компании — DWH Snowflake, то основной класс «обертывает» именно этот источник данных. 

Условно, этот класс хранит SQL-запрос, умеет с ним ходить в БД и забирать соответствующие данные, преобразовывать данные в Polars-датафрейм и сохранять их и метаданные в локальной БД, а также поддерживать актуальность и тех, и других, обновляя в случае необходимости. Объект этого класса находится в основе любого дашборда, являясь тем самым «датасетом» — популярной абстракцией в BI-инструментах по типу Superset и DataLense.

  • Обработка данных

Производится Polars-ом, который умеет работать в lazy-режиме напрямую с сохраненными в файловой системе .parquet-файлами. Тем самым можно работать с данными, которые не помещаются в оперативную память.

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

Реализация сервиса заняла порядка двух недель — силами одного Analytics Developer (меня). Наиболее трудоёмким этапом оказалось изначальное продумывание архитектуры и проверка гипотез. В частности, ресёрч ветки, в которой все дашборды собирались бы через UI (от этого варианта я в итоге отказался). 

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

А завершение этого текста — всё-таки на дворе 2025 год и говорим мы об аналитике — поручим ChatGPT.

Итоги: аналитика, доступная каждому

Нам удалось создать небольшой, но мощный инструмент «self-аналитики». Этот сервис позволяет не просто автоматизировать сложные задачи сегментации данных, но делать это быстро и удобно. Результаты такого ресерча легко визуализировать в виде дашборда, которым можно поделиться с коллегами или даже бизнес-заказчиками.

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

***

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

Комментарии (0)