![Сегментация данных — это не больно. Применяем ML-модели в аналитике - 1 Сегментация данных — это не больно. Применяем ML-модели в аналитике - 1](https://www.braintools.ru/images/2025/01/21/segmentaciya-dannyh-eto-ne-bolno-primenyaem-ML-modeli-v-analitike.png)
Как именно пол, возраст или семейное положение пользователей влияют на наши продуктовые метрики?
Ответить на подобные вопросы помогает решение задач в духе «сегментация чего-либо по имеющимся данным».
Классические подходы аналитиков (анализ зависимостей отдельных переменных, группировка по всем потенциальным переменным) в таких случаях могут быть сложны и требовать больших трудозатрат.
Альтернативный вариант — использовать собственный инструмент сегментирования, созданный на базе ML-модели под конкретный набор задач.
Под катом рассказываем о том, как у нас в Сравни устроен подобный сервис, принципах его работы и деталях технической реализации.
Привет! Меня зовут Марк, я Analytics Developer в Сравни. Однажды нам в команде продуктовой аналитики потребовалось выяснить, какие социально-демографические характеристики пользователей из нашей базы (пол, возраст, семейное положение, работа и т.п.) больше всего влияют на одну из метрик продукта (далее — MTR, от слова metric).
Из всех возможных путей решения задачи мы выбрали сделать свой собственный инструмент на базе ML. Почему так, как сервис работает и что там под капотом — рассказываю в этой статье.
Надеюсь, наша история будет полезна для продуктовых и data-аналитиков, интересна для продактов и всех, кто интересуется вопросами сегментации и в целом анализа данных.
Классическая сегментация: привычно, но тяжеловесно
Как выглядели бы типичные подходы аналитика при такой задаче?
-
Анализ зависимостей отдельных переменных
Аналитик строит запросы и смотрит в дашборды (при их наличии), чтобы исследовать, как MTR меняется в зависимости от конкретных свойств клиентов. Например, замечает, что у женщин MTR выше, чем у мужчин. Аналитик учитывает эту зависимость и движется дальше. Пройдясь по всем фичам, формирует финальные выводы — на основе анализа совокупности выявленных факторов.
-
Группировка по всем потенциальным переменным
Более радикально настроенный аналитик может попробовать группировать данные сразу по множеству интересных признаков (возраст, город, доход и т.д.), получив много мелких сегментов, каждый со своим MTR. Дальше он начинает вручную сжимать эту информацию до нескольких репрезентативных сегментов.
Оба подхода сложны и требуют значительных временных затрат. Особенно остро проблема проявляется в следующих ситуациях:
-
Численные поля. Как разделить, например, возраст на оптимальные интервалы?
-
Гранулярные категориальные признаки. Как объединить города в оптимальные группы?
-
Изменение метрик. Заказчик может попросить сегментацию по какой-то другой метрике; тогда вся работа начинается с нуля.
Итого: с классическими подходами к сегментации у аналитика есть все шансы на тяжелый день, полный монотонной ручной работы.
Обращаемся к ML-технологиям
Размышляя над тем, как упростить решение задачи, мы пришли к идее использовать некий специальный инструмент. Требовался сервис, который:
-
Полноценно справляется с задачами по сегментированию
-
Похож на привычный аналитику инструментарий вроде BI-инструментов (PowerBI, Superset).
Иными словами, нужен был дашборд с фильтрами, селекторами и прочими опциями, которым можно было бы поделиться с коллегами.
Выбор подходящей технологии не вызвал особых затруднений — можно сказать, тут нам повезло. Популярная ML-модель «решающее дерево» отлично справляется с задачей разделения данных на сегменты в контексте некоторой целевой метрики. Однако популярные BI-системы не слишком-то поддерживают интеграцию с ML-алгоритмами.
Значит, необходимо было самостоятельно написать инструмент (сервис), который содержал бы всю нужную нам функциональность.
Как устроен наш самописный ML-инструмент
С учётом вышеуказанных требований остановились на следующем наборе технологий:
-
Веб-фреймворк
Нужен UI, который бы обеспечил для аналитика знакомый интерфейс BI-инструментов.
Наш выбор: Streamlit — популярный веб-фреймворк на Python, который как раз заточен под разработку аналитических приложений.
-
Работа с данными
Нужен некоторый движок, на котором мы бы смогли провести препроцессинг данных перед их отправкой в ML-модель для сегментации. Фильтрация, сортировка, группировка с агрегациями и всё такое.
Наш выбор: Polars — набирающая популярность Blazingly fast библиотека для работы с датафреймами, которую мы ранее использовали в проектах компании и очень полюбили. В первую очередь, за выразительный API и действительно высокую скорость работы с такими данными (десятками миллионов строк), на которых тот же Pandas либо работал бы неприлично долго, либо попросту упал с какой-нибудь ошибкой.
Отличной альтернативой для работы с данными является «темная лошадка» в виде DuckDB. Это полноценная локальная OLAP база данных, по скорости не уступающая Polars. При этом она позволяет управлять данными в том числе через привычный аналитикам SQL-код — и решает проблему хранения данных «близко» к сервису, о которой я рассказываю ниже. Выбор в пользу Polars мы сделали в целях экономии времени: по этой технологии в компании уже была устоявшаяся экспертиза.
-
Сегментация
Нужен некоторый алгоритм/модель, которая могла бы автоматически сегментировать данные в контексте определенной метрики (следовательно, имеем задачу обучения с учителем).
Мы предпочли стандартную реализацию решающего дерева в библиотеке scikit-learn. Выбор модели обусловлен оптимальным балансом ее простоты и достаточности для решения задачи, а самая популярная и надежная реализация этой модели находится в scikit-learn.
-
Визуализация результатов
Результаты нужно показать пользователю в виде чартов. Наш выбор: встроенные чарты Streamlit и Plotly, с которым у Streamlit настроена интеграция.
Сегментируем пользователей, изучаем результаты
Давайте посмотрим на наш инструмент в работе — для примера возьмем конкретную задачу с сегментацией.
Так выглядит начальная панель у пользователя:
![Сегментация данных — это не больно. Применяем ML-модели в аналитике - 2 Сегментация данных — это не больно. Применяем ML-модели в аналитике - 2](https://www.braintools.ru/images/2025/01/21/segmentaciya-dannyh-eto-ne-bolno-primenyaem-ML-modeli-v-analitike-2.png)
Глобально на дашборде есть два раздела:
-
Предварительная фильтрация данных
-
Тут все стандартно, как в BI-системах. Пользователь может отсечь ненужные сегменты путем фильтрации данных по определённым полям. Например, на скрине ниже мы настроили фильтры на отбор холостых мужчин от 18 до 60 лет.
![Сегментация данных — это не больно. Применяем ML-модели в аналитике - 3 Сегментация данных — это не больно. Применяем ML-модели в аналитике - 3](https://www.braintools.ru/images/2025/01/21/segmentaciya-dannyh-eto-ne-bolno-primenyaem-ML-modeli-v-analitike-3.png)
-
Настройка параметров сегментирования
Тут при помощи виджетов-селекторов пользователь может составить задачу сегментирования. Возвращаясь к нашему кейсу: давайте настроим сегментирование в контексте целевой метрики по ряду фич (возраст, пол, образование и т.д.). На графиках мы хотим увидеть значение целевой метрики, и также дополнить ее информацией о размере сегмента. Помимо этого мы можем управлять параметрами сегментации через параметры решающего дерева. Здесь мы указали, что хотим получить максимум 7 сегментов, при этом чтобы доля каждого сегмента составляла не менее 5% от общего размера.
![Сегментация данных — это не больно. Применяем ML-модели в аналитике - 4 Сегментация данных — это не больно. Применяем ML-модели в аналитике - 4](https://www.braintools.ru/images/2025/01/21/segmentaciya-dannyh-eto-ne-bolno-primenyaem-ML-modeli-v-analitike-4.png)
Получаем следующий аутпут:
![Сегментация данных — это не больно. Применяем ML-модели в аналитике - 5 Сегментация данных — это не больно. Применяем ML-модели в аналитике - 5](https://www.braintools.ru/images/2025/01/21/segmentaciya-dannyh-eto-ne-bolno-primenyaem-ML-modeli-v-analitike-5.png)
То есть для каждой фичи строится отдельный бар-чарт, отражающий значения заданных метрик у сегментов, которые были сформированы деревом. Вы можете увидеть, что возраст был поделен на интервалы, а, например, типы образования были объединены в группы.
Таким образом пользователь может увидеть, как тот или иной атрибут клиента влияет на метрику в отдельности.
Внизу располагается таблица с результатами совместного сегментирования — когда дерево на вход принимает сразу все фичи и по их совокупности формирует конкретные сегменты. Также дерево оценивает вклад каждой фичи в своей решение, что позволяет нам упорядочить факторы по влиянию на целевую метрику.
В кейсе мы видим: больше всего на метрику продукта влияет возраст. А вот пол, на фоне остальных критериев, можно сказать, не влияет вовсе.
Детали технической реализации
Рассмотрим ключевые архитектурные особенности приложения.
-
Формирование дашбордов
Сегодня популярен подход «что-то 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-моделей во благо аналитики, делитесь в комментах! Будет рады узнать об опыте других компаний — и ответить на любые вопросы о нашей реализации.
Автор: mark_mer