为什么我学的东西那么杂?我也不知道,反正要用。
学习资料是 b 站黑马程序员的推荐系统视频。
1. 为什么要有推荐系统
了解推荐系统,首先要知道其背景,为什么我们需要推荐系统,它是用来干什么的。
1.1 信息过载
第一个原因就是现在的信息太多了,如果你想淘宝买个台灯,你不可能遍历整个淘宝所有卖台灯的,在其中挑选自己最喜欢的台灯,这不合理。
1.2 用户需求不明确
很多时候用户自己也不知道自己要什么,需要给一个参考的推荐。比如上新闻 app 看新闻,你并不知道有什么新闻,你大概知道自己喜欢什么相关的新闻,但你不知道有什么新闻,这个时候就需要推荐系统根绝诸如用户画像之类的东西给你推荐了。
1.3 如何处理以上问题
上面两个问题,在不同时代,应对不同情况,有着不同的解决方案。
- 分类目录:在最早的时候,我们有着诸如 yahoo,hao123 这种网站之家的东西,里面有各种分类,在每个分类下你可以看到很多热门网站。
- 搜索引擎:此外,我们还有搜索引擎来通过关键词搜索我们指定的东西。
- 推荐系统:到了最近,我们有了推荐系统,甚至不需要你输入什么东西,只要你打开 app,就能看到你喜欢的东西,甚至在看到之前你都不知道你喜欢它。
2. 推荐系统的解释
解释推荐系统,可以通过其和搜索引擎的对比来说明:
| 推荐系统 | 搜索引擎 | |
|---|---|---|
| 用户行为 | 被动 | 主动 |
| 意图 | 模糊 | 明确 |
| 个性化 | 强 | 弱 |
| 流量分布 | 注重长尾效应 | 注重马太效应 |
| 目标 | 持续服务 | 快速满足 |
| 评估指标 | 复杂 | 简明 |
2.1 马太效应
上面提到了马太效应,这里解释一下,马太效应命名出自《马太福音》:
凡有的,还有加给他,叫他有余;凡没有的,连他所有的也要夺去。
意思就是好的越好,差的越差。
- 反映在经济学上就是贫富差距越来越大。
- 而反映在这里指的流量分布上,指的其实是那些流量高的,会越来越高,流量低的则上涨很慢。
2.2 长尾效应
这个效应和上面的刚好相反。长尾效应认为即使流量不大,靠着总量多也能够达到不错的经济效益。即那些销量小但是种类多的产品,加在一起,也能得到和热门产品一样的收益。
- 对于大公司来说比如说定制化。
- 以及一些大量的零散的销售线。每个线可能赚的不多,但是加起来却可以得到相当可观的数额。
2.3 马太效应 与 长尾效应 是共存的
这两者虽然冲突,但是可共存,同一件事上都存在这两者效应。马太效应高那么长尾效应就低,反之亦然。
注意:无论是马太效应,还是长尾效应,它们反应的都是一种现象,而不是一种理论。
搜索引擎中马太效应更明显,因为用户用搜索引擎就是为了看第一页,搜不到就直接换关键词甚至搜索引擎了。而推荐系统则更注重长尾效应,会根绝你的用户画像给你推荐很多小流量的东西,即使你不喜欢,反正手一划拉就过去了,但是这也让小流量有了被再次曝光的机会。
2. 推荐系统架构
以下为我们要使用的架构。
```mermaid
graph TD
Lambda架构采集数据 --> 推荐算法使用数据计算结果
推荐算法使用数据计算结果 --> 结果用于服务用户
结果用于服务用户 --> 用户的行为就是对结果的反馈
用户的行为就是对结果的反馈 --> Lambda架构采集数据
2.1 lambda 架构
lambda 架构是一个大数据架构,为了解决数据量过大时候的查询问题。因为很明显当数据量特别大的时候,不可能对于每一个 query 都要重新计算。而 lambda 架构就是将在线请求和预计算结合在一起的架构,包含诸如 Hadoop,Hive,nosql,spark 等各种工具的使用。
2.2 推荐算法架构
前面 lambda 架构获取的是数据,后面推荐算法架构则是对数据进行处理。架构如下:
- 召回阶段:第一步叫做召回阶段,但是这个和评估的那个召回率没有关系。这一阶段主要是做海选,从海量数据中选取用户可能感兴趣的数据。这一阶段决定了推荐算法的天花板。
- 常用算法:
- 协同过滤:基于用户/物品。基于隐语义。
- 基于内容:获取用户的偏好后,通过 nlp 手段推荐给用户内容相似的产品
- 常用算法:
- 排序阶段:海选之后,依然有很多结果,对于这些结果还需要进一步的排序,以给用户推荐最合适的物品。排序阶段的效果决定了这个推荐算法能不能逼近上一步所决定的天花板。
- 排序评估标准:CTR 预估(常用 LR 算法)
- 策略调整:比如记录推送的结果被用户如何操作,从而调整推荐的策略。比如同一个东西推送很多次但是用户就是不点,那差不多就得删除了。此外还有一些诸如业务限制之类的规则,也属于这一步。
3. 协同过滤简单介绍
协同过滤(collaborative filtering)分为两种,user-based 和 item-based。
两者的思想基本就是物以类聚,人以群分。
这两种算法都要先有一个矩阵,类似如下:
- 每个空格表示某一个用户是否点击了某一个物品。
- 每一列其实可以看做一个用户向量。每一行可以看做物品向量。
3.1 基于用户的协同过滤(user-based CF)
正如上面所述,每一列可以得到用户向量。
其实,user-based CF 就是通过计算用户向量来计算相似度。然后把最相似的几个用户喜欢的其他物品推荐给你。
ps:user-based Cf 是最古老的推荐算法,可以说它标志着推荐系统的诞生。
3.2 基于物品的协同过滤
同理,item-based CF 计算的则是物品向量之间的相似度。然后把和你访问过得物品最相似的几个其他物品推荐给你。 注意:基于物品的协同过滤在不同的网站上有不同的描述,很多时候容易会让你以为这个是基于用户的,但其实是基于物品的。比如说以下两种说法其实都是表示这个推荐是通过物品相似度推荐给你的:
- “给你推荐这个商品是因为你喜欢xxx”
- “买了这个商品的用户同样也买了xxx” 第一个不难理解,但是第二个确实也是基于物品的,因为物品的相似度并不是通过物品本身的属性来计算的,而是通过喜欢这个物品的用户同时也喜欢另一个某商品来计算。
3.3 user-based CF vs item-based CF
看到上面的描述,尤其是 ##3.2 里对于 item-based CF 的第二个描述。其实你会发现这两者其实即使是 item-based 依旧是在使用用户的兴趣信息。所以它们包含的信息其实并无高下之分,而是要看具体应用场景。 一般来说,社交网络更适合 user-based CF,而非社交网络更适合 item-based CF。
不过最好是两个都试一下,然后选最好的。
4. 相似度计算
有了用户-物品矩阵后,就可以计算相似度了,但是相似度有多种计算方式。这里给出几种常用的方式。
4.1 jaccard 相似度
jaccard 相似度很简单,jaccard 要求方格里的值必须是布尔值。然后计算一下两个向量的交集除以并集即可。
sklearn 中的 jaccard 使用方式如下,先计算 jaccard 距离,再用 1 减去值即可:
4.2 皮尔逊相关系数 (Pearson Correlation Coefficient)
jaccard 用于推荐给用户其可能感兴趣的物品,且要求矩阵值为布尔值。
实际上,很多情况下,用户的评分不是一个布尔值,而很有可能是一个评分。这样 jaccard 就不能用了。
如下图所示:
不仅如此,非布尔值情况下,还分为稠密矩阵和稀疏矩阵两种情况。
- 顾名思义,稠密和稀疏指的是用户对物品的评分情况,因为用户不可能对所有物品都有评分,很明显会有很多 NaN。
- 而皮尔逊相关系数,就是在稠密矩阵时候可以使用的一种相似度计算方式。皮尔逊相关系数取值为 -1 到 1 ,-1 到 0 为负相关,0 为不相关,0 到 1 为正相关。
4.2.1 pandas 的 corr 方法
pandas 的 dataframe 类型自带一个 corr 方法,可以直接算出列的皮尔逊相关系数。
4.2.2 评分预测
NaN 不能简单的取值为 0。因为 0 代表不喜欢,所以得通过某种方式预测这些 NaN 的值。而相似度就可以用于做这样的事。
得到了用户对所有其他物品的评分预测后,自然就可以进行推荐了。
4.2.3 推荐
既然得到了对所有物品的预测后,直接对所有没有评分的物品做一个排序,然后选取 topN 推荐给用户即可。
5. 基于模型的算法
上面提到过稠密矩阵的算法,但是如果是稀疏矩阵呢?
这里就要用到基于模型的算法, 基于模型的算法有两种:
- 基于图的模型。
- 基于矩阵分解的方法。
5.1 基于图的模型
比较简单,就是用户和物品作为节点,用线连接。
看一个节点可以有几个路径到达另一个节点上,路径的可能性越多,路径的长度越小,两个节点就越相关。
5.2 基于矩阵分解的方法
假设我们有一个稀疏的 M by N 的矩阵。M 和 N 都相当大,矩阵实际上是十分巨大的。但是我们可以分解为 M by K 和 K by N。这样可以有效减少矩阵格子的数量。同时两个小矩阵相乘又能得到原来的矩阵。
其中,M by K 可以看做是用户矩阵,K by N 可以看做是物品矩阵(或者反过来)
5.2.1 K 的选取
- 选取的 K 最好要远小于 M 和 N。
- K 的选择是一种特征工程。
- K 可以理解为会影响到 用户对物品评分 的特征,比如性别,年龄等信息,所以可以通过对业务的理解来决定 K 的大小。
- 不过并不是那么可解释性,并不能一一对应到哪个特征对应哪个值。只能确定 K 的大小。比如你觉得有 30 个特征会影响到评分,那么 K 至少有 30。
5.2.2 分解
当我们分解得到这样两个矩阵后,随意从用户矩阵中抽出一条数据,也就是 1 by K,同理物品矩阵得到的是 K by 1,相乘得到一个数值,这个数值就是抽出的用户对抽出的物品的评分的预测。
虽然我们想 MK 乘以 KN 能够得回原矩阵,但是这是很难的,只能无限接近。如何计算这个分解方式呢?我们通过一个损失函数,不停的对分解进行优化:
括号里的解释:每一次抽取后,用原矩阵的值减去分解后求会去的值,然后计算平方和。
6. 推荐系统的评估
比较复杂,单单数据上的准确度等指标并不能代表什么。实际上用户的点击,满意度才是指标。
推荐系统有一个 exploitation 和 exploration 的问题:
- 前者指的是根据用户的喜好给用户推荐它喜欢的。
- 后者指的是给用户推荐它可能感兴趣的,新颖的东西。 这两个是互相对应的,顾这边就不能顾另一边,因此需要取舍。
在线评估也经常会用到金丝雀发布类似的概念,给部分用户发布新的推荐系统版本,监测这部分用户相比其他用户是否更加满意。
7. 冷启动
如何给新用户推荐数据,或者如何把一个新的物品推荐给用户,甚至当全部都是新的,一个新系统的上线,用户和物品都是新的,如何推荐?
7.1 用户冷启动
- 当新用户注册的时候,尽可能收集用户的信息。
- 引导新用户填写兴趣。
- 构建好用户基本画像后,可以映射到老用户的聚类上,然后根据聚类所在的老用户们进行推荐。
- 其他站点的数据(产品生态)
- 新用户倾向于热门(Exploration),老用户倾向于长尾(Exploitation)。
7.2 物品冷启动
- 给物品打标签
- 基于物品内容,将其推荐给喜欢过类似物品的用户。
7.3 系统冷启动
当用户和物品都是冷启动的时候,叫做系统冷启动。
- 当缺少用户行为数据的时候,使用基于内容的推荐。
- 随着行为越来越多,开始进行协同过滤。
- 最终是协同过滤和基于内容一起工作,有新物品的时候就基于内容,其他时候协同。
8. 基于内容的推荐
基于内容的推荐主要围绕着打标签。
- 给物品打标签。
- 用户自己填写
- 系统提取
- 分词
- tf-idf 求权重
- 打完标签后,根据标签的文字,转换为词向量。
- word2vec
- 根据词向量,构建物品向量。
- 权重*词向量,再求和
- 通过物品向量计算相似度。
- 皮尔逊相关系数求相似度
9. 电影评分案例
案例没什么好说的,硬要说的话,学到了一些 pandas 库的小知识。
9.1 groupby 和 pivot_table
groupby 更适合做聚合运算,分组是为了做接下来的运算,也就是为了聚合运算而出生的。这也是为什么 groupby 分组后没法直接打印看结果,因为其结构对聚合运算做了优化。
pivot_table 则是为了分组,虽然硬要做聚合运算也可以,但不如 groupby 的优化。