一,算法概述
有如下的打分矩阵:
其中打分矩阵R(n,m)是n行m列,n代表user个数,m代表item个数
(“-"代表用户没有打分)
(“-"代表用户没有打分)
当前的矩阵为R(5,4),U1-U5表示用户,D1-D4表示商品,我们需要做的就是根据已知不
同用户对不同商品的评分,通过算法预测出未评价的分数。
矩阵分解是推荐系统中使用的一类协同过滤算法。矩阵分解算法通过将用户-项目交互矩阵分解成两个低维矩形矩阵的乘积来工作,因而我们可以通过矩阵分解的思想来解决这个问题。
二,算法原理
1,矩阵分解的基本概念
矩阵分解是将矩阵拆分成数个矩阵的乘积,对于上述的矩阵R可以将其近似表示为:Rm×n≈Pm×k×Qk×n
矩阵分解的过程中,将原始的评分矩阵Rm×n分解成两个矩阵Pm×k和Qk×n的乘积:Rm×n≈Pm×k×Qk×n=R^m×n
附矩阵乘法的计算:
矩阵乘法是一种根据两个矩阵得到第三个矩阵的二元运算。 矩阵乘法只有在第一个矩阵的列数和第二个矩阵的行数相同时才有意义。
设A为m×p的矩阵,B为p×n的矩阵,那么称m×n的矩阵C为矩阵A与B的乘积,记作C=AB,其中矩阵C中的第i行第j列元素可以表示为:
例如:
注意事项
1、当矩阵A的列数等于矩阵B的行数时,A与B可以相乘。
2、矩阵C的行数等于矩阵A的行数,C的列数等于B的列数。
3、乘积C的第m行第n列的元素等于矩阵A的第m行的元素与矩阵B的第n列对应元素乘积之和。
2,运用梯度下降解决矩阵分解
上述已经介绍将矩阵Rm×n分解为矩阵Pm×k和Qk×n的乘积,因此为了得到近似的Rm×n,需要求出矩阵P和Q。
求出P和Q的方法:
附梯度下降:
梯度下降在机器学习中应用十分的广泛,不论是在线性回归还是Logistic回归中,它的主要目的是通过迭代找到目标函数的最小值,或者收敛到最小值。
梯度下降的直观体现:
假设我们位于某山的某个山腰处,山势连绵不绝,不知道怎么下山。于是决定走一步算一步,也就是每次沿着当前位置最陡峭最易下山的方向前进一小步,然后继续沿下一个位置最陡方向前进一小步。这样一步一步走下去,一直走到觉得我们已经到了山脚。这里的下山最陡的方向就是梯度的负方向。
首先我们先给出梯度的定义。某一函数沿着某点处的方向导数可以以最快速度到达极大值,该方向导数我们定义为该函数的梯度。
其中θ是自变量,f(θ)是关于θ的函数,▽表示梯度。
我们要研究的梯度下降式子可以写作:
其中η是步长,θ是由θ0按照上述式子更新后的值。
想要更详细的介绍请点击:梯度下降算法原理讲解——机器学习
附正则化
正则化的目的是为了防止过拟合(过拟合是指为了得到一致假设而使假设变得过度严格),其本质是约束参数。
想要更详细的介绍请点击:加入正则化项是如何减少过拟合的
三,算法的python实现
代码:
import numpy as np
import math
import matplotlib.pyplot as plt
#定义矩阵分解函数
def Matrix_decomposition(R,P,Q,N,M,K,alpha=0.0002,beta=0.02):
Q = Q.T #Q 矩阵转置
loss_list = [] #存储每次迭代计算的 loss 值
for step in range(5000):
#更新 R^
for i in range(N):
for j in range(M):
if R[i][j] != 0:
#计算损失函数
error = R[i][j]
for k in range(K):
error -= P[i][k]*Q[k][j]
#优化 P,Q 矩阵的元素
for k in range(K):
P[i][k] = P[i][k] + alpha*(2*error*Q[k][j]-beta*P[i][k])
Q[k][j] = Q[k][j] + alpha*(2*error*P[i][k]-beta*Q[k][j])
loss = 0.0
#计算每一次迭代后的 loss 大小,就是原来 R 矩阵里面每个非缺失值跟预测值的平方损失
for i in range(N):
for j in range(M):
if R[i][j] != 0:
#计算 loss 公式加号的左边
data = 0
for k in range(K):
data = data + P[i][k]*Q[k][j]
loss = loss + math.pow(R[i][j]-data,2)
#得到完整 loss 值
for k in range(K):
loss = loss + beta/2*(P[i][k]*P[i][k]+Q[k][j]*Q[k][j])
loss_list.append(loss)
plt.scatter(step,loss)
#输出 loss 值
if (step+1) % 1000 == 0:
print("loss={:}".format(loss))
#判断
if loss < 0.001:
print(loss)
break
plt.show()
return P,Q
if __name__ == "__main__":
N = 5
M = 4
K = 5
R = np.array([[5,3,0,1],
[4,0,0,1],
[1,1,0,5],
[1,0,0,4],
[0,1,5,4]]) #N=5,M=4
print("初始评分矩阵:")
print(R)
#定义 P 和 Q 矩阵
P = np.random.rand(N,K) #N=5,K=2
Q = np.random.rand(M,K) #M=4,K=2
print("开始矩阵分解:")
P,Q = Matrix_decomposition(R,P,Q,N,M,K)
print("矩阵分解结束。")
print("得到的预测矩阵:")
print(np.dot(P,Q))
代码测试结果: