LFM/funk-SVD

隐语义模型(LFM)

通过隐含特征(latent factor)联系用户兴趣和物品。比如给用户推荐图书的场景,隐含特征可以是图书的类别。通过降维的方法补全评分矩阵。

算法理论

用户 u u u对物品 i i i的兴趣
r ^ u i = p u T q i = ∑ k = 1 K p u , k q i , k \hat{r}_{ui}=p^T_u q_i=\sum\limits_{k=1}^K p_{u,k}q_{i,k} r^ui=puTqi=k=1Kpu,kqi,k
其中 p u , k p_{u,k} pu,k q i , k q_{i,k} qi,k是模型的参数, p u , k p_{u,k} pu,k度量用户 u u u的兴趣和第 k k k个隐类的关系, q i , k q_{i,k} qi,k度量第 k k k个隐类和物品 i i i的关系。
优化目标
C = ∑ u , i [ ( r u i − r ^ u i ) 2 + λ 1 ∣ ∣ p u ∣ ∣ 2 + λ 2 ∣ ∣ q i ∣ ∣ 2 ] = ∑ u , i [ ( r u i − ∑ k = 1 K p u , k q i , k ) 2 + λ 1 ∣ ∣ p u ∣ ∣ 2 + λ 2 ∣ ∣ q i ∣ ∣ 2 ] C=\sum\limits_{u,i}\Big[(r_{ui}-\hat{r}_{ui})^2+\lambda_1 ||p_u||^2+\lambda_2 ||q_i||^2\Big] \\=\sum\limits_{u,i}\Big[(r_{ui}-\sum\limits_{k=1}^K p_{u,k}q_{i,k})^2+\lambda_1 ||p_u||^2+\lambda_2 ||q_i||^2\Big] C=u,i[(ruir^ui)2+λ1pu2+λ2qi2]=u,i[(ruik=1Kpu,kqi,k)2+λ1pu2+λ2qi2]
利用梯度下降法迭代求解,得梯度如下
∂ C ∂ p u k = − 2 q i k ⋅ ( r u i − ∑ k = 1 K p u , k q i , k ) + 2 λ 1 p u k \frac{\partial C}{\partial p_{uk}}=-2q_{ik}\cdot (r_{ui}-\sum\limits_{k=1}^K p_{u,k}q_{i,k})+2\lambda_1 p_{uk} pukC=2qik(ruik=1Kpu,kqi,k)+2λ1puk
∂ C ∂ q i k = − 2 p u k ⋅ ( r u i − ∑ k = 1 K p u , k q i , k ) + 2 λ 2 q i k \frac{\partial C}{\partial q_{ik}}=-2p_{uk}\cdot (r_{ui}-\sum\limits_{k=1}^K p_{u,k}q_{i,k})+2\lambda_2 q_{ik} qikC=2puk(ruik=1Kpu,kqi,k)+2λ2qik
进而,有迭代更新公式
p u k ← p u k + α ( q i k ⋅ ( r u i − ∑ k = 1 K p u , k q i , k ) − λ 1 p u k ) p_{uk} \leftarrow p_{uk}+\alpha(q_{ik}\cdot (r_{ui}-\sum\limits_{k=1}^K p_{u,k}q_{i,k}) - \lambda_1 p_{uk}) pukpuk+α(qik(ruik=1Kpu,kqi,k)λ1puk)
q i k ← q i k + α ( p u k ⋅ ( r u i − ∑ k = 1 K p u , k q i , k ) − λ 2 q i k ) q_{ik} \leftarrow q_{ik}+\alpha(p_{uk}\cdot (r_{ui}-\sum\limits_{k=1}^K p_{u,k}q_{i,k}) - \lambda_2 q_{ik}) qikqik+α(puk(ruik=1Kpu,kqi,k)λ2qik)
其中 α \alpha α是学习率。

LFM模型的一些特性

(1)当数据集非常稀疏时,LFM的性能会下降,甚至不如user-based CF和item-based CF的性能。
(2)负正样本比例:对于隐性反馈数据集,即只有正样本(user like which item),没有负样本(user unlike which item),要想LFM解决TonN推荐,需要为每个用户生成负样本。一种比较好的做法是在一个用户没有过行为的物品中(热门却没用户行为),采样出一些物品作为负样本,采样时保证每个用户的正负样本数相当

LFM模型的改进版本

r ^ u i = μ + b u + b i + p u T ⋅ q i \hat{r}_{ui}=\mu+b_u+b_i+p^T_u\cdot q_i r^ui=μ+bu+bi+puTqi
其中 μ \mu μ是训练集中所有记录评分的全剧平均数, b u b_u bu是用户偏置项(用户的评分习惯和物品没有关系), b i b_i bi是物品偏置项(物品接受的评分中和用户没有什么关系的因素)。以上三个参数,只有 b u b_u bu b i b_i bi是模型需要学习的参数。

