推荐召回--基于用户的协同过滤UserCF


目录
  • 1. 前言
  • 2. 原理
  • 3. 数据及相似度计算
  • 4. 根据相似度计算结果
  • 5. 相关问题
    • 5.1 如何提炼用户日志数据?
    • 5.2 用户相似度计算很耗时,有什么好的方法?
    • 5.3 有哪些改进措施?
  • 6. 总结

1. 前言

协同过滤的思想在推荐系统中,可谓是开山鼻祖般的存在。从推荐系统最初至今,几十年的历程中,协同过滤一直都闪烁着迷人的光芒。

要说为何协同过滤这么重要,就得说说它的优点:

  1. 模型通用性强,不需要太多的领域知识
  2. 工程实现简单,可以方便的应用到产品中,而且效果还不错

协同过滤主要包括协同和过滤两个部分,在线的协同是重点,主要是根据数据找到相似的用户/物品,而离线的过滤主要是筛选,如根据相似得分,筛选出评分高的物品,或者是筛选出得分高但用户已经购买的物品。

接下来我们来说说,协同过滤的思想。通常呢,就是从埋点日志里,找出用户的行为数据,然后构建出用户和物品的一个共现矩阵,当然不可能说用户把所有的物品都消费过,所以这个共现矩阵会有很多空白的地方,而我们的重点就是通过计算,把这些空白的地方填充,然后排除已经消费过的物品,把那些最终得分高的推荐给用户。

一般而言呢,协同过滤分为三种类型:基于用户(user-based)的协同过滤,基于物品(item-based)的协同过滤,基于模型(model-based)的协同过滤。

那今天我们主要来讲解下基于用户的协同过滤:UserCF。

2. 原理

老话说的好:人以群分。你是什么样的人,你的朋友也基本和你一样。生活中呢,会有这样的场景出现:比如说最近想看一部悬疑片的电影,你会让你的好朋友给你推荐。这个过程呢,就是基于用户的协同思想,而你的朋友给你推荐过几部电影《神探夏洛克》、《盗梦空间》等,然后你说《盗梦空间》我看过了,我来看看《神探夏洛克》。那这个过程,就是过滤的思想了。从前到后,我们梳理下,就会发现,基于用户的协同过滤其实一直就出现在我们的日常生活中,只是没有用数学和算法的思想提炼而已。

那么问题来了,在实际的应用中,我们怎么去找到相似的用户,也就是从其他用户中找到你的“好朋友”呢?

3. 数据及相似度计算

说到这里,必须得提一下,通常而言,我们从埋点日志数据里,提炼出的用户-物品共现矩阵中,数据的展示会有两种方式:显式评分矩阵和隐式评分矩阵。

显式:比如说用户给物品评分5分,4分,3分等,这种呢,就是用户在消费物品后,会给物品反馈一个自己的衡量。也就是我们在网上购物后的一个评价得分。

隐式:通常有的用户在购买过物品后,不会给物品评分,因为懒。这个时候呢,我们怎么去衡量这个得分呢?简单,直接将用户购买过的物品给1,用户未购买的给0。

除去上面这两种情况呢,还可以根据用户的行为,自己制定相关的分数体系,如:点击1,加购3,购买6等。在数据处理中呢,将用户的操作行为,转换为对应的得分,那我们就可以顺利的去操作共现矩阵了。

对于数据的处理,到一个阶段。接下来看看如何计算用户的相似度。

对应上面的数据格式,业内在相似度计算上的选择也不同。显式用余弦cosine,隐式用杰卡德jaccard,余弦有变种,别忘皮尔逊,加时间衰减,效果会更好。

余弦相似度:

余弦相似度在计算用户、物品、文本时使用很频繁。

计算夹角,而不考虑长度的影响。如:用户A对物品1和物品2的评分是1分,2分,用户B的评分是4分,5分。用余弦相似度计算的话,用户A和用户B相似度高达98%,故引入皮尔逊。

