Использование матричной факторизации для системы рекомендаций

Я работаю над системой рекомендаций для ресторанов, использующих фильтр на основе элементов на С# 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 ^^