Привет, Хабр! На связи Денис Киров, руководитель отдела тестирования "дочки" ДОМ.РФ, компании «Цифровые технологии» и Дмитрий Сичкар, главный инженер по нагрузочному тестированию. Но расскажем мы сегодня не про тестирование программных продуктов, а про контроль качества работы компании в целом.    Корпорации борются за улучшение эффективности и качества работы сотрудников, а для того чтобы проверить, эффективна ли какая-либо внедренная методология, нужен числовой коэффициент. Сейчас мы рассматриваем такую метрику эффективности, как удовлетворенность бизнес-заказчика. Для замера подобного показателя чаще всего используется NPS (Net Promoter Score) – индекс потребительской лояльности, проще говоря, обратная связь. Сбор данной метрики в ручном режиме мы внедряем, собирая обратную связь от заказчика с точки зрения удовлетворенности работы команд, конкретных сотрудников, взаимодействующих с заказчиком напрямую, и это интересная и полезная статистика, которую можно анализировать и на основании нее принимать какие-либо управленческие решения. Но мы захотели попробовать автоматизировать сбор этого показателя.   Первый вопрос, которым мы озадачились: что вообще мы будем оценивать, откуда брать данные? Мы поняли, что чаще всего существенные успехи и явный негатив подсвечивается в чатах с бизнес-заказчиком. Для теста решили посмотреть основной и самый многолюдный чат в мессенджере «Телеграм», где есть все сотрудники со стороны заказчика, которые взаимодействуют с нами, и там, действительно, подсвечиваются все успехи, например, успешный и долгожданный релиз, а также все негативные моменты, например, когда что-то работает не в соответствии с ожиданиями, либо сроки нарушены.   После того, как мы определились, откуда мы берем информацию мы смогли более четко сформулировать поставленную задачу – нам необходимо проводить семантический анализ сообщений в бизнес – чатах и классифицировать его. Задача классификации – хорошо автоматизируемая вещь при помощи алгоритмов машинного обучения.  Далее пришло время проанализировать технологический стэк, выбрать необходимые инструменты и библиотеки, продумать архитектуру решения.  Система должна состоять из нескольких модулей, каждый из которых решает свою задачу и взаимодействует между собой:  Модуль сбора сообщений из Телеграм-чатов Хранилище данных, куда кладутся сообщения  Модуль предобработки данных  Модуль с обученной ML-моделью  Хранилище данных с результатами  Визуализатор результатов  Далее нам нужно было определиться с технологическим стэком:  Поскольку мы решаем задачу анализа данных и классификации, то язык программирования был выбран Python 3,  Для взаимодействия с Телеграмом – библиотека telebot,  В качестве первого хранилища данных – встраиваемая БД SqlLite,  Для работы с данными – библиотеки numpy и pandas, а также библиотеки непосредственно для работы с текстом – NLTK, pymorphy3,  Sklearn – библиотека машинного обучения, которая включает в себя все основные методы ML,  Influxdb – noSQL хранилище данных, которое мы будем использовать для хранения полученных результатов,  Grafana – всеми любимый «визуализатор» данных, там мы подготовим дашборд с результатами.  На рисунке ниже изображена схема системы в общем виде:    После того, как задача была проанализирована, и технологический стек определен, мы приступили непосредственно к реализации MVP.    Для MVP мы решили не использовать реальный бизнес-чат, а создали отдельный, в который добавили бота, созданного через bot_father.   Вынесли в конфигурационный файл токен для бота, реализовали парсинг интересующих параметров и запись их в БД.  Также настроили работу парсера в режиме реального времени.  Поскольку в бизнес-чатах есть пользователи, чьи сообщения анализировать не надо (все, кроме основных бизнес – заказчиков), мы реализовали отдельный конфигурационный файл, куда вносятся идентификаторы пользователей, чьи сообщения идут в систему, остальные отсекаются.   Информация, которую мы сохраняем:  идентификатор чата,   заголовок чата,  дата и время получения сообщения,  текст сообщения.  Далее нам было необходимо собрать наборы данных для обучения модели, для этого мы решили использовать ранее разработанный первый модуль и заодно его протестировать.   Мы стали пересылать в данный чат сообщения с последующей разметкой данных на «позитивные» и «негативные».    Пример негативного сообщения:   Пример позитивного сообщения:  Сбор датасета сразу показал две проблемы, которые мы не сразу учли: это эмодзи в сообщениях и картинки / стикеры. Парсер не может обрабатывать такие сообщения, и, чтобы не терять данные, мы вынесли часть предобработки в модуль парсера, а именно удаление эмодзи, стикеров и картинок из получаемых сообщений:  Данный модуль является очень важным, так как от качества обработки данных зависит точность классификации. Вот, что мы реализовали в данном модуле:  Реализация словаря стоп-слов – это те слова, которые не влияют на эмоциональный окрас текста, от них очищается полученное сообщение,  Очистка текста от знаков препинания,  Приведение текста к нижнему регистру,  Перевод всех слов в инфинитив (леммантизация текста).   Также в данном модуле происходит «векторизация» слов, так как модель работает с числами, а не словами.   В следующем модуле при обучении был собран словарь: при переводе слов в коды неизвестные слова отбрасываются.  На выходе из данного модуля передается обработанный и векторизированный текст, который уже классифицирует обученная модель.   Для того чтобы реализовать ML-модель, решающую задачи классификации текста, мы решили использовать два метода машинного обучения: «мешок слов» и «логистическую регрессию».   Чтобы качественно обучить модель, нужен большой набор данных, и того размеченного набора, который мы собрали при тестировании модуля парсинга, было недостаточно. Поэтому мы стали искать в интернете размеченные наборы данных, подходящие под нашу задачу. Мы нашли набор, в котором собраны комментарии по работе банков – позитивные и негативные.   В набор мы добавили также и наши собранные данные, таким образом получился «смешанный» комплект.   После сбора набора данных мы были готовы пробовать обучать модель, экспериментируя с различными настройками для повышения точности.  Что такое “мешок слов”, о котором говорилось ранее? Это представление текста в виде массива, состоящего из отдельных слов и количественного показателя их использования. Применяется при анализе естественного языка. Результатом представления является словарь в виде уникальных слов и их количества по предложениям и всему тексту в целом. Мы подали на вход набор данных, и на выходе получили словарь, про который говорилось в описании модуля предобработки данных. Он выглядит следующим образом:  Далее применялся метод машинного обучения – логистическая регрессия. Она является одним из статистических методов классификации с использованием линейного дискриминанта Фишера. Не углубляясь в математику, логистическую регрессию можно охарактеризовать следующим образом: в методе логистической регрессии не производится предсказание значения числовой переменной исходя из выборки исходных значений. Вместо этого значением функции является вероятность того, что данное исходное значение принадлежит к определенному классу. Это то, что нам нужно. На этапе MVP мы решили выделить два класса: негативный окрас и позитивный окрас.  Разбили выборку на тренировочный набор и тестовый набор в процентном соотношении 80 на 20 и получили неплохой результат – точность 0,95. Поскольку в набор данных были добавлены наши собранные сообщения, то такая точность нас устроила для MVP, и мы сохранили модель.  Далее мы запустили все реализованные модули и провели полноценное тестирование, пересылая в тестовый чат реальные сообщения из бизнес – чата, все сообщения были классифицированы правильно, поэтому мы посчитали, что тестирование пройдено успешно и перешли к финальной части - сохранению результатов и визуализации.  На выходе из предыдущего модуля мы получаем 0 – если окрас полученного сообщения негативный и 1 – если позитивный. Для хранения результатов мы решили использовать time – series DB – InfluxDB. Поэтому был реализован модуль сохранения данных.  В хранилище мы передаем пользователя, который написал сообщение и результат классификации модели.  В итоге мы получаем дашборд в Grafanaг в котором в режиме реального времени отображается картина за выбранный временной интервал, а также присутствует историчность для анализа.     Индекс рассчитывается по следующей формуле:  Берем общую сумму значений за выбранный временной интервал, делим на количество значений и умножаем на 100. Получается нормированный коэффициент, приведенный к процентам, где 100% — это “бизнес-заказчик полностью удовлетворен”, 0% — “бизнес-заказчик совсем не удовлетворен”.   На этапе MVP мы решили результат интерпретировать следующим образом:  0% – 50% - плохо (красный цвет)  50% - 70% - удовлетворительно (желтый цвет)  70% - 100% - отлично (зеленый цвет)  Также помимо общего коэффициента удовлетворенности мы реализовали детализацию по пользователям, чтобы понимать, кто конкретно доволен, а кто нет:  Нами был разработан MVP, который показал хорошие результаты и будет обязательно развиваться в дальнейшем. Данный проект показывает, что для мониторинга эффективности можно применять различные решения, включая машинное обучение, и от идеи до работающего прототипа всего один шаг, который обязательно нужно делать. Мы добились сбора еще одного показателя, который позволяет нам анализировать удовлетворенность заказчика без дополнительного сбора обратной связи и за тот период, который нас интересует. Данная метрика должна помочь принимать различные управленческие решения, заблаговременно понимать, если есть какие-либо проблемы.