梯度下降的矩阵分解公式推导与实例分析
注:此博客只是作者在学习的过程中的一些记录和浅疏的理解,内容多为借鉴和自己的一些总结。
当我们了解和学习过梯度下降之后,对于矩阵分解的学习会更直接易懂。
矩阵分解就是将一个大的矩阵分解成两个行对应列相等的两个小矩阵,用两个小的矩阵去预测大的矩阵的取值通。俗来说就是矩阵相乘的逆运算。在这里我们还要借用损失函数,构造损失函数(loss function)。接下来让我们看一些例子和相关理论介绍。
一,基于矩阵分解的推荐算法相关理论介绍
如图1,是一个用户对物品的评分距图
U1,2,3,4,5表示五个用户,D1,2,3,4表示四个不同的物品,表中的数据表示用户对物品的打分 评价。- 则表示没有打分。现在我们的目的就是把这些没有打分的通过方法预测出来。这也是矩阵分解的主要内容。
那我们该如何预测这些数值呢?
对于缺失的评分,可以转化为基于机器学习的回归问题,也就是连续值的预测。
对于矩阵分解有如下式子,假设R是图1的评分矩阵,NM维度(N为行,M为列),我们可以将其分解为用户-特性矩阵P,以及物品-特性矩阵Q。其中P矩阵维度NK,Q矩阵维度MK。所以我们可以得到式子1
其中Q是对Q矩阵进行转置,便于矩阵之间的计算。
二,对于P,Q矩阵的解释
P矩阵是N个用户对K个主题的关系,Q矩阵是K个主题跟M个物品的关系,这里K是我们引入的一个参数,在这里不予讨论。在算法里面K是一个参数,需要调节,通常是10~100之间。
然后我们便可以通过公式得到我们想要的那些预测值。
式子2的左边表示的是
三,构造损失函数
所以,这里我们又用到了损失函数来判断两者的相对误差大小。如式子3:
构造完损失函数,我们便可以运用梯度下降里面的知识对两个参数进行不断地迭代,更新P和Q的值。
P,Q矩阵求出来以后,对于每个用户i对商品j的评价就是:
p(i,1)*q(1,j)+p(i,2)*q(2,j)+…+p(i,k)*q(k,j)。
一般的为了防止过拟合问题,会对上述式子4加入正则化运算。
四,算法终止
每次更新完后,计算一次loss值,若loss值非常小或者到达最大迭代次数,结束算法。于是就得到了我们最终的预测矩阵。
五,手工实例
六,代码实现
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):
# 更新$\hat{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([[4, 0, 3, 5],
[0, 5, 4, 0],
[5, 4, 2, 0],
[2, 4, 0, 3],
[3, 4, 5, 0]]) # 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))