学习总结

  • 协同过滤(Collaborative Filtering)及其衍生的模型,和深度学习推荐系统密切相关。
    协同过滤:协同大家的反馈、评价和意见,对海量的信息进行过滤,从中筛选出用户感兴趣信息的一种推荐算法。大体步骤是:根据共现矩阵的每个用户行向量,计算目标用户的top k相似用户;在利用得到的相似度,计算目标用户对每一件商品的预测评分(用来推荐)。

【王喆-推荐系统】模型篇-(task1)协同过滤CF_相似度

  • 协同过滤处理稀疏矩阵的能力比较差,因此提出了通过矩阵分解共现矩阵,生成用户向量矩阵和物品向量矩阵,进而得到用户隐向量和物品隐向量。可以把最后的结果当作用户 Embedding 和物品 Embedding 来处理。
  • 只有合适的算法,没有最优的算法。移动互联网背景下我们更多是用点击数据,用户好友关系,通讯录或者甚至是同一个WIFI地址来计算用户协同过滤,数据稀疏性得到一定程度上的解决。现在,用户的协同过滤在信息流内容推荐,社交性的推荐系统有着很好的利用。比如抖音,因为内容更新频繁,用户协同过滤可以作为很好的召回手段。
    但也不是单纯用协同过滤来做推荐,而是将他们作为其中的一个或几个召回策略来使用。

文章目录


推荐系统的整体架构都是围绕着推荐模型搭建的,用于支持推荐模型的上线、训练、评估、服务。

一、协同过滤算法的基本原理

“用户行为数据是推荐系统最常用,也是最关键的数据。用户的潜在兴趣、用户对物品的评价好坏都反映在用户的行为历史中”。而协同过滤算法,就是一种完全依赖用户和物品之间行为关系的推荐算法。

先从一个栗子入手:假设电商平台中有4个商品(游戏机、小说、杂志和电视机)。
任务:一用户X访问该网站,推荐系统要决定是否将电视机推荐给X用户。

(1)将下图的有向图转成【共现矩阵】,其中点赞可以设置为数字1,踩可以设置为-1,没有用户行为就设置为0。如果有具体的评分,也可以取具体的评分(没有用户行为也可以设置为评分的均值)。

【王喆-推荐系统】模型篇-(task1)协同过滤CF_深度学习_02


图1 协同过滤的过程 (来自《深度学习推荐系统》)

(2)现在问题变成预测矩阵中的“问号”。在“协同”过滤算法中,推荐的原理是让用户考虑与自己兴趣相似用户的意见。所以预测的第一步就是找到与用户 X 兴趣最相似的 n(Top n 用户,这里的 n 是一个超参数)个用户,然后综合相似用户对“电视机”的评价,得出用户X 对“电视机”评价的预测。

(3)从共现矩阵中我们可以知道,用户 B 和用户 C 由于跟用户 X 的行向量近似,被选为 Top n(这里假设 n 取 2)相似用户,用户 B 和用户 C 对“电视机”的评价均是负面的。因为相似用户对“电视机”的评价是负面的,所以预测出用户 X 对“电视机”的评价也是负面的。

二、计算用户相似度

在共现矩阵中,每个用户对应的行向量其实就可以当作一个用户的 Embedding 向量。
利用余弦相似度了,它衡量了用户向量 i 和用户向量 j 之间的向量夹角大小。夹角越小,余弦相似度越大,两个用户越相似,定义:【王喆-推荐系统】模型篇-(task1)协同过滤CF_矩阵分解_03除了最常用的余弦相似度之外,相似度的定义还有皮尔逊相关系数、欧式距离等等。

改进:现在大佬们又使用如Word2vec,Item2vec等Embedding类的算法,将物品嵌入固定的向量空间中,再使用LSH算法(局部敏感哈希算法)取最近邻物品,即根据相似度排序取最近邻的物品。

三、用户评分的预测

