В прошедшие выходные (14-15 июля) в офисе Mail.Ru Group прошел очередной хакатон SmartMailHack. Нам предложили «придумать фичу, которая позволит получить доступ к данным из Почты и более эффективно взаимодействовать с ними».  Мы получили тестовый ящик с более чем 1500 сообщениями, а также полный доступ к нему через API. Организаторы предоставили большой, развернутый мануал по его использованию (книжка на 547 страниц). С помощью токена и простых JSON-запросов, мы могли получать всю необходимую информацию о почте: письма, имена отправителей, различные характеристики.  Обсудив, что у каждого из нас в почте порядка нескольких тысяч непрочитанных писем из рассылок, мы решили разобраться с этой проблемой. В нашем случае релевантность письма перестала определяться временем его появления в почтовом ящике. И если исходить из того, что будут открыты далеко не все письма, тогда лучше показать пользователю только те из них, которые он, вероятно, откроет. А всё остальное можно убрать куда подальше. Так что мы решили сделать сортировку для почты.  Сортировать письма предполагалось по категориям, а категории размещать внутри плиток (привет, Trello). Верхний ряд плиток объединял по смыслу письма от разных отправителей. Здесь могут быть «Поездки», «Регистрации», «Переписка с Васей», «События», «Финансы» и так далее, всего около 10 категорий. Вторым рядом шли плитки с самыми крутыми предложениями от компаний. Мы искали самые релевантные промокоды, самые скидочные акции, самые ценные предложения, и показывали их здесь, сгруппированными по компаниям. Затем шли все остальные письма, распределенные по компаниям-отправителям, а эти отправители, в свою очередь, были раскиданы по категориям («Еда», «Косметика», «Электроника» и другие). Причем категории тоже ранжировались по релевантности писем, и только письма, преодолевшие определенный порог релевантности, показывались внутри. Подкрепив идею словами «Найти нужное и избавиться от лишнего», мы полезли в ML. Мы решили построить три модели: Кажется, что данный пункт должен быть описан персонально для каждой задачи. Однако мы сгенерировали один общий датасет признаков и обучали на нём все модели. Времени для тщательного отбора не было. Была куча бинарных признаков, которые выгружаются с помощью API. Однако, большинство из них оказались сгенерированы на текстах: Мы разметили руками 1000 писем для обучения. Оказалось, это не такая медленная и нудная работа как может показаться сперва. Если использовать адреса и заголовки, можно заметно ускорить работу. Например, Lamoda почти всегда присылает письма в категорию «Одежда». Далее мы обучаем LightGBM на всем множестве признаков и получили качество 0.913 accuracy и 0.892 f1 меры, что мы определили очень неплохим результатом на уровне base line. Это показывает что письма можно классифицировать очень неплохо. В качестве целевой переменной мы использовали бинарный флаг 0/1 — было ли прочитано письмо пользователем. Далее ранжировали по вероятности, предсказанной моделью, поскольку именно это отражает то, насколько модель уверена в том прочитает человек сообщение или нет.  Здесь мы так же обучили LightGBM на всем множестве признаков и получили качество около 0.816 auc-roc. Помимо основных категорий у нас есть категория «Другое». Из нее можно выделять новые темы. Мы обучили стандартный DBSCAN на письмах из этой группы, а дальше выбрали те кластеры, в которых было много сообщений (threshold можно оптимизировать, но он был зафиксирован случайно). На коллекции документов кластера можно натравить, например, тематическое моделирование, получить наиболее релевантную тему для данного кластера и выделить его в отдельную группу. Отвалидировать этот алгоритм времени не хватило. Итак, входящие письма пропускаются через классификатор, если попадают в категорию «Другое» — кластеризуются, пытаются выделиться новые темы, а далее происходит ранжирование. Отправляется запрос на бэкенд, который всё агрегирует, и рендерится фронтенд. Оставшиеся идеи