矩阵分解的推荐算法

一、简介

推荐算法(recommendation algorithm)就是利用用户的一些行为,通过一些数学算法,推测出用户可能喜欢的东西。目前应用推荐算法比较好的地方主要是网络,其中淘宝、拼多多和京东等做的都非常好。
 推荐算法主要分为6种:
 1.基于内容的推荐(Content-Based Recommendation)
 2.基于协同过滤的推荐(Collaborative Filtering Recommendation)
 3.基于关联规则的推荐(Association Rule-Based Recommendation)
 4.基于效用的推荐(Utility-Based Recommendation)
 5.基于知识的推荐(Knowledge-Based Recommendation)
 6.组合推荐(Hybrid Recommendation)
 详细了解可参考:推荐算法百度百科

我们现在要解决的问题是对未评价的商品进行评分的预测,如下图所示:
img
 其中, U 1 、 U 2 、 U 3 、 U 4 、 U 5 U_1、U_2、U_3、U_4、U_5 U1U2U3U4U5代表用户, D 1 、 D 2 、 D 3 、 D 4 D_1、D_2、D_3、D_4 D1D2D3D4代表商品。可以看到有的商品用户没有给出评价,我们需要做的事情就是通过推荐算法,将未评价的分数猜测出来。

二、算法原理

1.定义类似于上图的评分矩阵R。
 R矩阵维度为 N ∗ M N*M NM N N N M M M列的矩阵),我们可以将 R R R分解为 P P P矩阵和 Q Q Q矩阵,其中P矩阵维度为 N ∗ K N*K NK Q Q Q矩阵维度为 M ∗ K M*K MK Q Q Q矩阵需要转置一下),于是有:
R ≈ R ^ = P ∗ Q T R \approx \hat{R}=P*Q^{T} RR^=PQT
 对于 P P P Q Q Q矩阵的解释,直观上, P P P矩阵是 N N N个用户对 K K K个主题的关系, Q Q Q矩阵是 K K K个主题跟 M M M个物品的关系,至于 K K K个主题具体是什么,在算法里面 K K K是一个参数,需要调节的,通常 10 ∼ 100 10\sim100 10100之间。

2.对于 R ^ \hat{R} R^ 矩阵:
r ^ i j = p i T q j = ∑ k = 1 K p i k q k j \hat{r}_{ij}=p_{i} ^{T}q_{j}=\sum_{k=1}^{K}p_{ik}q_{kj} r^ij=piTqj=k=1Kpikqkj
R ^ \hat{R} R^ R R R 的维度相同,其中 r i j ^ \hat{r_{ij}} rij^ R ^ \hat{R} R^ i i i 行第 j j j 列的元素值。

3.求损失函数并更新变量:
使用原始的评分矩阵 R R R与重新构建的评分矩阵 R ^ \hat{R} R^之间的误差的平方作为损失函数,即:
e i j 2 = ( r i j − r ^ i j ) 2 = ( r i j − ∑ k = 1 K p i k q k j ) 2 e_{ij}^{2}=(r_{ij}-\hat{r}_{ij})^{2}=(r_{ij}-\sum_{k=1}^{K}p_{ik}q_{kj})^{2} eij2=(rijr^ij)2=(rijk=1Kpikqkj)2
通过梯度下降法,更新变量:

  • 求导:

∂ ∂ p i k e i j 2 = − 2 ( r i j − ∑ k = 1 K p i k q k j ) q k j = − 2 e i j q k j \frac{∂}{∂_{p{ik}}}e_{ij}^{2}=-2(r_{ij}-\sum_{k=1}^{K}p_{ik}q_{kj})q_{kj}=-2e_{ij}q_{kj} pikeij2=2(rijk=1Kpikqkj)qkj=2eijqkj

∂ ∂ q k j e i j 2 = − 2 ( r i j − ∑ k = 1 K p i k q k j ) p i k = − 2 e i j p i k \frac{∂}{∂_{q{kj}}}e_{ij}^{2}=-2(r_{ij}-\sum_{k=1}^{K}p_{ik}q_{kj})p_{ik}=-2e_{ij}p_{ik} qkjeij2=2(rijk=1Kpikqkj)pik=2eijpik

  • 根据负梯度的方向更新变量:

