微信公众号:大数据左右手
专注于大数据技术,人工智能和编程语言
个人既可码代码也可以码文字。欢迎转发与关注
关注我,在公众号回复 “机器学习” 可领取电子书

###什么是隐语义模型LFM
协同过滤算法主要包括基于用户的协同过滤(User-Based CF)、基于物品的协同过滤(Item-Based CF)、隐语义模型(Latent Factor Model)等。其中基于用户和物品的协同过滤是通过统计学方法对数据进行分析的,因此也称为基于内存的协同过滤或基于邻域的协同过滤;隐语义模型是采用机器学习等算法,通过学习数据得出模型,然后根据模型进行预测和推荐,是基于模型的协同过滤

该算法最早在文本领域被提出,用于找到文本的隐含语义。核心思想是通过隐含特征(latent factor)联系用户兴趣和物品(item)。是基于机器学习的方法。找出潜在的主题和分类。基于用户的行为对item进行自动聚类,划分到不同类别/主题,即用户的兴趣。
###简介
这种算法的思想是这样的:每个用户都有自己的爱好和看新闻文字或者视频的习惯,比如用户A喜欢军事类的,打仗的,李云龙等等这些标签,如果这个短视频带有这些元素,那么就将这段短视频推荐给该用户,也就死用这些元素标签去连接用户和短视频作品。每个人对不同的元素偏好不同,而每一个短视频包含的元素也不相同,于是就有了这样的分析:

  • 用户潜在因子矩阵
    表示不同用户对于不同元素的偏好程度,1.代表绝对喜欢,0.代表不喜欢,如表举例
军事 娱乐 时政 历史 李云龙
用户A 0.7 0.3 0.4 0.8 0.8
用户B 0.8 0.4 0.6 0.7 0.1
用户C 0.5 0.6 0.7 0.3 0.3
  • 短视频潜在矩阵
    表示每种视频包含各种元素的成分
军事 娱乐 时政 历史 李云龙
视频A 0.8 0 0.4 0.8 1
视频B 0 0.8 0 0.7 0
视频C 0.5 0 0.7 0.6 0

利用这两个矩阵,我们可以算出用户A对视频A的喜欢程度
用户A对军事的偏好 * 视频1含有军事成分 + …(一次类推相乘相加)
即为:0.7 * 0.8+0.3 * 0+0.4 * 0.4+0.8 * 0.8+0.8 * 1=2.16

军事 娱乐 时政 历史 李云龙
用户A 0.7 0.3 0.4 0.8 0.8
视频A 0.8 0 0.4 0.8 1

按照上面的可以计算出

视频A 视频B 视频C
用户A 2.16 0.8 1.11
用户B 1.13 0.81 1.24
用户C 1.16 0.69 1.02

因此:我们推荐用户A的短视频是A,对用户B推荐的对视频是B,对用户C推荐的短视频是A

  • 这些潜在因子是怎么到来的呢
    一方面的用户在进入App的时候进行标签的勾选。二是用户的行为数据得出来的分析
    我举个例子吧,不是太准确,这个还是看公司的业务需求,比如短视频看完+5,看一半+3,收藏+3,跳过-2,拉黑-5等等的标准,比如这样的实例
视频A 视频B 视频C
用户A 5 3 -2
用户B 3 -5 5
用户C -2 3 -5

然后再根据系统对这条视频进行分类或者什么手段产生因子,根据第二步的实例可以算出用户对某视频的喜欢程度,这样就可以推荐了

###数学算法

LFM算法从数据集中抽取出若干主题,作为user和item之间连接的桥梁,将R矩阵表示为P矩阵和Q矩阵相乘。其中P矩阵是user-class矩阵,矩阵值Pij表示的是user i对class j的兴趣度;Q矩阵式class-item矩阵,矩阵值Qij表示的是item j在class i中的权重,权重越高越能作为该类的代表。所以LFM根据如下公式来计算用户U对物品I的兴趣度:

那么,接下去的问题就是如何计算矩阵P和矩阵Q中参数值。一般做法就是最优化损失函数来求参数。在定义损失函数之前,我们需要准备一下数据集并对兴趣度的取值做一说明。
  数据集应该包含所有的user和他们有过行为的(也就是喜欢)的item。所有的这些item构成了一个item全集。对于每个user来说,我们把他有过行为的item称为正样本,规定兴趣度RUI=1,此外我们还需要从item全集中随机抽样,选取与正样本数量相当的样本作为负样本,规定兴趣度为RUI=0。因此,兴趣的取值范围为[0,1]。
采样之后原有的数据集得到扩充,得到一个新的user-item集K={(U,I)},其中如果(U,I)是正样本,则RUI=1,否则RUI=0。损失函数如下所示:

