基于矩阵分解的推荐算法(java代码实现)

来源:互联网 发布:八方网络 编辑:程序博客网 时间:2024/04/25 12:06

目前推荐系统中用的最多的就是矩阵分解方法,在Netflix Prize推荐系统大赛中取得突出效果。以用户-项目评分矩阵为例,矩阵分解就是预测出评分矩阵中的缺失值,然后根据预测值以某种方式向用户推荐。常见的矩阵分解方法有基本矩阵分解(basic MF),正则化矩阵分解)(Regularized MF),基于概率的矩阵分解(PMF)等。今天以“用户-项目评分矩阵R(N×M)”说明三种分解方式的原理以及应用。
这里写图片描述
用户-项目评分矩阵
Basic MF:
Basic MF是最基础的分解方式,将评分矩阵R分解为用户矩阵U和项目矩阵S, 通过不断的迭代训练使得U和S的乘积越来越接近真实矩阵,矩阵分解过程如图:
矩阵分解过程
这里写图片描述
预测值接近真实值就是使其差最小,这是我们的目标函数,然后采用梯度下降的方式迭代计算U和S,它们收敛时就是分解出来的矩阵。我们用损失函数来表示误差(等价于目标函数):
损失函数 公式1
这里写图片描述
公式1中R_ij是评分矩阵中已打分的值,U_i和S_j相当于未知变量。为求得公式1的最小值,相当于求关于U和S二元函数的最小值(极小值或许更贴切)。通常采用梯度下降的方法:
梯度下降
这里写图片描述
学习速率是学习速率,表示迭代的步长。其值为1.5时,通常以震荡形式接近极值点;若<1迭代单调趋向极值点;若>2围绕极值逐渐发散,不会收敛到极值点。具体取什么值要根据实验经验。

Regularized MF

正则化矩阵分解是Basic MF的优化,解决MF造成的过拟合问题。其不是直接最小化损失函数,而是在损失函数基础上增加规范化因子,将整体作为损失函数。
这里写图片描述

红线表示正则化因子,在求解U和S时,仍然采用梯度下降法,此时迭代公式变为:(图片截取自相关论文,S和V等价)
梯度下降
这里写图片描述
梯度下降结束条件:f(x)的真实值和预测值小于自己设定的阈值(很小的值,之前一直理解为是变量U和V的迭代值差小于阈值就行)

Java代码实现矩阵分解

public class Test {     private static int N=5;//用户的数目     private static int M=4;//产品的数目     private static int K=2;//特征的数目     private static DecimalFormat df=new DecimalFormat("###.000");     public static void main(String[] args) {         double[] R=new double[N*M];         double[] P=new double[N*K];         double[] Q=new double[N*M];         R[0]=5;         R[1]=3;         R[2]=0;         R[3]=1;         R[4]=4;         R[5]=0;         R[6]=0;         R[7]=1;         R[8]=1;         R[9]=1;          R[10]=0;         R[11]=5;         R[12]=1;         R[13]=0;         R[14]=0;         R[15]=4;         R[16]=0;         R[17]=1;         R[18]=5;         R[19]=4;         System.out.println("R矩阵");         for(int i=0;i<N;++i) {           for(int j=0;j<M;++j){               System.out.print(R[i*M+j]+",");          }          System.out.println();         }         //初始化P,Q矩阵,这里简化了,通常也可以对服从正态分布的数据进行随机数生成          for(int i=0;i<N;++i)          {             for(int j=0;j<K;++j)             {                 P[i*K+j]=Math.random()%9;             }         }         for(int i=0;i<K;++i)          {             for(int j=0;j<M;++j)             {                 Q[i*M+j]=Math.random()%9;             }         }                    System.out.println("矩阵分解开始");         matrix_factorization(R,P,Q,N,M,K);           System.out.println("重构出来的R矩阵");         for(int i=0;i<N;++i)          {           for(int j=0;j<M;++j)           {            double temp=0;            for (int k=0;k<K;++k){               temp+=P[i*K+k]*Q[k*M+j];             }            System.out.print(df.format(temp)+",");           }           System.out.println();         }     }     public static void matrix_factorization(double[] R,double[] P,double[] Q,int N,int M,int K){        int steps=5000;        double alpha=0.0002;        double beta=0.02;        for(int step =0;step<steps;++step){            for(int i=0;i<N;++i) {                for(int j=0;j<M;++j){                    if(R[i*M+j]>0){                        double eij = R[i*M+j];                        for(int k=0;k<K;++k){                            eij -= P[i*K+k]*Q[k*M+j];                         }                        for(int k=0;k<K;++k){                            P[i*K+k] +=alpha * (2 * eij * Q[k*M+j] - beta * P[i*K+k]);                            Q[k*M+j] +=alpha * (2 * eij * P[i*K+k] - beta *  Q[k*M+j]);                        }                         }                     }                }            double loss=0;            for(int i=0;i<N;++i){                 for(int j=0;j<M;++j) {                     if(R[i*M+j]>0){                         double eij =0;                            for(int k=0;k<K;++k){                                eij += P[i*K+k]*Q[k*M+j];                             }                              loss += Math.pow(R[i*M+j]-eij,2);                              for(int k=0;k<K;++k){                                 loss += (beta/2) * (Math.pow(P[i*K+k],2) + Math.pow(Q[k*M+j],2));                              }                       }                 }            }             if(loss<0.001){                break;            }             if (step%1000==0){                System.out.println("loss:"+loss);            }        }    }}
阅读全文
1 0
原创粉丝点击