\[cos(\theta)=\frac{A \cdot B}{\mid \mid A \mid \mid \times \mid \mid B \mid \mid}= \frac{\sum_{i=1}^n A_i \times B_i}{\sqrt{\sum_{i=1}^n(A_i)^2} \times \sqrt{\sum_{i=1}^n(B_i)^2}} \]

皮尔逊相关系数:

实际上也是一种余弦相似度,只不过是先对向量做了去中心化,也就是减去均值后,再计算相似度。

区别于余弦相似度,皮尔逊计算结果在[-1, 1]之间。有正相关和负相关之分。

皮尔逊只适合于显示评分体系。

\[r = \frac{\sum_{i=1}^n(X_i - \overline X)(Y_i - \overline Y)}{\sqrt {\sum_{i=1}^n(X_i - \overline X)^2} \sqrt {\sum_{i=1}^n(Y_i - \overline Y)^2}} \]

杰卡德相似度:

简单来说,就是交集除以并集

\[J(A,B) = \frac{\mid A \bigcap B \mid}{\mid A \bigcup B \mid} \]

另外,拓展下常用的八大距离计算方法:

4. 根据相似度计算结果

在计算完用户相似度后,我们接下来就可以根据用户间的相似度,来给目标用户推荐物品。

一般,常用加权平均法:

\[pred(u,i)=\hat{r}_{ui}=\frac{\sum_{v\in U}sim(u,v)*r_{vi}}{\sum_{v\in U}|sim(u,v)|} \]

整体的思路就是:根据相似度,选取K个最相似的用户(K近邻思想),然后对这K个用户评分过的物品进行打分,最后过滤掉该用户已经评分过的即可。

有个问题得备注下:通常来说,用隐式矩阵的话,只是能预测出用户是否对物品感兴趣,但是呢,对物品的喜好程度不能很好的预测。所以实际工作中,尽可能的去使用显式评分矩阵,效果会更好。

当然,评分矩阵一般都比较稀疏,比如用皮尔逊计算,如果不存在正相关,那就无法做出预测。这个时候呢,可以使用余弦相似度,然后根据最终的推荐结果,去调整分数阈值。另外,召回通路不仅仅是一条,如果卡分数阈值后,没有推荐结果,那就用其他路填充呗。

5. 相关问题

5.1 如何提炼用户日志数据?

这个涉及到数据结构存储了,如果数据量不大,可以用字典的方式存储。其次用numpy、pandas来操作数据。

5.2 用户相似度计算很耗时,有什么好的方法?

主要的思想就是聚类过滤。如筛选某一区域的用户进行计算,或者根据性别、年龄、消费水平等等,这样的条件筛选完后,用户的基数就比较小。

其次就是向量化计算,记住:不要重复造轮子。Python中的numpy、pandas已经内嵌了很多方法,可以高效的操作数据。

在海量数据的基础上,还可以考虑Hadoop、Spark等大数据分布式计算框架。

此外,可以尝试一些单机版的工具:KGraph、GraphCHI等。

5.3 有哪些改进措施?

像上文提到的筛选出K个最相似的用户,可以大大缩减推荐的计算时间。

另外,可以考虑多线程的方法,如C++的OpenMP库可以让我们大大提升计算机的使用效率。

还有就是,可以惩罚热门物品的喜欢程度,增加时间衰减,一般用一个指数函数,来对物品进行降权处理。

6. 总结

关于用户的协同过滤,主要的输出有两个:相似用户和推荐列表。我们不但可以给用户推荐喜欢的商品,还可以根据业务场景,有选择的给用户推荐最相似的用户。这个也就时像抖音等社交平台上:“你可能认识的人”,“和你口味类似的人”等。

最后,协同过滤是推荐系统的入门策略,但也是推荐系统的基石。目前行业内的大厂,在召回侧的基本都是协同过滤、内容、模型等策略,像word2vec、fm等召回思想都是在base之上的延伸,所以掌握协同过滤的思想是非常重要的。

加油!!!