p i k ′ = p i k − α ∂ ∂ p i k e i j 2 = p i k + 2 α e i j q k j p_{ik}'=p_{ik}-α\frac{∂}{∂{p_{ik}}}e_{ij}^{2}=p_{ik}+2αe_{ij}q_{kj} pik=pikαpikeij2=pik+2αeijqkj

q k j ′ = q k j − α ∂ ∂ q k j e i j 2 = q k j + 2 α e i j p i k q_{kj}'=q_{kj}-α\frac{∂}{∂{q_{kj}}}e_{ij}^{2}=q_{kj}+2αe_{ij}p_{ik} qkj=qkjαqkjeij2=qkj+2αeijpik

4.在损失函数中加入正则化惩罚项:
 通常在求解的过程中,为了能够有较好的泛化能力,会在损失函数中加入正则项,以对参数进行约束。加入正则项后的计算过程如下:
E i j 2 = ( r i j − ∑ k = 1 K p i k q k j ) 2 + β 2 ∑ k = 1 K ( p i k 2 + q k j 2 ) E_{ij}^{2}=(r_{ij}-\sum_{k=1}^{K}p_{ik}q_{kj})^{2}+\frac{β}{2}\sum_{k=1}^{K}(p_{ik}^{2}+q_{kj}^{2}) Eij2=(rijk=1Kpikqkj)2+2βk=1K(pik2+qkj2)
通过梯度下降法,更新变量:

  • 求导:

∂ ∂ p i k E i j 2 = − 2 ( r i j − ∑ k = 1 K p i k q k j ) q k j + β p i k = − 2 e i j q k j + β p i k \frac{∂}{∂{p_{ik}}}E_{ij}^{2}=-2(r_{ij}-\sum_{k=1}^{K}p_{ik}q_{kj})q_{kj}+βp_{ik}=-2e_{ij}q_{kj}+βp_{ik} pikEij2=2(rijk=1Kpikqkj)qkj+βpik=2eijqkj+βpik

∂ ∂ q k j E i j 2 = − 2 ( r i j − ∑ k = 1 K p i k q k j ) p i k + β q k j = − 2 e i j p i k + β q k j \frac{∂}{∂{q_{kj}}}E_{ij}^{2}=-2(r_{ij}-\sum_{k=1}^{K}p_{ik}q_{kj})p_{ik}+βq_{kj}=-2e_{ij}p_{ik}+βq_{kj} qkjEij2=2(rijk=1Kpikqkj)pik+βqkj=2eijpik+βqkj

  • 根据负梯度的方向更新变量:

p i k ′ = p i k − α ( ∂ ∂ p i k e i j 2 + β p i k ) = p i k + α ( 2 e i j q k j − β p i k ) p_{ik}'=p_{ik}-α(\frac{∂}{∂{p_{ik}}}e_{ij}^{2}+βp_{ik})=p_{ik}+α(2e_{ij}q_{kj}-βp_{ik}) pik=pikα(pikeij2+βpik)=pik+α(2eijqkjβpik)

q k j ′ = q k j − α ( ∂ ∂ q k j e i j 2 + β q k j ) = q k j + α ( 2 e i j p i k − β q k j ) q_{kj}'=q_{kj}-α(\frac{∂}{∂{q_{kj}}}e_{ij}^{2}+βq_{kj})=q_{kj}+α(2e_{ij}p_{ik}-βq_{kj}) qkj=qkjα(qkjeij2+βqkj)=qkj+α(2eijpikβqkj)

5.算法终止:
每次更新完 R ^ \hat{R} R^ 后,计算一次 l o s s loss loss值,若 l o s s loss loss值非常小或者到达最大迭代次数,结束算法。于是就得到了我们最终的预测矩阵 R ^ \hat{R} R^

三、算法python实现

import numpy as np
import math
import matplotlib.pyplot as plt


R = np.array([[5, 3, 0, 1], # 用户商品评分,0代表未参与评分
              [4, 0, 0, 1],
              [1, 1, 0, 5],
              [1, 0, 0, 4],
              [0, 1, 5, 4]])
