推荐系统 pipeline 的构建过程和总体架构描述。
作者:Parul Pandey
编译:ronghuaiyang
推荐系统pipeline的构建过程和总体架构描述。
选择太少不好,但是选择太多也不是什么好事
你听说过著名的果酱实验吗?2000 年,哥伦比亚大学和斯坦福大学的心理学家 Sheena Iyengar 和 Mark Lepper 在他们的实地实验基础上提出了一项研究。在平常的一天,消费者在当地食品市场的高档杂货店购物时,会看到一个展示 24 种果酱的品尝摊位。前几天,同一个摊位只展示了 6 种果酱。这个实验是为了判断哪个摊位的销量会更高,并假设更多种类的果酱会吸引更多的顾客,从而获得更多的生意。然而,一个奇怪的现象被观察到。尽管有 24 种果酱的柜台更能吸引顾客的兴趣,但与只有 6 种果酱的柜台相比,它们的转化率相当低(大约低 10 倍)。
到底发生了什么?似乎选择很多看起来很吸引人,但这种选择过多有时可能会让客户感到困惑和阻碍。因此,即使网上商店可以获得数百万件商品,如果没有良好的推荐系统,这些选择可能弊大于利。
现在让我们更深入地了解一下它的架构和与推荐系统相关的各种术语。
术语和架构 Terminology & Architecture
让我们来看看一些与推荐系统相关的重要术语。
物品/文件
这些是系统推荐的实体,比如 Netflix 上的电影、Youtube 上的视频和 Spotify 上的歌曲。
查询/上下文
系统利用一些信息来推荐上述项目,这些信息构成查询。查询还可以是下列各项的组合:
-
用户信息,其中可能包括用户 id 或用户以前与之交互的物品。
-
**一些额外的上下文**,如用户的设备,用户的位置等。
嵌入
嵌入是一种将分类特征表示为连续值特征的方法。换句话说,嵌入是高维向量到低维空间(称为嵌入空间)的转换。在这种情况下,要推荐的查询或物品必须映射到嵌入空间。许多推荐系统依赖于学习一个适当的查询和物品的嵌入表示。
总体架构
推荐系统的一般架构包括以下三个主要部分:
1. 候选生成
这是推荐系统的第一阶段,从用户过去的活动中获取事件作为输入,并从大型语料库中检索一小部分(数百个)视频。主要有两种常见的候选生成方法:
- 基于内容的过滤
基于内容的过滤涉及到根据项目本身的属性来推荐物品。系统会推荐与用户过去喜欢的内容相似的内容。
- 协同过滤
协同过滤依赖于用户-物品的交互,依赖于相似的用户喜欢相似的东西的概念,例如购买了这个物品的顾客也购买了这个。
2. 打分
这就构成了第二阶段,在这一阶段,另一个模型进一步对候选人进行排名和打分,通常以 10 分为标准。例如,在 Youtube 的例子中,排名网络通过使用一组描述视频和用户的丰富特征,根据期望的目标函数为每个视频分配分数,从而完成这项任务。得分最高的视频将根据用户的得分进行排序,然后呈现给用户。
3. 重排
在第三阶段,系统考虑额外的约束,以确保多样性、新鲜度和公平性。例如,系统会删除用户之前明确不喜欢的内容,并考虑到网站上的所有的新内容。
一个典型推荐系统的总体结构
相似性度量
你如何辨别一个物品是否与另一个相似?事实证明,基于内容的过滤和协同过滤技术都使用了某种相似性度量。让我们来看两个这样的度量标准。
考虑两部电影 —— movie1 和 movie2,它们属于两个不同的类型。让我们在 2D 图上绘制电影,如果电影不属于某个类型,则赋值为 0,如果电影属于某个类型,则赋值为 1。
这里,电影 1(1,1)同时属于类型 1 和类型 2,而电影 2 只属于类型 2(1,0)。这些位置可以被认为是向量,这些向量之间的角度说明了它们之间的相似性。
余弦相似度
它是两个向量夹角的余弦,similarity(movie1,movie2) = cos(movie1,movie2) = cos 45
大概是 0.7。余弦相似度为 1 表示相似度最高,余弦相似度为 0 表示不相似。
内积
两个向量的点积是角的余弦乘以范数 i 的乘积。similarity(movie1,movie2) = ||movie1|| ||movie 2|| cos(movie1,movie2).
推荐系统 Pipeline
典型的推荐系统 pipeline 包括以下五个阶段:
一个典型的推荐系统管道
假设我们正在构建一个电影推荐系统。该系统不知道用户或电影的先验知识,只知道用户通过对电影进行评级而与电影之间的互动。这里有一个 dataframe,它由电影 ID、用户 ID 和电影的评级组成。
电影评级Dataframe
由于我们只有评级,没有其他信息,我们将使用协同过滤为我们的推荐系统。
1. 预处理
- 效用矩阵转换
我们需要首先将电影评分数据转换成一个用户-物品矩阵,也称为效用矩阵。
矩阵的每个单元格都由用户对电影的评分来填充。这个矩阵通常表示为一个scipy 稀疏矩阵,因为许多单元是空的,因为没有对特定的电影进行任何评级。如果数据是稀疏的,那么协同过滤就不能很好地工作,因此我们需要计算矩阵的稀疏性。
如果稀疏性值约为 0.5 或更多,那么协同过滤可能不是最佳解决方案。这里要注意的另一点是,空单元格实际上表示新用户和新电影。因此,如果有较高比例的新用户,那么我们可能会考虑使用其他一些推荐方法,如基于内容的过滤或混合过滤。
- 归一化
总会有一些用户的评价过于积极(通常是 4 或 5 分)或过于消极(每个电影的评价都是 1 或 2 分)。这可以通过采取平均归一化来实现。
2. 模型训练
数据预处理后,我们需要开始模型构建过程。矩阵分解是一种常用的协同过滤技术,虽然也有其他方法,如邻域方法。以下是涉及的步骤:
- 分解用户-物品矩阵,得到 2 个潜因子矩阵 —— 用户-因子矩阵和物品-因子矩阵。
用户评分是由人生成的电影的特征。这些特征是可以直接观察到的,我们认为它们很重要。然而,也有一些特定的特征是不能直接观察到的,但在评级预测中也很重要。这些隐藏的特征被称为潜特征。
潜特征可以被认为是用户和项目之间交互的基础特征。本质上,我们并不清楚每个潜特征代表什么,但可以假设一个特征可能代表用户喜欢喜剧电影,另一个潜特征可能代表用户喜欢动画电影,等等。
- 通过这两个潜矩阵的内积来预测缺失评级。
潜因子这里用K表示。此重建矩阵填充原始的用户-物品矩阵中的空单元格,因此未知评级现在已知。
但是我们如何实现上面所示的矩阵分解呢?事实证明,有很多方法可以做到这一点,使用下面的方法之一:
-
交替最小二乘(ALS)
-
随机梯度下降法(SGD)
-
奇异值分解(SVD)
3. 超参数优化
在调整参数之前,我们需要挑选一个评估指标。推荐的一个流行的评估指标是精度(Precision at K),它查看最前面的 K 个推荐,并计算这些推荐中与用户实际相关的比例。
因此,我们的目标是找到在 K 或任何其他需要优化的评估指标上具有最佳精度的参数。一旦找到了这些参数,我们就可以重新训练我们的模型来获得我们的预测评级,我们可以使用这些结果来生成我们的推荐。
4. 后处理
然后,我们可以对所有预测的评级进行排序,并为用户获得前 N 个推荐。我们还希望排除或过滤掉用户以前已经交互过的物品。就电影而言,推荐用户以前看过或不喜欢的电影是没有意义的。
5. 评估
我们之前已经讨论过这个问题了,现在让我们更详细地讨论一下。评估任何推荐系统的最佳方法是在实际系统上进行测试。像A/B 测试这样的技术是最好的,因为可以从真实的用户那里得到实际的反馈。然而,如果这是不可能的,那么我们不得不求助于一些离线评估。
在传统的机器学习中,我们将原始数据集分割,创建一个训练集和一个验证集。然而,这对推荐模型不起作用,因为如果我们在一个单独的用户群上训练所有数据,并在另一个用户群上验证数据,模型就不会起作用。所以对于推荐系统,我们实际上做的是在矩阵中随机掩盖一些已知的评级。然后我们通过机器学习来预测这些掩盖的评级,然后将预测评级与实际评级进行比较。
离线评估推荐系统
之前我们讨论了精度作为评估指标。这里有一些其他的可以使用。
Python 库
有许多专门为推荐目的而创建的 Python 库。以下是最受欢迎的一些:
-
Surprise[1]:一个 Python scikit 构建和分析推荐系统。
-
Implicit[2]:针对隐式数据集的快速 Python 协同过滤。
-
LightFM[3]: Python 实现了许多隐式和显式反馈的流行推荐算法。
-
pyspark.mlib.recommendation[4]: Apache Spark 上的机器学习 API。
结论
在本文中,我们讨论了推荐系统在缩小选择范围方面的重要性。我们还介绍了推荐系统的设计和构建过程。Python 实际上简化了这一过程,为此提供了对大量专用库的访问。试着用一个来建立你自己的个性化推荐引擎。
参考资料
[1]Surprise: http://surpriselib.com/
[2]Implicit: https://implicit.readthedocs.io/en/latest/quickstart.html
[3]LightFM: https://lyst.github.io/lightfm/docs/home.html
[4]pyspark.mlib.recommendation: _https://spark.apache.org/docs/2.1.1/api/python/modules/pyspark/mllib/recommendation.html
原文
英文原文:https://towardsdatascience.com/recommendation-systems-in-the-real-world-51e3948772f3