У моего предыдущего работодателя моя команда занималась созданием рекомендательного механизма, который уведомлял нашу команду по продажам об их следующих лучших действиях по продажам. Мы не всегда хотели иметь следующее лучшее действие для каждого клиента — возможно, они не были готовы к другому продукту или не было никаких защитных действий — поэтому нам нужно было ограничить наши рекомендации минимальным порогом активации. И наоборот, если было несколько рекомендаций выше порога, мы хотели представить лучшую из них, определяемую метрикой, охватывающей вероятность, ценность и бизнес-рычаги.
Мы выбрали для решения этой проблемы старый способ одновременного запуска нескольких независимых моделей склонности. Выходные данные каждой модели были откалиброваны с учетом вероятности, была рассчитана оценка дохода, а произведение этих двух результатов создало взвешенное с учетом вероятности значение в долларах, которое можно было сравнивать между моделями с различной архитектурой. Этот подход работал для нашего Proof of Concept, содержащего одну рекомендацию, но масштабирование стало сложным.
Моя группа так и не приступила к изучению золотого стандарта совместной фильтрации RecSys, в основном из-за отсутствия опыта работы с ним. Сегодня даже стандартные подходы к совместной фильтрации могут показаться устаревшими по сравнению с методами глубокого обучения или, в последнее время, с тонко настроенными подходами LLM.
В основе проблемы RecSys лежит проблема завершения матрицы. Если мы представим нашу систему рекомендаций как соответствие между пользователями и продуктами, мы можем представить это как матрицу, в которой пользователи являются ее строками, а столбцы - продуктом. В каждой ячейке находится числовое значение, представляющее рейтинг (например, 1–5 согласно стандартному набору данных Кинообъектив), двоичное значение (представляющее, купил ли пользователь продукт или нет) или любое другое непрерывное значение (например, представляющий ценность функции вместо продукта).
Матрица будет неполной. Не каждый пользователь купил или просмотрел каждый продукт. Цель RecSys — заполнить матрицу, тем самым выведя оценки для продуктов, которые пользователь еще не купил, и исходя из этого предложить пользователю рекомендуемые им продукты в порядке убывания предполагаемой оценки (необязательно с учетом других ограничений).
Пополнение матрицы решается методом матричной факторизации. Предполагается, что наша матрица W, если бы она была дополнена наземными значениями истинности, может быть разложена на произведение двух других матриц U
и V
; а именно UV=W
.
Предположим, у нас есть N=1000
пользователей и M=20
товаров. W
будет матрицей NxM
. Выбирая (несколько произвольно) желаемое количество скрытых факторов, скажем, K=5
, мы строим U
как матрицу размера NxK
, а V
как KxM
. U
представляет собой скрытый фактор, представляющий пользователей и V
продуктов. Следуя правилам умножения матриц, произведение матрицы UV=W’
имеет размер NxM
, то есть размер W
.
Начав случайную инициализацию U
и V
, наша цель — сделать продукт W’
как можно ближе к W
. В то время как завершение матрицы в общем смысле является NP-сложной задачей, предположение о том, что матрица имеет низкий ранг (поскольку предпочтения пользователя обычно могут быть сведены только к нескольким факторам), позволяет решить ее с помощью градиентного спуска.
Для нашей функции потерь мы выбираем норму, применимую к матрицам, например среднеквадратичную ошибку по ячейкам, и стремимся минимизировать разницу, корректируя значения в U
и V
. Короче говоря, это все!
Вернемся к моему предыдущему работодателю. Мы были в секторе финансовых услуг, и продукты, которые мы хотели порекомендовать, были типичными банковскими продуктами: DDA, MMA, Sweep-счета, кредитные карты, спотовая конвертация FX и т. д. Проблема была не такой простой, как «что будет следующим лучшим». продукт», но и «когда для этого подходящее время». Это не тот случай, когда каждый клиент без учетной записи FX должен иметь ее: это было только в том случае, если этого требовали их бизнес-потребности. Это часто сопровождалось элементом синхронизации. Одним из подходов к учету элемента синхронизации в контексте матричной факторизации было бы добавление столбцов, представляющих переменные пользовательских функций. Матрица будет полностью заполнена для этих переменных, потому что мы будем знать все их значения заранее. Остальные столбцы будут столбцами двоичного продукта. Заполнение этой матрицы будет учитывать, например, как долго пользователь был нашим клиентом, сколько у него других продуктов и т. д. Подразумевается, что аналогичные продукты будут рекомендованы аналогичным пользователям по жизненному этапу.