Использование матричной факторизации для системы рекомендаций
Я работаю над системой рекомендаций для ресторанов, использующих фильтр на основе элементов на С# 6.0. Я хочу настроить свой алгоритм для выполнения, насколько это возможно, поэтому я провел некоторое исследование по различным способам прогнозирования оценок для ресторанов, которые пользователь еще не просмотрел.
Я начну с исследования, которое я сделал
Сначала я хотел создать пользовательский совлокальный фильтр, используя корреляцию pearson между пользователями, чтобы иметь возможность видеть, какие пользователи подходят друг к другу.
Основная проблема заключалась в том, сколько данных было необходимо для расчета этой корреляции. Сначала вам нужно было 4 отзыва на 2 пользователей в одном ресторане. Но мои данные будут очень скудными. Было маловероятно, что 2 пользователя просмотрели те же 4 ресторана. Я хотел исправить это, расширив условия матча (т.е. Не совпадающие пользователи в одних и тех же ресторанах, но в одном и том же ресторане), но это дало мне проблему, когда было трудно определить, какие обзоры я буду использовать в корреляции, поскольку пользователь мог оставить 3 отзыва в ресторане с типом "Фаст-фуд". Какие из них лучше всего подходят для других пользователей в ресторане быстрого питания?
После большего количества исследований я пришел к выводу, что совлокальный фильтр на основе элементов превосходит пользовательский совлокальный фильтр. Но опять же, я столкнулся с проблемой разреженности данных. В моих тестах я смог рассчитать прогноз для ресторана, который пользователь еще не просмотрел, но когда я использовал алгоритм на разреженном наборе данных, результаты были недостаточно хороши. (В большинстве случаев сходство не было возможным между двумя ресторанами, так как ни один из 2 пользователей не оценил тот же ресторан).
После еще большего исследования я обнаружил, что использование метода матричной факторизации хорошо работает с разреженными данными.
Теперь моя проблема
Я искал по всему Интернету учебники по использованию этого метода, но у меня нет опыта в системах рекомендаций, и мои знания об алгебре также ограничены. Я понимаю справедливость метода. У вас есть матрица, в которой у вас есть 1 сторона пользователей и другая сторона ресторанов. Каждая ячейка - это рейтинг, который пользователь дал в ресторане.
Матричный метод факторизации создает две матрицы: один с весом между пользователями и типом ресторана, а другой между ресторанами и этими типами.
Я просто не могу понять, как рассчитать вес между типом ресторана и ресторанами/пользователями (если я правильно понимаю матричную факторизацию). Я нашел десятки формул, которые вычисляют эти числа, но я не могу понять, как их разбить и применить в моем приложении.
Я приведу вам пример того, как данные выглядят в моем приложении:
В этой таблице U1 обозначает пользователя, а R1 обозначает ресторан.
В каждом ресторане есть свои теги (тип ресторана). То есть R1 имеет тег "итальянский", у R2 есть "Fast food" и т.д.
| R1 | R2 | R3 | R4 |
U1 | 3 | 1 | 2 | - |
U2 | - | 3 | 2 | 2 |
U3 | 5 | 4 | - | 4 |
U4 | - | - | 5 | - |
Есть ли кто-нибудь, кто может указать мне в правильном направлении или объяснить, как я должен использовать этот метод для своих данных? Любая помощь будет принята с благодарностью!
Ответы
Ответ 1
Матричная факторизация предполагает, что "скрытые факторы", такие как предпочтение итальянского питания пользователя и физическая ценность продукта питания, связаны с оценками в матрице.
Таким образом, весь Проблемный вид превращается в проблему реконструкции матрицы, для которой существует множество различных решений. Простым, возможно, медленным решением является (помимо ALS и некоторые другие возможности Матричной реконструкции), аппроксимирующие матрицу с использованием алгоритма спуска градиента. Я рекомендую эту короткую статью ieee статью о рекомендательных системах.
Извлечение скрытых факторов - это другая проблема.
Таким образом, реализация GDM может выглядеть так:
public void learnGDM(){
//traverse learnSet
for(int repeat = 0; repeat < this.steps; repeat++){
for (int i = 0; i < this.learnSet.length; i++){
for (int j = 0; j < this.learnSet[0].length; j++){
if(this.learnSet[i][j] > 0.0d){
double Rij = this.learnSet[i][j];
for(int f = 0 ; f <= latentFactors; f++){
double error = Rij - dotProduct(Q.getRow(i), P.getRow(j));/*estimated_Rij;*/
//ieee computer 1.pdf
double qif = Q.get(i, f);
double pif = P.get(j, f);
double Qvalue = qif + gradientGamma * (error * pif - gradientLambda * qif);
double Pvalue = pif + gradientGamma * (error * qif - gradientLambda * pif);
Q.set(i,f, Qvalue);
P.set(j, f, Pvalue);
}
}
}
}
//check global error
if(checkGlobalError() < 0.001d){
System.out.println("took" + repeat + "steps");
break;
}
}
Где учебное задание представляет собой двумерный массив, содержащий рейтинговую матрицу, как в статье ieee. Алгоритм GDM изменяет векторы рейтинга P и Q на каждую итерацию так, чтобы они приближались к рейтингам в рейтинговой матрице. Тогда "не заданные" оценки могут быть рассчитаны точечным произведением P и Q. Самые высокие оценки для не присвоенных оценок будут тогда рекомендациями.
Итак, это для начала. Существует множество оптимизаций и других алгоритмов или модифицированных версий GDM, которые также могут выполняться параллельно.
Некоторые хорошие чтения:
рекомендации систем в Энциклопедии машинного обучения
презентация по факторизации матриц
рекомендующие системы < --- large one ^^