Привет! Меня зовут Денис Красильников, я исследователь-разработчик из команды персонализации. Сегодня я расскажу, как мы с коллегами подошли к задаче оценки качества объяснения рекомендаций магазинов, в которых покупают наши клиенты. Об этом же мы написали статью и даже прошли с ней на воркшоп WSDM 2023.  У нас в приложении мобильного банка есть раздел с рекомендациями партнерских кэшбэков магазинов. Под магазинами я буду подразумевать все места, в которых можно что-то купить: от продуктовых до онлайн-кинотеатров. Раздел, о котором пойдет речь, — это такая лента из магазинов, в которой работает некая рекомендательная система, подбирающая каждому пользователю список самых релевантных для него мест и расставляющая их в порядке релевантности. На Ютубе есть наш доклад об этом.  А что если мы захотим не только строить рекомендации, но и объяснять их? То есть говорить, почему мы порекомендовали именно этот магазин, а не какой-то другой. Исследования (раз, два, три) подтверждают, что объяснение рекомендаций повышает доверие пользователей к сервису и другие бизнес-метрики. Когда человек понимает логику рекомендации, он обычно склонен рассматривать ее более серьезно, поскольку ему становится ясно, что она не появилась из ниоткуда.  Это позволяет пользователям оценить, насколько рекомендация соответствует их потребностям, предпочтениям и контексту. Они могут видеть, какие данные или алгоритмы были использованы для формирования рекомендации — это помогает сделать более информированный выбор и повышает доверие к рекомендациям. Объяснение также помогает людям осознать, что они контролируют принятие решений, поскольку могут учитывать полученную информацию. Поэтому объяснение рекомендации — важный фактор.  Повышение доверия приводит к тому, что клиенты начинают использовать сервис активнее. Рост активности, в свою очередь, положительно влияет на качество модели: чем больше у нас данных о каждом пользователе, тем точнее мы угадываем его предпочтения. Поэтому мы решили, что хотим этим заняться.  Все, о чем пойдет речь ниже, — описание эксперимента на исторических данных. На момент выхода этой статьи фича не реализована в приложении, но мы надеемся скоро ее добавить. Мы хотим взять транзакции пользователей в магазинах и с их помощью обучить рекомендательную модель генерировать рекомендации. А затем построить к ним объяснения и провалидировать эти объяснения каким-то образом: например, спросить у людей, насколько они корректны. Когда речь заходит о задачах, связанных с машинным обучением, в первую очередь встает вопрос о данных. Мы использовали открытый датасет TTRS с анонимизированными транзакциями пользователей — мы собрали его в Тинькофф. Каждая строчка содержит в себе ID пользователя, ID магазина, дату и время транзакции. А также категорию магазина, но ее мы пока что опустим за ненадобностью. user_id item_id time_stamp 0 0 1646137297 0 3 1676137233 1 2 1476137297 1 1 1675137297 2 2 1676137697 3 0 1676037297 4 3 1645137297 Для простоты мы оставили только последнюю по времени транзакцию пользователя в каждом магазине. Список транзакций превратили в матрицу размерности «число пользователей × число магазинов», где в ячейке стоит 1, если пользователь покупал в этом магазине, и 0 — если нет.  Колонку timestamp использовали для разбиения выборки на три части: train, validation и test. Это нужно, чтобы исключить ситуацию, когда модель просто подстраивается под увиденные данные. На train-части мы заставляем модель выучить некоторые закономерности, на valid-части — оцениваем, насколько хорошо модель показывает себя на новых для нее данных. Исходя из качества на valid-части мы выбираем оптимальное состояние модели. На test-части сравниваем лучшую, по версии valid-части, модель с другими, чтобы сделать вывод о ее качестве. user_id / item_id 0 1 2 3 0 1 0 0 1 1 0 1 1 0 2 0 0 1 0 3 1 0 0 0 4 0 0 0 1 Следующий наш шаг — построение рекомендаций. Для этого мы раскладывали исходную матрицу взаимодействий на две: матрицу пользователей и матрицу магазинов. Столбцы в этих матрицах соответствовали неким признакам, которые модель извлекает в ходе обучения, а строки — номеру пользователя или магазина. Причем произведение этих матриц должно давать матрицу, которая будет максимально похожа на исходную. Это классический подход к решению задач коллаборативной фильтрации, а бонусом он позволяет использовать матрицу айтемов для объяснений. Например, мы можем искать по ней похожие айтемы.  В качестве рекомендательной модели мы использовали Alternating Least Squares (ALS). Это довольно примитивная модель машинного обучения — хоть и без модных нынче нейронных сетей, но быстрая и хорошо подходящая для implicit данных. Она хорошо перформит даже на честных академических бенчмарках. Это такие данные, когда у нас есть только факт о том, что пользователь как-то взаимодействовал с айтемом. То есть мы не знаем, понравился он ему или нет. Модель по очереди оптимизирует матрицу пользователей и матрицу айтемов, а также умеет объяснять свои рекомендации.  В нашей работе мы использовали довольно простой вид объяснений: «Рекомендуем вам посетить магазин X, потому что вы покупали в магазине Y». Такой формат мы выбрали по нескольким причинам: Он не зависит от моделей — для генерации рекомендаций мы можем использовать как сложные Deep Learning модели, так и обыкновенную матричную факторизацию или эвристики. У нас было мало времени — нужен был простой и универсальный формат объяснений, который не зависит от метода генерации.  Такие объяснения было легко создавать. Мы просто сэмплировали случайную пару из всех магазинов.  Часто можно придумать объяснение транзакций клиента на основе других его покупок. Например, пиццерия — потому что бургерная. У этого подхода есть некоторые недостатки. Это не самое подробное объяснение, потому что представлен только один магазин: остальные результаты мы не показываем клиенту. Но, несмотря на это, преимущества перевешивают, поэтому сейчас мы считаем этот вариант оптимальным, хотя в будущем планируем добавлять и другие форматы объяснений. Давайте на примере разберем, как выглядит наше объяснение. Допустим, мы хотим объяснить, почему рекомендуем пользователю сходить в определенную кофейню. У нас есть список кандидатов из предыдущих покупок пользователя, и их нужно отсортировать по степени приемлемости объяснения. Достать такие данные из исходного датасета не получится, а давать нелогичные объяснения вроде «Рекомендуем вам кофейню, потому что вы были в строительном магазине» не хочется — это негативно скажется на пользовательском опыте.  Для решения этой задачи нам нужно было с помощью разметки понять, как определять релевантность одного магазина другому. В идеале мы хотели получить степень релевантности, то есть вещественные значения, но бинарные тоже подойдут.  Для разметки использовали внутренний краудсорсинг. Предварительно мы уменьшили общее число магазинов, оставив только самые популярные. В список попали 350 магазинов, которые покрыли почти все транзакции из датасета. Это помогло минимизировать случаи, когда асессорам — людям, размечавшим для нас данные, — могли попадаться магазины, которые им не знакомы. Из 350 магазинов мы случайным образом сгенерировали 23 000 пар, в которых X и Y должны были быть релевантны или нерелевантны друг другу. Для объективности каждую пару размечали 5 различных людей: всего было задействовано около 500 разметчиков.  В итоге получился такой алгоритм работы: Обучить модель, которая создает рекомендации.  Сгенерировать N рекомендаций для каждого пользователя из тестовой выборки. Объяснить каждую из этих рекомендаций. Исключить пары объяснений, которые мы не разметили. Так как разметили только 20% от 23 000 пар, мы убрали объяснения, на которые разметки не было, чтобы метрики были объективными. Разметить все пары не получилось, потому что у нас было мало времени. Посчитать метрики качества объяснений, о которых мы поговорим позже. Давайте подробно рассмотрим методы объяснений, которые мы используем в своей работе. У нас есть возможность применять как эвристики различного уровня сложности, так и алгоритмы машинного обучения, и даже комбинировать их: Случайная генерация. Мы в случайном порядке перемешивали все магазины из покупок пользователей и говорили, что это и есть объяснение. Этот метод мы применяли, чтобы сравнивать с ним остальные методы. Если метод работал хуже случайной генерации, значит, с ним точно что-то не так.  Топ популярного. Мы упорядочивали все магазины по популярности и отдавали это в качестве объяснения.  Хронологический порядок. Мы сортировали покупки пользователей в хронологическом порядке и говорили, что последняя покупка — это объяснение рекомендации.  Персональный топ популярного. Это как топ популярного, только уникальный для каждого человека.  Ассоциативные правила — это алгоритмы, которые ищут взаимосвязь между объектами, основываясь на их совместной встречаемости и других методах частотного анализа.  Топ популярного внутри категории. Это довольно хитрая эвристика. Я уже писал, что у каждого магазина есть категория. Если мы порекомендовали магазины с категорией А, то сначала объясняем через объекты из этой же категории, упорядочивая их по популярности, после чего добавляем остальные в общем порядке.  EASE (Embarrassingly Shallow AutoEncoders) — относительно свежий метод коллаборативной фильтрации, который мы обучали на той же выборке, что и ALS, и использовали для генерации объяснений.  ALS, описанная выше.  Последние два метода можно рассматривать как приятное дополнение от рекомендательной модели, которую мы применяли. В процессе обучения метод выявляет взаимосвязи между объектами, которые мы используем в дальнейшем для генерации объяснений.  Немного пробежимся по ассоциативным правилам, чтобы понять, откуда они вообще взялись. Если внимательно посмотреть на наш формат объяснений «Рекомендуем вам посетить магазин X, потому что вы покупали в магазине Y», в нем можно увидеть математическую операцию под названием импликация. В таком ключе ассоциативные правила сами напрашиваются для использования в эксперименте. Вводятся они следующим образом: Для правила «Y, потому что X» можно построить следующие ассоциативные меры.  Про метрики давайте поговорим чуть подробнее. Допустим, асессор разметил кандидатов следующим образом. Там, где стоит ноль, пара не попала в разметку и данных по ней нет. Единичка — асессор сказал, что рекомендация корректна, а минус один — некорректна.  Все магазины, которые асессор пометил как релевантные, мы хотим поднять как можно выше в топе. В нашем случае — поставить как можно ближе к началу списка. А те, которые асессор отметил как нерелевантные, мы хотим задвинуть в конец списка. Фактически мы приходим к задаче ранжирования, поэтому и использовать будем ранжирующие метрики.  Мы смотрели на NDCG@k, Recall@k и MAP@k.  AR с индексом — это различные методы ассоциативных правил, про которые написано выше. SimCatMostPop — упорядочивание по популярности внутри своей категории. SimCatALS — аналогично SimCatMostPop: сначала мы упорядочиваем внутри категории по ALS, а потом — все остальные в порядке ALS.  Глядя на табличку, можно сделать вывод, что самым лучшим объяснением рекомендаций в нашем эксперименте оказался ALS. Мы предполагали, что EASE покажет себя хотя бы не хуже ALS, ведь в процессе обучения он выучивает матрицу, ячейку которой можно интерпретировать как «вероятность покупки j-го элемента при условии покупки i-го».  Интересное наблюдение: оказалось, что ALS упорядочивает объяснения лучше, чем эвристика с категориями. Возможно, так происходит потому, что внутри одной категории часто бывают магазины, ориентированные на различные социальные группы. Хороший пример такой категории — супермаркеты.  В любом случае мы довольны результатами и не собираемся останавливаться на достигнутом: сейчас улучшаем качество текущей модели, исследуем другие форматы объяснений, придумываем новые способы их построений и делаем все, чтобы такая крутая фича полетела на прод как можно раньше.