矩阵分解——梯度下降

矩阵分解——梯度下降法

场景

  当然是推荐系统了。
  假设有四部电影,有五个人看了其中的几部,对其打了分数(实际情况是一部电影有四个侧重方向,也就是因子):在这里插入图片描述   我们的目标就是预测出“-”位置对应的分值,这样就可以通过用户“可能”的喜欢程度,将分值最高的推荐给用户。
  通过矩阵分解,可以把 R 分解成两个矩阵的乘积: R ( n , m ) = P ( n , k ) ∗ Q ( k , m ) R(n,m)=P(n,k)*Q(k,m) R(n,m)=P(n,k)Q(k,m) 。也就是把高维的矩阵分解成两个低维的矩阵。
  矩阵 P ( n , k ) P(n,k) P(n,k)表示n个用户和k个特征之间的关系矩阵,这k个特征是一个中间变量,矩阵 Q ( k , m ) Q(k,m) Q(k,m)的转置是矩阵 Q ( m , k ) Q(m,k) Q(m,k),矩阵 Q ( m , K ) Q(m,K) Q(m,K)表示m个对象和k个特征之间的关系矩阵,其中k需要手动调节。当然,这只是近似,通过不断调整P与Q的值,让他们的乘积 R ^ \hat R R^ 越来越接近 R R R ,这就是梯度下降进行矩阵分解的过程。

相关函数

1. 目标函数
假设用户的真实评分与预测之间的差值服从高斯分布,令 R ^ = ∑ k = 0 K p i k q k j \hat R=\sum_{k=0}^K p_{ik}q_{kj} R^=k=0Kpikqkj
2. 损失函数——Loss Function
  损失函数(loss function)是用来估量模型的预测值f(x)与真实值S的不一致程度。因为e对 p i k p_{ik} pik q k j q_{kj} qkj都是凸函数,我们可以用平方损失函数:
  首先令 R ^ = ∑ k = 0 K p i k q k j \hat R=\sum_{k=0}^K p_{ik}q_{kj} R^=k=0Kpikqkj

  设 e ^ = ( R i j − R ^ i j ) 2 = ( r i j − ∑ k = 1 K p i k q k j ) 2 \hat e= (R_{ij}-\hat R_{ij})^2=(r_{ij}-\sum_{k=1}^Kp_{ik}q_{kj})^2 e^=(RijR^ij)2=(rijk=1Kpikqkj)2
  在 R i j R_{ij} Rij已知的情况下, e ^ \hat e e^即为我们构建的损失函数,最后需要求出的为所有非“-”项的loss和的最小值,即 m i n   l o s s = ∑ R i j ! = ‘ − ’ n e i j 2 min\ loss=\sum_{R_{ij}!=‘-’}^n e_{ij}^2 min loss=Rij!=neij2

梯度下降求解

现在我们有了损失函数,就可以求出各个变量的负梯度(求偏导):
在这里插入图片描述
接下来根据梯度方向,更新变量:在这里插入图片描述
这里 α \alpha α为步长,根据数据集的大小拟定。
  上面就是用户因子和项目因子的更新公式,迭代更新公式即可找到可接受的局部最优解。其实负梯度的负方向,当函数是凸函数时是函数值减小的方向走;当函数是凹函数时是往函数值增大的方向移动。而矩阵分解的目标函数L是凸函数,因此,通过梯度下降法我们能够得到目标函数L的极小值(理想情况是最小值)。

PS: 矩阵分解还有许多其他的方法,如特征值分解与奇异值分解,在此不多赘述。

过拟合

  有时Loss函数会得到0的结果,表面上效果很好,但是在用户数据中表现并不好,模型需要顾忌每一个点,最终形成的拟合函数波动很大。在某些很小的区间里,函数值的变化很剧烈。这就意味着函数在某些小区间里的导数值(绝对值)非常大,当用户-项目评分矩阵R非常稀疏时,就会出现过拟合 (overfitting) 的问题,过拟合问题的解决方法就是正则化 (regularization)
引入正则化项后目标函数变为:

     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 i j 2 ) e_{ij}^2 =(R_{ij}-\sum_{k=1}^Kp_{ik}q_{kj})^2+ \frac\beta{2}\sum_{k=1}^K(p_{ik}^2+q_{ij}^2) eij2=(Rijk=1Kpikqkj)2+2βk=1K(pik2+qij2)

之后再对其进行梯度下降,最后得到:
在这里插入图片描述

关于正则化防止过拟合:

解决过拟合的方式(一):正则化

代码

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


def matrix_factorization(R,P,Q,K,steps=5000,alpha=0.0002,Lambda=0.02):
    result=[]
    for step in range(steps):
        for i in range(len(R)):
            for j in range(len(R[i])):
                if R[i][j]>0:
                    eij=R[i][j]-np.dot(P[i,:],Q[:,j])        #乘法运算
                    for k in range(K):
                        P[i][k]=P[i][k]+alpha*(2*eij*Q[k][j]-Lambda*P[i][k])
                        Q[k][j]=Q[k][j]+alpha*(2*eij*P[i][k]-Lambda*Q[k][j])
        eR=np.dot(P,Q)
        e=0                      #e即为损失函数
        for i in range(len(R)):
            for j in range(len(R[i])):
                if R[i][j]>0:
                    e=e+pow(R[i][j]-eR[i][j],2)    #只对已评分的元素求损失函数
        result.append(e)
        if e<0.001:            #若损失函数小于阈值,则跳出for循环,否则继续进行上述过程
            break
    return P,Q,result


if __name__ == '__main__':
    R=[
        [5,3,0,1,0],
        [4,0,0,1,2],
        [1,1,0,5,0],
        [1,0,0,4,5],
        [0,1,5,4,3],
        [3,0,2,1,0]
    ]

    R = np.array(R)
    M = len(R)
    N = len(R[0])
    K = 3
    P = np.random.rand(M, K)  # 随机生成一个 M行 K列的矩阵
    Q = np.random.rand(K, N)  # 随机生成一个 K行 N列的矩阵
    nP, nQ, result = matrix_factorization(R, P, Q, K)
    print("原始的评分矩阵R为:\n", R)
    R_MF = np.dot(nP, nQ)
    print("经过MF算法填充0处评分值后的评分矩阵R_MF为:\n", R_MF)
    n = len(result)
    x = range(n)
    plt.plot(x, result, color='r', linewidth=3)
    plt.title("Convergence curve")
    plt.xlabel("generation")
    plt.ylabel("loss")
    plt.show()
  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值