目录
1.推荐系统介绍
最近在看《深度学习推荐系统》这本书,将记录学习过程。推荐系统的定义这里不过多阐述,只从两个角度来阐述推荐系统的意义所在。从用户的角度来看,推荐系统在“信息过载”的情况下,协助用户高效获得感兴趣信息。从公司的角度来看,推荐系统解决产品能够最大限度地吸引用户、留存用户、增加用户粘性、提高用户转化率的问题,从而达到公司商业目标连续增长。
1.1推荐系统的逻辑架构
推荐系统处理的是“人”和“信息”的关系。这里的信息主要指的是“商品信息”,在视频推荐中指的是“视频信息”,在新闻推荐中指的是“新闻信息”,简而言之,可统称为“物品信息”。而从人的角度出发,为了更可靠推测出“人”的兴趣点,推荐系统希望利用大量与“人”相关的信息,包括历史行为、人口属性、关系网络等,这些课统称为“用户信息”。此外在具体的推荐场景中,用户的最终选择一般会受时间、地点、用户的状态等一系列环境信息的影响,可称为“场景信息”或“上下文信息”。
在获知“用户信息”“物品信息”“场景信息”的基础上,推荐系统要处理的问题可以较形式地定义为:对于用户U,在特定场景C下,针对海量的“物品”信息,构建一个函数f(U,I,C),预测用户对特定候选物品I的喜好程度。其逻辑框架如下:
1.2推荐系统的技术框架
推荐系统的具体实现可以分为数据和模型两个部分。其中数据部分主要负责“用户”“物品”“场景”的信息收集与处理。具体讲,将负责数据收集与处理的三种平台按照实时性强弱排序,依次为“客户端及其服务器端实时数据处理”“流处理平台准实时数据处理”“大数据平台离线数据处理”。在实时性由若到强递减的同时,三种平台的海量数据处理能力则由弱到强。
模型部分有召回层、排序层以及补充策略与算法层组成。其中召回层一般利用高效的召回规则、算法或简单的模型,快速从海量的候选集中召回用户感兴趣的物品。排序层利用排序模型对初筛的候选集进行精排序。补充策略与算法层将推荐列表返回用户之前,为兼顾结果的“多样性”“流行度”“新鲜度”等指标,结合一些补充的策略和算法对推荐列表进行一定的调整,最终形成用户可见的推荐列表。后面所讲算法均为推荐系统的排序模型所用。
2.协同过滤算法
协同过滤算法核心思想:物以类聚,人以群分。也因此分别有着基于用户相似度的协同过滤推荐算法(UserCF)以及基于物品相似度的协同过滤推荐算法,以下将分别介绍。首先给出一张共现矩阵表,其包含了4个用户对5种商品的评分以及新用户Adam。
物品1 | 物品2 | 物品3 | 物品4 | 物品5 | |
用户1 | 3 | 1 | 2 | 3 | 3 |
用户2 | 4 | 3 | 4 | 3 | 5 |
用户3 | 3 | 3 | 1 | 5 | 4 |
用户4 | 1 | 5 | 5 | 2 | 1 |
Adam | 5 | 3 | 4 | 4 | ? |
2.1相似度计算
从行看,每个用户可以表示成一个行向量,从列看,每个商品可以表示为一个列向量。协同过滤算法都是基于相似度的计算,所以在介绍两种算法之前必须介绍一些相似度的计算方法。向量i与j:
(1)余弦相似度:
相关API:
###余弦相似度
from sklearn.metrics.pairwise import cosine_similarity
co_matrix=[[3,1,2,3,3],[4,3,4,3,5],[3,3,1,5,4],[1,5,5,2,1]]
print(cosine_similarity(co_matrix))
[[1. 0.95938348 0.9356927 0.63781505]
[0.95938348 1. 0.89442719 0.77151675]
[0.9356927 0.89442719 1. 0.63831064]
[0.63781505 0.77151675 0.63831064 1. ]]
缺陷:对于【评分数据不规范的时候】,也就是说,存在有的用户喜欢打高分,有的用户喜欢打低分情况的时候,有的用户喜欢乱打分的情况,这时候余弦相似度算出来的结果可能就不是那么准确了。例如:
物品1 | 物品2 | 物品3 | |
用户1 | 4 | 4 | 5 |
用户2 | 1 | 1 | 2 |
用户3 | 4 | 1 | 5 |
这时候,如果用余弦相似度进行计算,会发现用户1和用户3比较相似,而实际上,如果看这个商品喜好的一个趋势的话,其实用户1和用户2比较相似,只是用户2比较喜欢打低分,用户1比较西喜欢打高分。所以对于这种用户评分偏置的情况,余弦相似度就不是那么好了。
co_matrix=[[4,4,5],[1,1,2],[4,1,5]]
print(cosine_similarity(co_matrix))
[[1. 0.97332853 0.91970901]
[0.97332853 1. 0.94491118]
[0.91970901 0.94491118 1. ]]
(2)皮尔逊相关系数:
其中P表示为物品,表示用户i为物品p的评分。
相关API:
###皮尔逊相关系数
import pandas as pd
co_matrix=[[3,1,2,3,3],[4,3,4,3,5],[3,3,1,5,4],[1,5,5,2,1]]
print(pd.DataFrame(co_matrix).corr("pearson"))
0 1 2 3 4
0 1.000000 -0.648886 -0.435286 0.473684 0.969458
1 -0.648886 1.000000 0.670820 -0.324443 -0.478091
2 -0.435286 0.670820 1.000000 -0.870572 -0.427618
3 0.473684 -0.324443 -0.870572 1.000000 0.581675
4 0.969458 -0.478091 -0.427618 0.581675 1.000000
优势:
这是非常常用的一种计算相似度的一种方式,相比余弦相似度,皮尔逊相关系数通过使用用户平均分对独立评分进行修正,减少了用户评分偏置的影响。简单的说,其实皮尔逊相关系数做的就是把两个向量都减去他们的均值,然后在计算余弦相似度。用pearson来计算用户相似度进行推荐的话,效果还是比较好的。
物品1 | 物品2 | 物品3 | |
用户1 | 4 | 4 | 5 |
用户2 | 1 | 1 | 2 |
用户3 | 4 | 1 | 5 |
继续这个例子:
###皮尔逊相关系数
import pandas as pd
print(pd.DataFrame(co_matrix).T.corr("pearson"))
0 1 2
0 1.000000 1.000000 0.693375
1 1.000000 1.000000 0.693375
2 0.693375 0.693375 1.000000
除了这两种常见的相似度计算,还有欧式距离、曼哈顿距离等,这里不过多阐述。
2.2基于用户相似度的协同过滤(UserCF)
基于用户相似度的协同过滤核心思想认为:兴趣相同的人,喜欢的东西也类似。如下图所示:
上图清楚的表示:当一个人喜欢寸衫、裤子、帽子的时候,我们可以找到类似(也喜欢寸衫、裤子帽子)的人,看他是否喜欢鞋子,来判断当前的人是否喜欢鞋子。
我们拿出前面的例子:
物品1 | 物品2 | 物品3 | 物品4 | 物品5 | |
用户1 | 3 | 1 | 2 | 3 | 3 |
用户2 | 4 | 3 | 4 | 3 | 5 |
用户3 | 3 | 3 | 1 | 5 | 4 |
用户4 | 1 | 5 | 5 | 2 | 1 |
Adam | 5 | 3 | 4 | 4 | ? |
步骤:
(1)首先我们用相似度计算公式(这里用了余弦定理)算出与Adam最相似的k个人(这里我们选择2个):
#第一个为Adam
Users=[[5,3,4,4],[3,1,2,3],[4,3,4,3],[3,3,1,5],[1,5,5,2]]
print(cosine_similarity(Users))
[[1. 0.9753213 0.99224264 0.89072354 0.79668736]
[0.9753213 1. 0.94362852 0.91160719 0.67478587]
[0.99224264 0.94362852 1. 0.85280287 0.85811633]
[0.89072354 0.91160719 0.85280287 1. 0.67082039]
[0.79668736 0.67478587 0.85811633 0.67082039 1. ]]
发现User1与User2与Adam最为相似
(2)根据相似度用户计算Adam对物品5的最终评分,这里的最终评分计算公式为:
其中,表示所有相似用户,
表示用户u与用户s的相似度,
表示用户s对物品p的评分。(有点加权平均的味道)
在上面,我们知道用户1与用户2与Adam相似,因此所有相似用户为用户1与用户2,其对物品5的评分分别为:3,5
因此:Adam对物品5的评分为:
之前我们在余弦相似度的时候提到,余弦相似度的弊端在于每个人打分倾向性不同,有的人喜欢打高分,有的人喜欢打低分,因此余弦相似度计算会不准(这里简单起见我们沿用了继续用余弦相似度计算用户之间的相似度)。我们引入了皮尔逊相关系数来缓解这个问题,其主要是通过每个向量减去均值来减少个人的偏置影响,接着在进行余弦相似度计算。
而在预估Adam对商品5评分的时候,我们用到了用户1和用户2对商品5的评分,这也可能存在有些人喜欢打高分,有些人喜欢打低分的情况,因此为了减少个人偏置的影响,我们也需要进一步优化计算公式,公式如下:
其中Adam的平均分为:4,用户1与用户2的平均分分别为:2.4和3.8。因此Adam对物品5的评分为:
(3)根据用户评分对用户进行推荐
制定一个阈值,预测评分超过阈值,即可推荐给用户。
缺点:
(1)数据稀疏性:一个大型的电子商务推荐系统一般有非常多的物品,用户可能买的其中不到1%的物品,不同用户之间买的物品重叠性较低,导致算法无法找到一个用户的相似近邻,即偏好相似的用户,及时找到了,准确性也可能不会太高。这导致UserCF不适用于那些正反馈获取较困难的应用场景(如酒店预订,大件商品购买等低频应用)。
(2)用户相似矩阵维护难度大:在互联网应用场景中,绝大多数产品的用户数都要远大于物品数,因此维护用户相似度矩阵的难度要大很多。此外,基于用户相似度的协同过滤需要维护用户显示度矩阵以便快速的找出TopN相似用户,该矩阵的存储开销非常大,存储空间随着用户数量的增加而增加,不适合用户数据量大的情况使用。
适用场景:常适用于用户少,物品多,时效性较强的场合,如新闻推荐场景。
2.3基于物品相似度的协同过滤(ItemCF)
如果说,UserCF是兴趣相同的人喜欢的东西也相似,那么ItemCF可以认为相似的物品被人喜欢的程度类似。基于拿我们上述例子来说:
物品1 | 物品2 | 物品3 | 物品4 | 物品5 | |
用户1 | 3 | 1 | 2 | 3 | 3 |
用户2 | 4 | 3 | 4 | 3 | 5 |
用户3 | 3 | 3 | 1 | 5 | 4 |
用户4 | 1 | 5 | 5 | 2 | 1 |
Adam | 5 | 3 | 4 | 4 | ? |
之前我们从行看获取一个用户向量,此时我们从列看获取一个物品向量。ItemCF计算过程与UserCF类似:
步骤:
(1)首先我们用相似度计算公式(这里用皮尔逊相关系数)算出与物品5最相似的k个物品(这里我们选择2个):
#列表第一个为物品5
co_matrix=[[3,5,4,1],[3,4,3,1],[1,3,3,5],[2,4,1,5],[3,3,5,2]]
print(pd.DataFrame(co_matrix).T.corr("pearson"))
0 1 2 3 4
0 1.000000 0.969458 -0.478091 -0.427618 0.581675
1 0.969458 1.000000 -0.648886 -0.435286 0.473684
2 -0.478091 -0.648886 1.000000 0.670820 -0.324443
3 -0.427618 -0.435286 0.670820 1.000000 -0.870572
4 0.581675 0.473684 -0.324443 -0.870572 1.000000
可以发现物品1和物品4与物品5最为相似
(2)根据相似度物品计算Adam对物品5的最终评分,这里的物品最终评分计算公式为:
其中,表示物品p与物品q的相似度,P表示所有相似物品
我们已知,物品5的平均分为:3.25,物品5与物品1的相似度为0.97,物品5与物品4的相似度为0.58。物品1的平均分为:3.2,物品4 的平均分为:3.4
因此,最终得分为:
(3)根据物品评分对用户进行推荐
制定一个阈值,预测评分超过阈值,即可推荐给用户。
ItemCF优点:
(1)ItemCF算法的预测结果比UserCF算法的质量要高一点
(2)由于ItemCF算法可以预先计算好物品的相似度,所在线预测性能要比UserCF算法高
ItemCF缺点:
(1)数据稀疏性
(2)物品相似度矩阵维护困难
适用场景:
适用于兴趣变化较为稳定的应用,更接近于个性化的推荐,适合物品少,用户多,用户兴趣固定持久,物品更新速度不是太快的场合。比如:艺术品,音乐,电影。
3.矩阵分解--协同过滤的进化
之前提到的ItemCF以及UserCF,他们其实都不具备较强的泛化能力,即其都比较偏向于热门商品。如,我们得到A,B,C,D四个物品向量:
A | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 |
B | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
C | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
D | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 |
我们通过余弦定理计算物品相似度矩阵:
A | B | C | D | |
A | ---- | 0.00 | 0.00 | 0.71 |
B | 0.00 | ---- | 0.00 | 0.18 |
C | 0.00 | 0.00 | ---- | 0.18 |
D | 0.71 | 0.18 | 0.18 | ---- |
我们可以看出A,B,C之间的相似度均为0,而与A,B,C最相似的物品均为D,因此在以ItemCF为基础构建的推荐系统中,物品D将被推荐给所有对A、B、C有过正反馈的用户。但是事实上,物品D与A,B,C相似的原因仅仅在于物品D是一件热门商品,系统无法找到A、B、C之间相似性的主要原因是其特征向量非常稀疏,缺乏相似性计算的直接数据。这也揭露了协同过滤的天然缺陷----推荐结果的头部效应明显,处理稀疏向量的能力弱。
也因此,矩阵分解被提了出来,即在共现矩阵的基础上,用更稠密的隐向量来表示用户和商品,以此弥补协同过滤处理稀疏矩阵能力不足的问题。
如图,通过用户矩阵与物品矩阵两个稠密矩阵来表示共现矩阵,而在用户矩阵中,每个用户通过2维隐向量(行向量)表示,并且用户兴趣相近的向量在二维空间上其距离也是相近的。同理也通过2维隐向量(列向量)来表示商品,相似的商品在二维空间中也是相近的。
在举例区别协同过滤以及矩阵分解算法区别:
在抖音中,一个人点赞的视频,可能由其他很多人也都点赞了,协同过滤就是将也点赞的这些人找出来,并且找到这些人还点赞的其他视频,并将这些视频推荐给当前目标用户,这就是协同过滤。而在矩阵分解中,为每个人和视频都生成一个k维的隐向量,当前用户给他推荐视频,就是在找表示当前用户的隐向量最近的一些视频隐向量,并将没看过的视频推荐给用户。因此,隐向量的好坏决定了矩阵分解的质量。
矩阵分解算法将维的共现矩阵R分解为
维的用户矩阵U和
维的物品矩阵V相乘的形式。其中m是用户数量,n是物品数量,k是隐向量的维度。k的大小决定了隐向量表达能力的强弱,k取值越小,隐向量包含的信息越少,模型的泛化能力越高;反之,k的取值越大,隐向量的表达能力越强,但泛化能力相应降低。此外,k的取值还与矩阵分解的求解复杂度直接相关。在具体应用中,k的取值要经过多次试验找到一个推荐效果和工程开销的平衡点。
核心等式:
其中,是用户u在用户矩阵U中对应的行向量,
是物品i在物品矩阵V中对应的列向量,
是用户u对物品i的预估评分,
是用户u对物品i的真实评分。
那么接下来的问题在于,如何进行矩阵分解。
(1)特征值分解:只适用于方阵,不现实
(2)奇异值分解(SVD):现实中计算开销过大,工业上不采用
(3)梯度下降法(LFM):现实中应用较多
3.1LFM
我们进行矩阵分解,必须使得让原始评分与用户对商品的预估评分
尽可能的小,因此我们的损失函数可以采用均方差,即我们的优化目标为:
其中K为所有用户评分样本的集合。为了减少过拟合现象,加入正则化后的优化目标函数为:
接着通过梯度下降去不断优化这个目标函数。
完整步骤如下:
(1)首先初始化2个参数矩阵U和V
(2)遍历参数矩阵中的两个隐向量内积计算出某用户对某商品的预估评分
(3)计算预估评分与真实评分的均方差损失
(4)通过均方差损失,根据梯度下降法更新隐向量
(5)回到2步骤,知道损失函数趋于一个阈值
3.2RSVD
在前面中我们提到,个人评分存在偏置的影响,即有人喜欢打高分,有人喜欢打低分,为了消除用户和物品打分的偏差,常用的做法是在句子分解时加入用户和物品的偏差向量,即:
其中,是全局偏差常数,
是物品偏差系数,可使用所有i收到的所有评分的均值,
是用户偏差系数,可以使用用户u给出的所有评分的均值。
此时我们的优化目标也应该做出相应的改变,即:
其余与LFM一样,不在赘述。
相较于ItemCF与UserCF,矩阵分解算法直接通过梯度下降得出物品和用户的隐变量,并通过当前用户的隐变量,计算其最接近的物品隐向量,做出推荐。
3.3矩阵分解的优缺点
优点:(1)泛化能力强,在一定程度上接近了数据稀疏的问题。(2)空间复杂度低,k远小于n和m(3)更好的扩展性和灵活性,矩阵分解的最终产物是用户和物品隐向量,这其实与深度学习中的Embedding思想不谋而合,因此矩阵分解的结果也非常便于与其他特征进行组合与拼接,并便于深度学习网络进行无缝结合。
局限性:只关注了用户与物品的交互信息,没有关注其他信息,如用户、物品和上下文相关的特征,这使得矩阵分解丧失了利用很多有效信息的机会,同时在缺乏用户历史行为时,无法进行有效的推荐。