在获得 Top n 个相似用户之后,利用 Top n 用户生成最终的用户 u 对物品 p 的评分的过程,可以基于假设:目标用户和top n用户喜好相似。最直接计算是利用用户相似度,和相似用户评价的加权平均值:【王喆-推荐系统】模型篇-(task1)协同过滤CF_深度学习_04其中【王喆-推荐系统】模型篇-(task1)协同过滤CF_协同过滤_05用户u和用户s之间的相似度,而【王喆-推荐系统】模型篇-(task1)协同过滤CF_矩阵分解_06是用户s对商品p的评分。就这样得到【王喆-推荐系统】模型篇-(task1)协同过滤CF_相似度_07即目标用户u对物品p的预测评分(其他商品也是一样道理),根据这个分数对商品排序,从而得到推荐列表。

上面的方法是用户之间的相似度计算,当然也可以利用商品之间的相似度计算,如下栗子:

如下图,通过用户B对图书1的评分 × 未知图书与图书1的相似度来预测用户B对剩下图书的评分。如图书2的预测评分 = 图书1的评分5分 × 图书1和图书2的相似度0.27 ,从而用户B对图书2的评分是:5*0.27=1.35。同样方式计算出其他图书的评分预测。

【王喆-推荐系统】模型篇-(task1)协同过滤CF_推荐算法_08

四、矩阵分解算法的原理

4.1 协同过滤的缺点

协同过滤缺点:
(1)共现矩阵经常很稀疏(用户行为可能很少,所以寻找相似用户的过程不准确)。
(2)对于一个新物品,协同过滤是无法推荐的。因为新物品用户无评分,导致它跟所有物品的相似度都是为0。
为此流视频公司Netflix改进协同过滤算法,得到矩阵分解算法。

4.2 矩阵分解

【王喆-推荐系统】模型篇-(task1)协同过滤CF_相似度_09


图2 论文中的“协同过滤(左a)”和“矩阵分解(右b)”的原理图

矩阵分解算法则是期望为每一个用户和视频生成一个隐向量,将用户和视频定位到隐向量的表示空间上(如图 2(b) 所示),距离相近的用户和视频表明兴趣特点接近,在推荐过程中,我们就应该把距离相近的视频推荐给目标用户。

矩阵分解的主要过程,就是先分解协同过滤生成的共现矩阵,生成用户和物品的隐向量(类似embedding),再通过用户和物品隐向量间的相似性进行推荐。

4.3 分解共现矩阵

就是把一个 mxn 的共现矩阵,通过SVD(Singular Value Decomposition)矩阵分解成一个 mxk 的用户矩阵和 kxn 的物品矩阵相乘的形式(如图 3,通过模型训练得到User矩阵和Item矩阵后,将该2矩阵相乘可得到预测评分值矩阵,这里预测评分矩阵未写出)。

【王喆-推荐系统】模型篇-(task1)协同过滤CF_相似度_10


有了用户矩阵和物品矩阵,用户隐向量和物品隐向量就非常好提取了。用户隐向量就是用户矩阵相应的行向量,而物品隐向量就是物品矩阵相应的列向量。

最常用的分解共现矩阵的方法:梯度下降(通过求偏导来更新权重)【王喆-推荐系统】模型篇-(task1)协同过滤CF_矩阵分解_11为了实现梯度下降,最关键的一步设计损失函数:【王喆-推荐系统】模型篇-(task1)协同过滤CF_协同过滤_12

其中【王喆-推荐系统】模型篇-(task1)协同过滤CF_协同过滤_13是共现矩阵里用户u对物品i的评分,【王喆-推荐系统】模型篇-(task1)协同过滤CF_推荐算法_14是物品向量,【王喆-推荐系统】模型篇-(task1)协同过滤CF_矩阵分解_15是用户向量。
该目标函数是为了让物品向量,和用户向量之积,和原始评分的差的平方尽可能小。即用户和物品矩阵之积,越接近共现矩阵越好。

【栗子】在推荐系统领域,可以简单的认为,SVD就是将一个矩阵,在一定的精度损失下,将一个矩阵分解成两个矩阵。

【王喆-推荐系统】模型篇-(task1)协同过滤CF_矩阵分解_16


实际生产环境中:SVD一般作为协同过滤的离线召回使用。一般地,将需要给用户推荐的物品提前离线计算好,存在HBASE中,在用户有请求的时候,直接读取推荐的结果,放入初排阶段的召回集中。

五、矩阵分解算法的 Spark 实现

使用Spark MLlib,三部曲:定义模型,使用 fit 函数训练模型,提取物品和用户向量。

