推荐系统之矩阵分解模型原理及Python实现

一、矩阵算法概述
原本在使用各种APP的时候觉得推荐算法是一个神奇的东西,恰巧要做手厅用户的前人千面,所以利用协同过滤做了手厅的基于产品的推荐模型,发现出来的产品推荐很接近,更充满好奇心,所以有了接下来各种推荐算法的学习。在各种资料中,发现了基于矩阵分解的推荐系统,学习了它的原理之后,发现矩阵算法对于推荐的效果更好且更好运用。接下来介绍矩阵分解的原理。
矩阵分解(Matrix Factorization, MF),下面简称MF,矩阵算法就是,将用户和产品矩阵中的数据,分解成两个矩阵(用User矩阵和Item矩阵),两个矩阵相乘得到的结果就是预测评分。当我们要计算第i 个用户对第j 个item的预测评分时),我们就可以用User矩阵的第i行和Item矩阵的第j 列做内积,这个内积的值就是预测评分了。对于某个用户进行推荐时,我们把他的用户向量和所有item向量做内积,然后按内积从大到小排序,取出前K 个item,过滤掉历史item后推荐给用户。
那MF是如何从评分矩阵中分解出User矩阵和Item矩阵的呢?简单来说,MF把User矩阵和Item矩阵作为未知量,用它们表示出每个用户对每个item的预测评分,然后通过最小化预测评分跟已知实际评分的差异,学习出User矩阵和Item矩阵。

在这里插入图片描述

二、矩阵算法推导公式
矩阵分解是指一个矩阵分解成两个或者多个矩阵的乘积。对于评分矩阵记为R(m×n),分解成两个矩阵P(m×k)和Q(k×n),我们要使得矩阵P(m×k)和Q(k×n)的乘积能够还原原始的矩阵R(m×n)。
在这里插入图片描述
其中,矩阵P(m×k)表示的是m个用户与k个主题之间的关系,而矩阵Q(k×n)表示的是k个主题与n个商品之间的关系。
那么接下来的问题是如何求解矩阵Pm×kPm×k和Qk×nQk×n的每一个元素,可以将这个问题转化成机器学习中的回归问题进行求解。
损失函数
可以使用原始的评分矩阵Rm×nRm×n与重新构建的评分矩阵Rm×nRm×n之间的误差的平方作为损失函数,即:
在这里插入图片描述
最终,求解所有有评分项的损失值和的最小值。
在这里插入图片描述
损失函数的求解,可以通过梯度下降法求解,求解损失函数的负梯度:

在这里插入图片描述
根据负梯度的方向更新变量:
在这里插入图片描述
通过迭代,直到算法最终收敛。
为了能够有较好的泛化能力,为了防止过拟合,会在损失函数中加入正则项,以对参数进行约束,加入L2正则的损失函数为:
在这里插入图片描述
求解损失函数的负梯度:
在这里插入图片描述
根据负梯度的方向更新变量:
在这里插入图片描述
通过迭代,直到算法最终收敛。
预测
在这里插入图片描述
三、Python实现
1、下面利用用户观看的电影数据来实现矩阵分解的推荐。

import pandas  as  pd
import numpy as np
import matplotlib.pyplot as plt
movies_df = pd.read_csv("C:\\Users\\data\\movies.csv")
ratings_df = pd.read_csv("C:\\Users\\data\\real_ratings.csv")

在这里插入图片描述
在这里插入图片描述
2、创建定影评分表

userNo=max(ratings_df['userId']+1) #用户数量
movieNo=max(ratings_df['movieRow'])+1#电影数量
rating = np.zeros((userNo,movieNo)) #生成零矩阵
for index,row in ratings_df.iterrows(): #评分
    rating[int(row['userId']),int(row['movieRow'])]=row['rating'] #填充得分

在这里插入图片描述

def matrix_factorization(data,K,steps=100,alpha=0.0002,beta=0.02):
    #获取用户数和电影数
    M,N = data.shape
    #初始化参数
    P=np.random.rand(M,K)#随机生成一个矩阵
    Q=np.random.rand(K,N)
      result=[]
    for step in range(steps):
        for i in range(len(data)):
            for j in range(len(data[i])):
                if data[i][j]>0:
                    eij=data[i][j]-np.dot(P[i,:],Q[:,j]) # .dot(P,Q) 表示矩阵内积
                    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])
        eR=np.dot(P,Q)
        e=0
        for i in range(len(data)):
            for j in range(len(data[i])):
                 if data[i][j]>0:
                    e=e+pow(data[i][j]-np.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)
        if e<0.001:   #损失函数小于阈值,算法收敛
            break
    return P,Q,result
def save_file(file_name, source):#保存结果
    f = open(file_name, "w")
    m, n = np.shape(source)
    for i in range(m):
        tmp = []
        for j in range(n):
            tmp.append(str(source[i, j]))
        f.write("\t".join(tmp) + "\n")
    f.close()
def prediction(dataMatrix, p, q, user):#预测为用户user未互动的项打分
    n = np.shape(dataMatrix)[1]
    predict = {}
    for j in range(n):
        if dataMatrix[user, j] == 0:
            predict[j] = np.dot(p[user,], q[:, j])
    return sorted(predict.items(), key=lambda d: d[1], reverse=True)
def top_k(predict, k):#为用户推荐前k个商品
    top_recom = []
    len_result = len(predict)
    if k >= len_result:
        top_recom = predict
    else:
        for i in range(k):
            top_recom.append(predict[i])
    return top_recom
if __name__ == "__main__":
    nP,nQ,result=matrix_factorization(rating,20)
    save_file("p", nP)
    save_file("q", nQ)
    predict = prediction(rating, nP, nQ, 7)
    top_recom = top_k(predict, 10)
       #-------------损失函数的收敛曲线图---------------
    n=len(result)
    x=range(n)
    plt.plot(x,result,color='r',linewidth=3)
    plt.title("Covergence curve")
    plt.xlabel("generation")
    plt.ylabel("loss")
    plt.show()

其中,利用梯度下降法进行矩阵分解的过程中的收敛曲线如下所示:在这里插入图片描述
推荐的前10部电影及得分
在这里插入图片描述

  • 2
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值