import random
import math
def InitLFM(datas, F):
    #初始化每个用户和每个物品的隐含层向量
    """
    :param datas: user-item matrix
    :param F: 隐语义层类别数
    :return: 初始化的user-item matrix隐语义分解的 user-隐语义矩阵 item-隐语义矩阵
    """
    p = dict()   #{用户id : 该用户对应的隐含层向量}
    q = dict()
    for u, i, rui in datas:
        if u not in p:
            p[u] = [random.random()/math.sqrt(F) for x in range(0,F)]
        if i not in q:
            q[i] = [random.random()/math.sqrt(F) for x in range(0,F)]
    return (p, q)
#test:
user_item = [('U_A','I_a',4.0),
             ('U_B','I_b',3.0),
             ('U_C','I_c',5.0),
             ('U_D','I_d',4.0),
             ('U_E','I_e',3.0)]
lfm_decompose = InitLFM(user_item, 3)
print(lfm_decompose)
#Output:
({'U_A': [0.0711747331462215, 0.2616227297093711, 0.4899385151289309], 
  'U_B': [0.555968449196184, 0.21855559641436223, 0.041509712538012535], 
  'U_C': [0.1052411630108121, 0.13275955981411028, 0.479097718394469], 
  'U_D': [0.15802706877290149, 0.017726990993899946, 0.36606267043759183],
  'U_E': [0.3321503428981605, 0.15044863198207514, 0.3359742839454751]}, 
{'I_a': [0.14004807384500936, 0.5378836451538328, 0.4501529686622375],
 'I_b': [0.1654725947133352, 0.09187293849635998, 0.3309355309148931],
 'I_c': [0.22693588447564933, 0.3399964380090505, 0.468304320741949],
 'I_d': [0.467540151256175, 0.4681798818717969, 0.0863588872230948],
 'I_e': [0.31334966195966957, 0.5064351119551628, 0.060277549670346375]})
import numpy as np
def Predict(u, i, p, q):
    #根据 user-隐语义矩阵 item-隐语义矩阵 还原user对item的预测分
    """
    :param u: user-id
    :param i: item-id
    :param p: user-隐语义矩阵
    :param q: item-隐语义矩阵
    :return: user对item的预测分
    """
    return np.dot(p[u], q[i])
#test:
all_compose=[]
for i in user_item:
    lfm_compose = Predict(i[0], i[1], lfm_decompose[0], lfm_decompose[1])
    all_compose.append(lfm_compose)
print(all_compose)
#Output:
[0.09034022111346175, 0.25724014106241055, 0.18898141649285463, 0.038779828218872214, 0.09510803928688424]
def LearningLFM(datas, F, n, alpha, lam):
    #LFM优化求 user-隐语义矩阵 item-隐语义矩阵 的过程
    """
    :param datas: user-item matrix
    :param F: 隐含层类别数
    :param n: 梯度更新迭代轮次
    :param alpha: 迭代步长
    :param lam: 正则化项系数
    :return: 优化后的分解矩阵
    """
    (p, q) = InitLFM(datas, F)
    for step in range(0, n):
        totalerror = 0.0
        for u, i, rui in datas:   #(用户id, 物品id, 得分)
            pui = Predict(u, i, p, q)   #LFM预测分
            eui = rui - pui
            totalerror += np.abs(eui)
            for k in range(F):
                p[u][k] += alpha * (q[i][k] * eui - lam * p[u][k])
                q[i][k] += alpha * (p[u][k] * eui - lam * q[i][k])
        #print(totalerror)
        alpha *= 0.9
    return (p, q)
#test:
LFM_matrix = LearningLFM(user_item, 2, 20, 0.25, 0.5)
print(LFM_matrix)
#Output:
({'U_A': [1.4556948719620124, 1.0808822320643687],
  'U_B': [0.34805247328789335, 1.506941524269859],
  'U_C': [1.4004162596465355, 1.0323917498743957],
  'U_D': [1.264866114649551, 1.3305433780548566],
  'U_E': [1.1725088890202162, 1.021494392658505]}, 
 {'I_a': [1.5405697795989084, 1.164920748249187],
  'I_b': [0.36288140741053504, 1.575764055732583],
  'I_c': [2.1107317430824186, 1.5407904238923547],
  'I_d': [1.3090775380908621, 1.3865900804605573],
  'I_e': [1.2029532096219022, 1.067316130809409]})
def Recommend(user, p, q):
    """
    :param user: user-id
    :param p: user-隐语义矩阵
    :param q: item-隐语义矩阵
    :return: 对user-id的LFM推荐排序列表
    """
    rank = dict()
    puf = p[user]
    for i, qif in q.items():
        if i not in rank:
            rank[i] = 0
        rank[i] += np.dot(puf, qif)
    return rank
#test:
print(Recommend('U_A', LFM_matrix[0], LFM_matrix[1]))
#Output:
{'I_a': 3.5010760116000625, 
 'I_b': 2.855107643198207, 
 'I_c': 3.3870812532757943, 
 'I_d': 3.1630603878656465, 
 'I_e': 2.8016187845189524}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值