赞
踩
1.问题引入
如果给出如图1所示的一个用户对物品的评分表如何预测用户未打分的部分?
图1 用户对不同物品的评分表
可以使用矩阵分解来完成。
矩阵分解的一个作用就是能用来预测如1所示的未知评分,那么如何进行矩阵分解?
我们知道一个矩阵能表示成两个矩阵的乘积的形式即R(m,n)=P(m,k)*Q(k,n),那么对于一个特定的矩阵R我们就可以找到两个矩阵P,Q让P(m,k)*Q(k,n)≈R(m,n)。这样对于如图1所示的矩阵我们就可以预测出用户未打分的物品的分值是多少。k是一个用户自定义的值可以通过交叉验证的方法获得最佳k值。
2.算法原理
如何进行矩阵分解也即如何求解矩阵P与Q的每一项。
可以用如下方法:
1.首先令即预测矩阵R的第i行j列项等于分解矩阵p的第i行乘以矩阵q的第j列。
2.构造损失函数,令原始的矩阵R1与预测的矩阵R之间的误差的平方作为损失函数如果R1(i,j)已知则R1(i,j)的误差的平方和为那么这个误差肯定是越小越好,即要找到对应的Pik和Qkj使得误差最小。可以使用梯度下降的方法求相应的Pik和Qkj。
3.利用梯度下降法求解对应的Pik和Qkj。
先求导
求解对应的Pik和Qkj,因为是求最小值所以应沿梯度的负方向,即新值=旧值+步长*该点的梯度。
Pik和Qk的初值是随机生成的,因为只要迭代次数足够多最终总能找到最小值点,和初值无关。
4.按照梯度下降的方法一直求解一定次数或者两次求得的p或q的差值小于某个给定值后停止迭代。得出对应的分解之后的两个矩阵的每一项,即可得出预测分数。
为了防止模型过拟合,可以增加正则化项即上述求解步骤变为:
1.令和上述第一步的意义相同。
2.为了使模型有更好的泛化能力,在损失函数中增加正则化项即
即
3.对损失函数求导
沿梯度负方向更新变量
4.按照梯度下降的方法一直求解一定次数或者两次求解的p或q的差值小于某个给定值后停止迭代。得出对应的分解之后的两个矩阵的每一项,即可得出预测分数。
3.python代码实现
- # !/usr/bin/env python
- # encoding: utf-8
- __author__ = 'Scarlett'
- #矩阵分解在打分预估系统中得到了成熟的发展和应用
- # from pylab import *
- import matplotlib.pyplot as plt
- from math import pow
- import numpy
-
-
- def matrix_factorization(R,P,Q,K,steps=5000,alpha=0.0002,beta=0.02):
- Q=Q.T # .T操作表示矩阵的转置
- result=[]
- for step in range(steps): #梯度下降的次数
- for i in range(len(R)): #i代表矩阵的每一行
- for j in range(len(R[i])): #j代表矩阵的每一列
- if R[i][j]>0: #如果原始矩阵的这一项有评分,则梯度下降更新其p矩阵的i行数据和q矩阵的j列数据
- eij=R[i][j]-numpy.dot(P[i,:],Q[:,j]) # .dot(P,Q) 表示矩阵内积,即p矩阵的第i行和q矩阵的第j列项对应乘积之和
- for k in range(K):
- P[i][k]=P[i][k]+alpha*(2*eij*Q[k][j]-beta*P[i][k])
- Q[k][j]=Q[k][j]+alpha*(2*eij*P[i][k]-beta*Q[k][j])
- #每进行一个step对p和q矩阵中相应的项更新一次
- eR=numpy.dot(P,Q)
- e=0
- #计算每次更新后损失函数的值
- for i in range(len(R)):
- for j in range(len(R[i])):
- if R[i][j]>0:
- e=e+pow(R[i][j]-numpy.dot(P[i,:],Q[:,j]),2)
- for k in range(K):
- e=e+(beta/2)*(pow(P[i][k],2)+pow(Q[k][j],2)) #正则化项的值
- result.append(e) #将每一次更新后损失函数的值添加到列表result中
- if e<0.001: #如果本次损失函数的值足够小则结束循环
- break
- return P,Q.T,result
-
- if __name__ == '__main__':
- R=[
- [5,3,0,1],
- [4,0,0,1],
- [1,1,0,5],
- [1,0,0,4],
- [0,1,5,4]
- ]
-
- R=numpy.array(R)
-
- N=len(R)
- M=len(R[0])
- K=2
-
- P=numpy.random.rand(N,K) #随机生成一个 N行 K列的矩阵
- Q=numpy.random.rand(M,K) #随机生成一个 M行 K列的矩阵
-
- nP,nQ,result=matrix_factorization(R,P,Q,K)
- print("原始的评分矩阵R为:\n",R)
- R_MF=numpy.dot(nP,nQ.T)
- print("经过MF算法填充0处评分值后的评分矩阵R_MF为:\n",R_MF)
-
- #-------------损失函数的收敛曲线图---------------
-
- n=len(result)
- x=range(n)
- plt.plot(x,result,color='r',linewidth=3)
- plt.title("Convergence curve")
- plt.xlabel("generation")
- plt.ylabel("loss")
- plt.show()
结果:
手工推导
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。