推荐系统——矩阵分解MF

目录

矩阵分解针对的问题

MF的解决思路

预测函数

损失函数

优化目标

梯度下降

对加上正则项的损失函数求偏导

按照梯度方向对变量进行更新

进行迭代,直到达到迭代次数或损失函数小于规定的阈值

代码

结果

附——正则化

矩阵分解针对的问题

以电影评分为例,通常将用户和电影构造成一个矩阵,矩阵中每一个元素表示用户对电影的评分,分数越高表明该用户对电影喜爱程度越高,用?表示缺失值。但在实际场景中,相比于电影数量,大部分用户都未对电影进行评分,所以实际中矩阵一定为稀疏矩阵。而协同过滤处理稀疏矩阵的能力比较弱,并且协同过滤对于上述矩阵的维护难度较大,由此提出了矩阵分解(MF)。

MF的解决思路

将矩阵R分解成用户矩阵、物品矩阵两个矩阵相乘的形式,即R\approx P\times Q。假设矩阵R为m\times n的矩阵,则将其分解为矩阵P(m\times k)和矩阵Q(k\times n)P_{m\times k}\times Q_{k\times n}\approx R_{m\times n}。其中,k为隐向量的维度,k越大,用户的喜好和物品的划分就越准确。

预测函数

Preference(P,Q)=\hat{r_{pq}}=p_{i}q_{j}^{T}=\sum_{i=1}^{k}p_{ik}q_{kj}

损失函数

用户p对物品q的预测评分为\hat{r_{pq}}=p_{i}q_{j}^{T},所以真实值与预测值之间的误差为\bigtriangleup r=r_{pq}-\hat{r_{pq}},所以我们用误差平方和来定义损失函数,可得

loss=SSE=\sum_{p,q}^{}e_{pq}^{2}=\sum_{p,q}(r_{pq}-\sum_{k=1}^{K}p_{ik}q_{kj})^{2}

优化目标

如果预测越准确,那么上述误差值\left | \left | \bigtriangleup r \right | \right |越小,所以,怎样使\bigtriangleup r最小就成立一个优化问题。

\underset{p^{*}q^{*}}{min}\sum (r_{ui}-p_iq_j)^{2}+\lambda (\left | \left | p \right | \right |^{2}+\left | \left | q \right | \right |^{2})\sum (r_{ui}-p_iq_j)^{2}为损失函数,\lambda (\left | \left | p \right | \right |^{2}+\left | \left | q \right | \right |^{2})为正则化项。

梯度下降

  • 对加上正则项的损失函数求偏导

\frac{\partial L^{2}}{\partial p_{ik}}=-2L_{ij}q_{kj}+\lambda \sum_{k=1}^{k}p_{ik}

\frac{\partial L^{2}}{\partial q_{kj}}=-2L_{ij}p_{ik}+\lambda \sum_{k=1}^{k}q_{kj}

  • 按照梯度方向对变量进行更新

p_{ik}^{'}=p_{ik}-\alpha \frac{\partial L^{2}}{\partial p_{ik}}=p_{ik}+2\alpha Lq_{kj}-\lambda p_{ik}

q_{kj}^{'}=q_{kj}-\alpha \frac{\partial L^{2}}{\partial q_{kj}}=q_{kj}+2\alpha Lp_{ik}-\lambda q_{kj}

  • 进行迭代,直到达到迭代次数或损失函数小于规定的阈值

代码

# -*- coding: utf-8 -*-
from math import *
import  numpy as np
import matplotlib.pyplot as plt
#调用math、numpy、matplotlib库

def MF(R,P,Q,K,aplha,beta,steps):
    '''
    :param R: 用户-物品评分矩阵 m*n
    :param P: 用户的分解矩阵 m*k
    :param Q: 物品的分解矩阵 k*n
    :param K: 隐向量的维度
    :param aplha: 学习率
    :param beta: 正则化参数 
    '''
    print('开始分解原矩阵')
    Q=Q.T
    result=[]
    #开始训练  更新参数 计算损失值
    #更新参数 使用梯度下降方法
    print('开始训练')
    for step in range(steps):#训练次数
        ''''''
        for i in range(len(R)):
            for j in range(len(R[i])):
                eij=R[i][j]-np.dot(P[i,:],Q[:,j])#eij
                for k in range(K):#隐向量维度
                    if R[i][j]>0:
                        #梯度下降法更新参数
                        P[i][k]=P[i][k]+aplha*(2*eij*Q[k][j]-beta*P[i][k])
                        Q[k][j]=Q[k][j]+aplha*(2*eij*P[i][k]-beta*Q[k][j])
        eR=np.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] - 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
    print('training Finshed 。。。。')

    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]
    ]#未进行评分用0表示
    R=np.array(R)
    N=len(R)    #原矩阵R的行数
    M=len(R[0]) #原矩阵R的列数
    K=3    #K值可根据需求改变
    P=np.random.rand(N,K) #随机生成一个 N行 K列的矩阵
    Q=np.random.rand(M,K) #随机生成一个 M行 K列的矩阵
    nP,nQ,result=MF(R,P,Q,K,aplha=0.0002,beta=0.02,steps=5000)
    print(result)
    print('原矩阵',R)         #输出原矩阵
    R_MF=np.dot(nP,nQ.T)
    print('计算出的矩阵',R_MF)      #输出新矩阵
    #画图
    plt.plot(range(len(result)),result)
    plt.xlabel("time")
    plt.ylabel("loss")
    plt.show()

结果

附——正则化

正则化防止过拟合

所谓过拟合,就是过分的拟合了样本数据,造成引入了大量的噪音,无法呈现原本的规律。而我们又无法针对特殊的样本数据进行剔除,所以干脆对所有的参数加入随机因子,即正则项。正则化是降低过拟合问题的常见手段,关于过拟合说明如图:

图一是欠拟合,对样品的拟合程度过于简单,图二是刚好理想的拟合情况,图三就是过拟合,过度的拟合了噪音,导致无法很好的表示出整体规律。 ——正则化详见:http://t.csdn.cn/IQ1So

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值