为了最小化上面的损失函数,我们采取随机梯度下降算法,它首先通过求参数的偏导数找到最速下降方向,然后通过迭代法不断地优化参数

  • 通过求参数Pu,k的偏导确定最快的下降方向
    -
  • 迭代计算不断优化参数(迭代次数事先人为设置),直到参数收敛


    当估算出P和Q矩阵后,我们就可以使用最开始的公式计算用户U对各个item的兴趣度值,并将兴趣度值最高的N个item(根据业务来)推荐给用户。

LFM中,重要的参数有4个:(代码实例中可以体现)

  1. 隐特征的个数F
  2. 学习速率alpha
  3. 正则化参数lambda
  4. 负样本/正样本比例ratio
    其中,ratio参数对LFM的性能影响最大

代码实例

1. 引入依赖

import numpy as np
import pandas as pd

2. 数据准备

# 评分矩阵R
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],])
len(R[0])

**输出效果:5

3. 算法实现

"""
@输入参数:
R:M*N 的评分矩阵
K:隐特征向量维度
max_iter: 最大迭代次数
alpha:步长
lamda:正则化系数

@输出:
分解之后的 P,Q
P:初始化用户特征矩阵M*K
Q:初始化物品特征矩阵N*K
"""

# 给定超参数

K = 5
max_iter = 5000
alpha = 0.0002
lamda = 0.004

# 核心算法
def LFM_grad_desc( R, K=2, max_iter=1000, alpha=0.0001, lamda=0.002 ):
    # 基本维度参数定义
    M = len(R)
    N = len(R[0])
    
    # P,Q初始值,随机生成
    P = np.random.rand(M, K)
    Q = np.random.rand(N, K)
    Q = Q.T
    
    # 开始迭代
    for step in range(max_iter):
        # 对所有的用户u、物品i做遍历,对应的特征向量Pu、Qi梯度下降
        for u in range(M):
            for i in range(N):
                # 对于每一个大于0的评分,求出预测评分误差
                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 * lamda * P[u][k] )
                        Q[k][i] = Q[k][i] - alpha * ( 2 * eui * P[u][k] + 2 * lamda * Q[k][i] )
        
        # u、i遍历完成,所有特征向量更新完成,可以得到P、Q,可以计算预测评分矩阵
        predR = np.dot( P, Q )
        
        # 计算当前损失函数
        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 += lamda * ( P[u][k] ** 2 + Q[k][i] ** 2 )
        if cost < 0.0001:
            break
        
    return P, Q.T, cost


4. 测试

P, Q, cost = LFM_grad_desc(R, K, max_iter, alpha, lamda)

print(P)
print(Q)
print(cost)

predR = P.dot(Q.T)

print(R)
predR

输出效果
P:
[[ 0.3830611 0.82850065 0.82023839 0.52119365 1.07831816]
[ 0.30047264 1.61805241 0.44803691 0.18957273 0.69562221]
[ 0.5089245 1.15974588 0.28690078 1.15027101 -0.37415904]
[ 0.32906774 0.80254889 0.99686519 0.22888021 1.54492518]
[ 1.33431509 0.33140111 0.74692304 1.149386 0.48054638]
[ 0.56541894 0.7369649 1.00561082 0.74870477 1.12564774]]
Q:
[[ 0.4798044 0.92225918 1.07482479 0.10285196 1.94418819]
[ 0.20864097 0.47978933 1.07255543 0.48634109 0.91665161]
[-0.15978907 1.57366588 0.46409477 0.18390879 0.29599675]
[ 1.49743967 1.06857301 0.64402246 1.7015778 0.39911779]
[ 0.32778316 0.45598072 -0.24798659 0.34891638 0.44123607]]
cost:
0.5421902087209758
R:
[[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]]
predR:
array([[3.97955851, 2.59909912, 2.03827334, 3.30440379, 0.95757906],
[3.48991137, 2.04939982, 2.94695921, 3.06770057, 1.09826208],
[1.01301061, 1.18678376, 1.97767619, 3.99406951, 0.86074703],
[4.99666771, 3.05037658, 2.17238821, 2.99840935, 0.98813726],
[2.80114856, 2.23799913, 1.00857109, 4.98078217, 1.01632564],
[4.29729537, 2.9460835 , 2.00696893, 4.00506296, 1.02991035]])

###算法存在的缺点

  1. 数据稀疏会导致性能降低
  2. 不能在线实时推荐。因为LFM在生成推荐列表时速度太慢。
  3. 不能给出推荐解释。因为LFM计算的是各个隐类,但每个类别不会自动生成这个类的类别标签。

至此,隐语义模型LFM介绍完了

机器学习未完待续 ……欢迎关注

微信公众号:大数据左右手
人要去的地方,除了远方,还有未来
欢迎关注我,一起学习,一起进步!
关注我,在公众号回复 “机器学习” 可领取电子书