N = R.shape[0]  # 用户数
M = R.shape[1]  # 商品数
K = 5           # 主题数
# 定义P和Q矩阵
P = np.random.rand(N, K)    # 初始化P和 Q
Q = np.random.rand(K, M)

def getLoss(R, P, Q, N, M, K, beta):    # 损失函数
    loss = 0.
    for i in range(N):
        for j in range(M):
            if (R[i][j] == 0):
                continue
            sum = sum2 = 0
            for k in range(K):
                sum += P[i][k] * Q[k][j]
                sum2 += P[i][k] * P[i][k] + Q[k][j] * Q[k][j]
            loss += math.pow(R[i][j] - sum, 2) + beta * sum2 / 2
    return loss
def matrix_composition(R, P, Q, N, M, K, alpha = 0.0002, beta = 0.002): # 矩阵分解
    loss_list = []
    for step in range(5000):    # 规定梯度下降次数
        loss = getLoss(R, P, Q, N, M, K, beta)
        if(loss < 0.001):   # 损失值可以忽略不计
            break
        if(step % 20 == 0): # 每20次记录一下loss变化
            plt.scatter(step, loss)
        # if(step % 1000 == 0):   # 调试
        #     print(loss)
        # update
        for i in range(N):
            for j in range(M):
                if(R[i][j] == 0):   # 只看有评分的
                    continue
                sum = 0
                for k in range(K):
                    sum += P[i][k] * Q[k][j]
                for k in range(K):  # 更新变量
                    P[i][k] += alpha * (2 * (R[i][j] - sum) * Q[k][j] - beta * P[i][k])
                    Q[k][j] += alpha * (2 * (R[i][j] - sum) * P[i][k] - beta * Q[k][j])
    return P, Q



if __name__ == '__main__':
    print('评分矩阵')
    print(R)
    P, Q = matrix_composition(R, P, Q, N, M, K)
    print('P和Q矩阵如下')
    print(P)
    print()
    print(Q)
    print()
    print(np.dot(P, Q)) # 矩阵计算
    plt.show()
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
矩阵分解推荐算法是一种常用的推荐算法,可以通过将用户和物品的评分矩阵分解成两个低维矩阵的乘积来预测用户对未评分物品的评分。下面是一个使用Python实现的简单的矩阵分解推荐算法示例: ```python import numpy as np # 构造评分矩阵 R = np.array([[5, 3, 0, 1], [4, 0, 0, 1], [1, 1, 0, 5], [1, 0, 0, 4], [0, 1, 5, 4]]) # 设置超参数 K = 2 # 隐含因子个数 lr = 0.01 # 学习率 epochs = 5000 # 迭代次数 lambda_u = 0.02 # 用户矩阵正则化参数 lambda_v = 0.02 # 物品矩阵正则化参数 # 随机初始化用户矩阵和物品矩阵 U = np.random.randn(R.shape[0], K) V = np.random.randn(R.shape[1], K) # 训练模型 for epoch in range(epochs): # 遍历所有已知评分,更新用户矩阵和物品矩阵 for i in range(R.shape[0]): for j in range(R.shape[1]): if R[i, j] > 0: eij = R[i, j] - np.dot(U[i, :], V[j, :].T) # 预测误差 U[i, :] += lr * (eij * V[j, :] - lambda_u * U[i, :]) # 更新用户矩阵 V[j, :] += lr * (eij * U[i, :] - lambda_v * V[j, :]) # 更新物品矩阵 # 预测评分矩阵 R_pred = np.dot(U, V.T) # 输出预测结果 print(R_pred) ``` 在上面的代码中,我们使用numpy库构造了一个5x4的评分矩阵R,并设置了隐含因子个数K、学习率lr、迭代次数epochs以及正则化参数lambda_u和lambda_v。然后,我们随机初始化用户矩阵U和物品矩阵V,并使用梯度下降方法迭代更新这两个矩阵,直到达到最大迭代次数。最后,我们通过将用户矩阵U和物品矩阵V的乘积作为预测评分矩阵R_pred来预测用户对未评分物品的评分。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值