PS:需要在模型中指定训练样本中用户 ID 对应的列 ​​userIdInt​​​ 和物品 ID 对应的列 ​​movieIdInt​​​,并且两个 ID 列对应的数据类型需要是 ​​int​​ 类型的。

// 建立矩阵分解模型
val als = new ALS()
.setMaxIter(5)
.setRegParam(0.01)
.setUserCol("userIdInt")
.setItemCol("movieIdInt")
.setRatingCol("ratingFloat")


//训练模型
val model = als.fit(training)


//得到物品向量和用户向量
model.itemFactors.show(10, truncate = false)
model.userFactors.show(10, truncate = false

两点注意:
(1)矩阵分解算法得出的结果,可以把它当作 Embedding 来处理。参考用Redis时实现过物品 Embedding 和用户 Embedding 的存储和线上预估的过程。
(2)可以利用矩阵分解后的用户和物品隐向量,仿照其他 Embedding 的实现,在 Sparrow RecSys 中动手实现一下线上部署的过程,得到矩阵分解模型的实际效果。

六、作业

(1)基于协同过滤算法,你能找到进行相似“物品”推荐的方法吗?
答:已经有物品向量了应该直接求cosine sim取topk就行了

(2)在 MovieLens 数据集中,不同用户对物品打分的标准不尽相同。比如说,有的人可能爱打高分,评价的影片得分都在 4 分以上,有的人爱打低分,大部分影片都在 3 分以下。你觉得这样的偏好对于推荐结果有影响吗?我们能不能在算法中消除这种偏好呢?

答:经典的做法是在生成共现矩阵的时候对用户的评分进行用户级别的校正或者归一化,用当前得分减去用户平均得分作为共现矩阵里面的值。

均值方差归一化是最标准的做法,即原始向量【x1,x2,x3】变成【x1-xp,x2-xp,x3-xp】,(cur-average)/(max_min),这样有利于弱化个人评分标准不同的影响;
其实cosine和欧氏距离在l2归一化的条件下在数学上是等价的,本质还是要归一化。

七、课后答疑

(1)矩阵分解在工业界落地好像并不常见,从工程实践角度来讲,是有什么特殊的原因吗?
【答】五年前的推荐系统,矩阵分解是很主流的技术方案。但是矩阵分解没法引入除用户行为外的其他特征,深度学习出来之后就逐渐被取代了。

(2)业务的指标是给不同用户推送可能点击概率比较大的广告,提高不同用户对不同广告的点击率,我这边是利用CTR模型来做的,预测每个用户点击某一个广告的概率,最后发现对于不同的广告,点击概率>0.5的人群重合度很大,目前分析有两个原因,一是测试所用的广告标签类似,导致可能点击用户群体相同;二是最可能的,就是喜欢点击广告的,就是那一波人,另外一波人无论什么广告都没有兴趣点击。老师有遇到过这种情况吗?是怎么解决的?

【答】从数据上说,第二个原因的可能性非常大,你其实可以分析一下原始的数据,是不是说点击人群的范围确实比较小。

至于解决方法建议从特征设计的角度入手,看看能不能加入一些能增强模型泛化能力的特征,比如大家都有的一些人口属性特征,广告的分类结构特征之类的,希望能把特定人群的一些行为泛化出去。

(3)做点击推荐的时候正负样本比例相差很大,除了随机抽样负样本,还有什么比较好的办法呢?
【答】工作中常用的就是负样本欠采样,和正样本过采样,或者增大正样本学习的权重。
还有一种方法叫SMOTE,大致意思是通过合成的方式过采样正样本。可以尝试但有一定风险。

(4)lfm是否也是一种矩阵分解的方法,在实践中感觉计算量很大,在这里用als是否因为基于spark框架且运算量较少?
【答】als是矩阵分解方法最常用的方法。lfm也可以理解为一种矩阵分解方法,可以看作是MF的进化版本,因为lfm可以加入一阶部分,而且可以加入其他特征,更灵活一些。

Reference

(1)https://github.com/wzhe06/Reco-papers
(2)《深度学习推荐系统实战》,王喆
(3)​​​推荐算法:3种协同过滤的原理及实现​​​ (4)​​推荐系统中协同过滤算法实现分析​