# 隐语义模型(LFM)

隐语义模型来进行协同过滤,揭示隐藏的特征,这些特征解释为什么给出对应的评分,这类特征可能是无法直接用语言解释的

通过矩阵分解降维分析,协同过滤算法非常依赖历史数据,而在一般的推荐系统中,偏好数据又往往是稀疏的,这需要对原始数据做降维处理,分解后的矩阵,代表了用户和物品的隐藏特征

  • 基于概率的隐语义分析(pLSA)
  • 隐dilikelei分布(LDA)
  • 矩阵因子分解模型(SVD)

# LFM降维方法——矩阵因子分解

假设用户评分矩阵为R,现在有m个用户,n个物品

想要发现k个隐类,现在的任务是找到两个矩阵P和Q,使得两个矩阵的乘积近似等于R,即将用户评分矩阵分解为两个低维矩阵相乘

Rmn=PmkTQknR_{m*n} = P^{T}_{m*k}*Q_{k*n}

# LFM的进一步理解

可以认为,用户给电影打分,是有内在原因的,可以挖掘出影响用户打分的隐藏因素,进而根据未评分电影与这些隐藏因素的关联程度,决定未评分电影的预测评分

应该有一些隐藏因素,比如电影的演员、题材、年代等等,或者一些人无法直接理解的隐藏因子

找到隐藏因子,就可以对user和item进行关联,对用户的喜好进行推测

# 梯度下降实现

# LFM梯度下降实现
import numpy as np
import pandas as pd

### 1. 准备数据
# 评分矩阵
R = np.array([[4,0,2,0,1],
              [0,2,3,0,0],
              [1,0,2,4,0],
              [5,0,0,3,1],
              [0,0,1,5,1],
              [0,3,2,4,1]])
#
# print(R.shape)

### 2. LFM梯度下降
def lfm(R, K, steps, alpha, lamb):
    """
    :param R: 评分矩阵MxN, M个user,N个物品
    :param K: 隐特征向量维度
    :param steps: 最大迭代步数
    :param alpha: 步长
    :param lamb: 正则化系数
    :return: P初始化用户特征矩阵MxK,Q初始化物品特征矩阵NxK, cost损失
    """
    M, N = R.shape
    P = np.random.rand(M,K)  # 随机给初始
    Q = np.random.rand(N,K)
    Q = Q.T
    
    for step in range(steps):
        # 对所有用户U,物品I遍历,对应的特征向量P,Q梯度下降
        for u in range(M):
            for i in range(N):
                # 对于有评分的,才求出评分误差
                if R[u][i] != 0:
                    eui = np.dot(P[u,:], Q[:,i]) - R[u][i]
                    # 按照梯度下降算法更新Pu和Qi
                    for k in range(K):
                        P[u][k] = P[u][k] - alpha * ( 2 * eui * Q[k][i] + 2* lamb * P[u][k])
                        Q[k][i] = Q[k][i] - alpha * ( 2 * eui * P[u][k] + 2* lamb * Q[k][i])
    
        cost = 0
        for u in range(M):
            for i in range(N):
                if R[u][i] != 0:
                    cost += (np.dot(P[u,:], Q[:,i]) - R[u][i]) ** 2
                    # 加上正则化项
                    for k in range(K):
                        cost += lamb*(P[u][k]**2 + Q[k][i]**2)
        if cost < 0.0001:
            break
        print("第%s次迭代,cost:%s" % (step, cost))
        
    return P, Q.T, cost

K = 10
step = 5000
alpha = 0.0002
lamb = 0.004

P, Q, cost = lfm(R, K, step, alpha, lamb)
pred_R = np.dot(P, Q.T)
print(pred_R)

预测结果