前言

推荐系统中最为主流与经典的技术之一是协同过滤技术(Collaborative Filtering),
它是基于这样的假设:用户如果在过去对某些项目产生过兴趣,那么将来他很可能依然对其保持热忱。
目前推荐系统中用的最多的就是矩阵分解(Matrix Factorization)方法。
矩阵分解就是预测出评分矩阵中的缺失值,然后根据预测值以某种方式向用户推荐。
矩阵分解可以解决一些近邻模型无法解决的问题,近邻模型存在的问题:
1、物品之间存在相关性,信息量并不是随着向量维度增加而线性增加
2、矩阵元素稀疏,计算结果不稳定,增减一个向量维度,导致紧邻结果差异很大的情况出现。
这里以用户-项目评分为例来详解矩阵分解。

一、矩阵分解

1.案例

用户-项目评分矩阵R(M×N)

打分矩阵R(n,m)是n行m列,n表示user个数,m表示item个数,‘-’表示用户没有打分

python拆分矩阵列 python 矩阵分解_矩阵分解

2.思路

矩阵分解就是把大矩阵分解成两个小矩阵,
即矩阵R可近似表示为矩阵P与矩阵Q的乘积:
python拆分矩阵列 python 矩阵分解_矩阵分解_02
矩阵P(n,k)表示n个user和K个特征之间的关系矩阵,将矩阵Q(m,k)表示m个item和K个特征之间的关系矩阵,
接下来就是要求的矩阵P和Q,即可的预测矩阵R

3.推导步骤

  1. 首先:
    python拆分矩阵列 python 矩阵分解_损失函数_03
  2. 损失函数:
    python拆分矩阵列 python 矩阵分解_损失函数_04
  3. 对损失函数加入正则项:
    为了防止过拟合
    加入正则L2范数的损失函数为:
    python拆分矩阵列 python 矩阵分解_python拆分矩阵列_05
  4. 使用梯度下降法更新p和q分量:
  • 求解损失函数的负梯度:

python拆分矩阵列 python 矩阵分解_损失函数_06

python拆分矩阵列 python 矩阵分解_矩阵分解_07

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

python拆分矩阵列 python 矩阵分解_python拆分矩阵列_08

python拆分矩阵列 python 矩阵分解_推荐系统_09

  1. 不停迭代,直到损失函数<=阈值;
  2. 对结果的输出:
    输出得到的预测矩阵python拆分矩阵列 python 矩阵分解_python拆分矩阵列_10;
    可对预测矩阵可视化,或转成表格也行;
    可输出个学习效率图像。

二、python代码实例

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

def MF(R,P,Q,K,steps=5000,alpha=0.0002,beta=0.02):
    #矩阵因子分解函数,
    #steps:迭代次数,alpha:步长
    n,m = R.shape    #R矩阵行,列
    result = []
    for step in range(steps):
        #进行迭代
        for i in range(n):
            for j in range(m):
                eij = R[i][j] - np.dot(P[i,:],Q[:,j])   #.dot表矩阵乘
                for k in range(K):
                    #更新参数
                    if R[i][j] != 0:     #限制评分不为0,即预测评分
                        P[i][k] += alpha*(2*eij*Q[k][j] - beta*P[i][k])
                        Q[k][j] += alpha*(2*eij*P[i][k] - beta*Q[k][j])
        eR = np.dot(P,Q)
        e = 0   #误差
        #求损失函数:
        for i in range(n):
            for j in range(m):
                if R[i][j] != 0:
                    e += pow(R[i][j]-np.dot(P[i,:],Q[:,j]),2)
                    #加入正则化
                    for k in range(K):
                        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

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 = np.array(R)
    N,M = R.shape    #获取原矩阵的行列
    K = 3   #k值可根据需求改变
    P = np.random.rand(N,K)
    Q = np.random.rand(K,M)
    nP,nQ,result = MF(R, P, Q, K)
    print(R)
    R_MF = np.dot(nP,nQ)
    print(R_MF)
    plt.plot(range(len(result)),result)    #学习效率
    plt.show()

输出:

[[5 3 0 1]
 [4 0 0 1]
 [1 1 0 5]
 [1 0 0 4]
 [0 1 5 4]]
[[4.98721783 2.95625121 3.57560418 1.00024006]
 [3.9709488  2.24242023 3.11559738 0.99765797]
 [1.04748953 0.88624237 5.33748545 4.96558301]
 [0.97508183 0.74294582 4.37299881 3.97589923]
 [1.84618381 1.13400265 4.94201315 4.01873275]]

python拆分矩阵列 python 矩阵分解_推荐系统_11