矩阵分解学习总结+python代码

矩阵分解常作为推荐系统中一个比较常用的方法,在传统的svd分解中,矩阵分解是把一个
R m × n = M m × m Σ U n × n T R_{m×n}=M_{m\times m}\Sigma U_{n\times n}^{T} Rm×n=Mm×mΣUn×nT
对于M矩阵来说是 R R T RR^T RRT ,而对于N是 R T R R^TR RTR 的特征向量。
但是R为稀疏矩阵(因为在用户的矩阵中部分用户对于部分物品是没有评分的,也就是矩阵元素为0),这也就意味着 R T R R^TR RTR 是不存在的,同样R乘以R的转置也不存在。所以这里就需要新的方法来处理这个问题。当然我们可以使用每行的平均值来填充空的元素,这一看起来比较合理的方法。不过这样会导致结果会有很大的偏见,所以不建议使用。
后来simon Funk就提出了一种分解方法,Funk mf,也就是我们日常所使用的mf。及利用中间变量来降维从而使得矩阵可分

R m × n = P m × k Q n × k T R_{m \times n}=P_{m \times k}Q_{n \times k}^T Rm×n=Pm×kQn×kT

这里的P和Q矩阵分别是用户u-中间矩阵,和物品矩阵,上面的模型也被称为隐含语义模型,或者叫做隐式反馈。
那么就得出预测矩阵

R ˉ = P × Q \bar{R}=P\times Q Rˉ=P×Q
有了预测矩阵,那么就可以想到梯度下降来求解最优参数了,于是:

S S E = ( R − R ˉ ) 2 = ( R − p × q ) 2 SSE=(R-\bar{R})^2=(R-p\times q)^2 SSE=RRˉ2=(Rp×q)2

对sse求导得:

∂ S S E ∂ P u = − 2 Q i ( R − P u × Q i ) \frac{\partial SSE}{\partial{P_u}}=-2Q_i(R-P_u\times Qi) PuSSE=2Qi(RPu×Qi)

∂ S S E ∂ Q i = − 2 P u ( R − P u × Q i ) \frac{\partial{SSE}}{\partial{Q_i}}=-2P_u(R-P_u\times Qi) QiSSE=2Pu(RPu×Qi)
但是,这里还有个问题,过拟合问题,所以为了防止过拟合问题,这里添加了L2正则项来避免这个问题。
sse式子就变为:

S S E = ( R − ∑ k = 1 K P u k Q k i ) 2 + β / 2 ​ ∑ k = 1 K ​ ( ∣ ∣ P ∣ ∣ 2 + ∣ ∣ Q ∣ ∣ 2 ) SSE=(R-\sum_{k=1}^K P_{uk} Q_{ki})^2+\beta/2\!\sum_{k=1}^K\!(||P||^2+||Q||^2) SSE=(Rk=1KPukQki)2+β/2k=1K(P2+Q2)
求导得:

∂ S S E ∂ P u = α ( 2 e u i Q i − β P u ) \frac{\partial{SSE}}{\partial P_u}=\alpha(2e_{ui}Q_{i}-\beta P_{u}) PuSSE=α(2euiQiβPu)

∂ S S E ∂ Q i = α ( 2 e u i P u − β Q i ) \frac{\partial{SSE}}{\partial Q_{i}}=\alpha(2e_{ui}P_{u}-\beta Q_{i}) QiSSE=α(2euiPuβQi)
其中eui 表示的是对SSE开根
打完收工;
下面放上python代码

#矩阵分解在打分预估系统中得到了成熟的发展和应用
# from pylab import *
import matplotlib.pyplot as plt
from math import pow
import numpy


def matrix_factorization(R,P,Q,K,steps=5000,alpha=0.0002,beta=0.02):
    Q=Q.T  # .T操作表示矩阵的转置
    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]-numpy.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=numpy.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]-numpy.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.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]
    ]

    R=numpy.array(R)

    N=len(R)
    M=len(R[0])
    K=2

    P=numpy.random.rand(N,K) #随机生成一个 N行 K列的矩阵
    Q=numpy.random.rand(M,K) #随机生成一个 M行 K列的矩阵

    nP,nQ,result=matrix_factorization(R,P,Q,K)
    print("原始的评分矩阵R为:\n",R)
    R_MF=numpy.dot(nP,nQ.T)
    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()

但是,说一千道一万,我们只是预测了用户的偏好程度,也就是基于概率来求出了用户可能的评分,并不是预测行为。那么如果用户在对某一个物品的评分不是你所预测的分数(好比你预测用户会打5分,结果用户只打了1分)。这种情况应该怎么办喃?

你可能感兴趣的:(AI)