Skip to content

Latest commit

 

History

History
559 lines (329 loc) · 29 KB

07. 推荐系统.md

File metadata and controls

559 lines (329 loc) · 29 KB

7 推荐系统

​ 在实体店中可以观察到的一个共同趋势是,我们让销售人员在购物的同时指导和推荐我们相关的产品,在线零售平台,有数以万计的不同产品可用,我们必须自己驾驭 找到合适的产品。 情况是用户有太多的选择和选择,但他们不喜欢花很多时间浏览整个项目目录。 因此,推荐系统(Recommender Systems, RS)的作用对于推荐相关项目和推动客户转换至关重要。

​ 传统的实体店使用货架图来安排物品,这样可以提高高销售商品的可见度并增加收入,而在线零售商店需要根据每个客户的偏好保持动态,而不是让每个人保持相同。

​ 推荐系统主要用于以个性化方式向正确的用户自动建议正确的内容或产品,以增强整体体验。推荐系统在使用大量数据和学习理解特定用户的偏好方面非常强大。建议可帮助用户轻松浏览数百万种产品或大量内容(文章/视频/电影),并向他们展示他们可能喜欢或购买的正确项目/信息。因此,简单来说,推荐系统帮助用户发现信息。现在,这取决于用户决定推荐系统是否在推荐方面做得很好,他们可以选择产品/内容或丢弃并继续前进。用户的每个决策(正面或负面)都有助于在最新数据上重新训练推荐系统,以便能够提供更好的推荐。在本章中,我们将讨论推荐系统如何工作以及在引擎盖下使用的不同类型的技术来提出这些建议。我们还将使用PySpark构建推荐系统。

7.1 推荐

​ 在向用户推荐各种事物的意义上,推荐系统可用于多种目的。 例如,其中一些可能属于以下类别:

  • 零售产品
  • 工作
  • 朋友
  • 电影/音乐/视频/书籍
  • 广告

​ “推荐内容”部分完全取决于使用推荐系统的背景,并且可以通过提供用户可以购买的最可能的项目或通过在适当的时间展示相关内容来增加参与度来帮助企业增加收入。 推荐系统负责处理推荐的产品或内容应该是用户可能喜欢但不会自己发现的关键方面。 除此之外,推荐系统还需要一系列不同的建议,以保持足够的趣味性。 今天企业大量使用推荐系统的几个例子,如亚马逊产品,Facebook的朋友建议,LinkedIn的“你可能知道的人”,Netflix的电影,YouTube的视频,Spotify的音乐和Coursera的课程。

​ 从商业角度来看,这些建议的影响证明是巨大的,因此花费更多时间使这些推荐系统更有效和相关。 推荐系统在零售环境中提供的一些直接好处是:

  • 增加收入
  • 用户的正面评价和评分
  • 增加参与度

​ 对于广告推荐和其他内容推荐等其他垂直行业,推荐系统极大地帮助他们为用户找到正确的东西,从而增加了使用和订阅。 如果没有推荐系统,以个性化方式向数百万用户推荐在线内容或向每个用户提供通用内容可能会令人难以置信地脱离目标并导致对用户的负面影响。 ​ 现在我们了解了推荐系统的用法和功能,我们可以看看不同类型的推荐系统。可以构建主要有五种类型的推荐系统:

  • 基于人气的推荐系统
  • 基于内容的推荐系统
  • 基于推荐系统的协同过滤
  • 混合推荐系统
  • 基于推荐系统的关联规则挖掘

​ 除了最后一项,即基于推荐系统的关联规则挖掘之外,我们将简要介绍其中的每一项,因为它超出了本书的范围。

7.1.1 基于人气的推荐系统

​ 这是最基本,最简单的推荐系统,可用于向用户推荐产品或内容。 它建议基于大多数用户购买/浏览/喜欢/下载的项目/内容。 虽然实现简单易行,但由于建议对每个用户保持不变,因此不会产生相关结果,但它有时会优于某些更复杂的推荐系统。 实现此推荐系统的方式是简单地对各种参数上的项目进行排序,并推荐列表中排名靠前的项目。 如前所述,项目或内容可按以下方式排名:

  • 下载次数
  • 购买次数
  • 观看的次数
  • 评分最高
  • 共享的次数
  • 喜欢的次数

这种推荐系统直接向客户推荐最畅销或最受关注/购买的商品,从而增加了客户转换的机会。 该推荐系统的局限性在于它不是超个性化的。

7.1.2 基于内容的推荐系统

​ 这种类型的推荐系统向用户过去喜欢的用户推荐类似的项目。 因此,整个想法是计算任何两个项目之间的相似性得分,并基于用户兴趣的概况推荐给用户。 我们首先为每个项目创建项目配置文件。 现在可以通过多种方式创建这些项目配置文件,但最常见的方法是包含有关项目的详细信息或属性的信息。 例如,电影的项目配置文件可以具有各种属性的值,如恐怖,艺术,喜剧,动作,戏剧和商业,如下所示。

Movie Id Horror Art Comedy Action Drama Commercial
2310 0.01 0.3 0.8 0.0 0.5 0.9

​ 上面是项目配置文件的示例,每个项目都有一个表示其属性的类似向量。现在,让我们假设用户观看了10部这样的电影并且非常喜欢它们。 因此,对于该特定用户,我们最终得到表7-1中所示的项目矩阵。

Table 7-1. Movie Data

Movie ID Horror Art Comedy Action Drama Commercial
2444 0.2 0.0 0.8 0.0 0.5 0.7
2310 0.01 0.3 0.8 0.0 0.5 0.9
2388 0.0 0.3 0.85 0.0 0.8 0.9
2876 0.0 0.3 0.8 0.0 0.5 0.9
2345 0.0 0.3 0.8 0.0 0.5 0.9
2309 0.7 0.0 0.0 0.8 0.4 0.5
2366 0.1 0.15 0.8 0.0 0.5 0.6
2631 0.0 0.45 0.8 0.0 0.5 0.65
2974 0.6 0.3 0.0 0.6 0.5 0.3
2151 0.9 0.2 0.0 0.7 0.5 0.9

用户资料

​ 基于内容的推荐系统中的另一个组件是使用用户喜欢或评级的项目配置文件创建的用户配置文件。 假设用户喜欢表7-1中的电影,用户配置文件可能看起来像一个矢量,这只是项目矢量的平均值。 用户个人资料可能如下所示。

User ID Horror Art Comedy Action Drama Commercial
1A92 0.251 0.23 0.565 0.21 0.52 0.725

​ 这种创建用户配置文件的方法是最基准的方法之一,还有其他复杂的方法可以创建更丰富的用户配置文件,例如规范化值,加权值等。下一步是基于之前的偏好推荐给用户可能会喜欢的这个项目(电影) 。 因此,计算用户简档和项目简档之间的相似性得分并相应地进行排序。 相似度得分越多,用户喜欢电影的机会就越高。 有几种方法可以计算相似性得分。

欧几里德距离

​ 略

Cosine Similarity(余弦相似度)

​ 略

让我们总结一下基于内容的推荐系统的一些优点和缺点。

好处: 1.基于内容的推荐系统独立于其他用户的数据工作,因此可以应用于个人的历史数据。 2.可以很容易地理解推荐系统背后的基本原理,因为是基于用户配置文件和项目配置文件之间的相似性得分。 3.仅基于用户的历史兴趣和偏好,还可以向用户推荐新的和未知的项目。 缺点: 1.项目配置文件可能存在偏差,可能无法反映确切的属性值,并可能导致错误的建议。 2.建议完全取决于用户的历史,并且只能推荐与历史观看/喜欢的项目类似的项目,并且不考虑访问者的新兴趣或喜好。

7.1.3 基于协同过滤的推荐系统

​ 基于协同过滤的推荐系统不需要项目属性或描述的建议; 相反,它适用于用户项目交互。 这些互动可以通过各种方式来衡量,例如评级,购买的项目,花费的时间,在另一个平台上共享等等。在深入了解协同过滤之前,让我们退后一步,思考我们如何在日常基础上做出某些决定 - 决策:

​ 1.要观看哪部电影 ​ 2.要读哪本书 ​ 3.去哪家餐馆 ​ 4.前往哪个地方

​ 我们问朋友! 我们在某些方面要求与我们相似的人提出建议,并且与我们的品味和喜好相同。 我们的兴趣在某些方面匹配,因此我们相信他们的建议。 这些人可以是我们的家庭成员,朋友,同事,亲戚或社区成员。 在现实生活中,很容易知道谁是这个圈子里的人,但是当谈到在线推荐时,协同过滤的关键任务是找到与你最相似的用户。 每个用户可以由包含用户项交互的反馈值的向量表示。 让我们首先理解用户项矩阵,以了解协同过滤方法。

User Item Matrix

​ 用户项矩阵正是名称所暗示的。 在行中,我们拥有所有独特的用户; 沿着列,我们有所有独特的项目。 这些值用反馈或交互分数填充,以突出用户对该产品的喜好或不喜欢。 简单的用户项矩阵可能如表7-2所示。

Table 7-2. User Item Matrix

User ID Item 1 Item 2 Item 3 Item 4 Item 5 Item n
14SD 1 4 5
26BB 3 3 1
24DG 1 4 1 5 2
59YU 2 5
21HT 3 2 1 2 5
68BC 1 5
26DF 1 4 3 3
25TR 1 4 5
33XF 5 5 5 1 5 5
73QS 1 3 1

​ 正如您所看到的,用户项目矩阵通常非常稀疏,因为有数百万个项目,并且每个用户不与每个项目交互; 所以矩阵包含很多空值。 矩阵中的值通常是基于用户与该特定项的交互推导出的反馈值。 UI矩阵中可以考虑两种类型的反馈。

明确的反馈

​ 这种反馈通常是在用户在交互之后对项目进行评级并且已经经历项目特征时。 评级可以是多种类型。

  • 评分为1-5分
  • 推荐给他人的简单评级项目(是或否或从不)
  • 喜欢这个项目(是或否)

​ 显式反馈数据包含非常有限的数据点,因为即使在购买或使用该项目后,很小一部分用户也会花时间给出评级。 一个完美的例子可以是电影,因为即使在观看之后,很少有用户给出评级。 因此,仅根据显式反馈数据构建RS可能会使我们陷入困境,尽管数据本身噪声较小但有时不足以构建RS。

隐含的反馈

​ 这种反馈不是直接的,主要是从用户在在线平台上的活动推断出来的,并且是基于与商品的互动。例如,如果用户购买了商品,将其添加到购物车,查看并花费了很多 在查看关于该项目的信息的时间上,这表明用户对该项目具有更高的兴趣。 隐式反馈值易于收集,每个用户在通过在线平台浏览时都可以获得大量数据点。 隐式反馈的挑战在于它包含大量噪声数据,因此不会在建议中增加太多价值。 ​ 现在我们了解了进入该矩阵的UI矩阵和值类型,我们可以看到不同类型的协同过滤(CF)。 CF主要有两种:

  • 最近邻居CF
  • 基于潜伏因子的CF.

Nearest Neighbors Based CF(最近邻居CF)

​ 这个CF的工作原理是找出最相似的用户,他们也喜欢或不喜欢与活跃用户相同的项目(对于我们试图推荐的用户)。最近邻居的协同过滤涉及两个步骤。 第一步是找到k-最近邻居,第二步是预测活跃用户喜欢特定项目的等级或可能性。可以使用我们在本章中讨论的一些早期技术找到**k-nn。 余弦相似度或欧几里德距离等度量可以帮助我们根据两个群体喜欢或不喜欢的常见项目,从用户总数中找到活跃用户的大多数类似用户。 也可以使用的其他指标之一是Jaccard相似性。 让我们看一个例子来理解这个指标 - 回到早期的用户项矩阵,只取五个用户的数据,如表7-1**所示。

​ 假设我们共有五个用户,我们希望找到活动用户的两个最近邻居(14SD)。可以使用找到Jaccard相似性

sim(x,y)=|Rx ∩ Ry|/ | Rx ∪ Ry|

​ 因此,这是任何两个用户共同评定的项目数除以用户评定的项目总数: sim(user1,user2)= 1/5 = 0.2,因为它们只评价了共同的第2项。

​ 具有活动用户的四个用户中的其余用户的相似性得分将看起来如表7-4中所示。

Table 7-4. User Similarity Score

User ID Similarity Score
14SD 1
26BB 0.2
24DG 0.6
59YU 0.677
26DF 0.75

​ 因此,根据Jaccard的相似性,前两个最近的邻居是第四和第五个用户。 但是,这种方法存在一个主要问题,因为Jaccard相似度在计算相似性得分时不考虑反馈值,只考虑评定的常用项目。因此,用户可能会对许多项目进行共同评估,但可能有人将其评为高分,而另一个可能将评分较低。 Jaccard相似度得分仍然可能最终得到两个用户的高分,这是违反直觉的。 在上面的示例中,显而易见的是,活动用户与第三用户(24DG)最相似,因为他们对三个共同项目具有完全相同的评级,而第三用户甚至不出现在前两个最近邻居中。 因此,我们可以选择其他指标来计算k近邻(KNN)。

Missing Values

​ 用户项矩阵将包含许多缺失值,原因很简单,因为有很多项,而不是每个用户都与每个项交互。 有两种方法可以处理UI矩阵中的缺失值。

  • 将缺失值替换为0。
  • 将缺失值替换为用户的平均评级。

普通项目的评级越相似,邻居对活跃用户越近。 有两类基于最近邻居的CF.

  • 基于用户的CF.
  • 基于项目的CF.

​ 两个推荐系统之间的唯一区别在于,在基于用户的情况下,我们找到k个最近的用户,并且在基于项目的CF中,我们找到要向用户推荐的k个最近的项目。 我们将看到推荐如何在基于用户的推荐系统中工作。 ​ 顾名思义,在基于用户的CF中,整个想法是找到与活跃用户最相似的用户,并向活跃用户推荐类似用户购买/评价的项目,他没有看到/买过 /尝试过。 这种推荐系统的假设是,如果两个或更多用户对一堆项目有相同的意见,那么他们也可能对其他项目有相同的意见。 让我们看一个例子来理解基于用户的协同过滤: ​ 有三个用户,我们要向活跃用户推荐一个新项目。 对于活跃用户的项目喜欢和不喜欢,这两个用户中的其余用户是最接近的两个邻居。

​ 所有三个用户都对某个特定的相机品牌评分非常高,前两个用户是基于相似性得分的活跃用户最相似的用户。

​ 现在,前两个用户也评价了另一个项目(Xbox 360)非常高,第三个用户尚未与之交互,也没有看到如图7-3所示。 使用此信息,我们尝试预测活动用户将给予新项目(Xbox 360)的评级,这又是该特定项目(XBOX 360)的最近邻居的评级的加权平均值。

基于潜在因子的CF

​ 这种协同过滤也使用用户项矩阵,但不是找到最近邻居并预测评级,而是尝试将UI矩阵分解为两个潜在因子矩阵。 潜在因子是从原始值导出的值。 它们与观察到的变量有内在联系。 这些新的矩阵在等级方面要低得多,并且包含潜在因素。 这也称为矩阵分解。 让我们举个例子来理解矩阵分解过程。 我们可以将秩r的m×n大小矩阵“A”分解为两个较小的秩矩阵X,Y,使得X和Y的点积产生原始A矩阵。 如果我们有一个矩阵A,如表7-5所示,

Table 7-5. Latent Factor Calculation

1 2 3 5
2 4 8 12
3 6 7 13

​ 然后我们可以将所有列值写为第一列和第三列(A1和A3)的线性组合。

A1 = 1 * A1 + 0 * A3 A2 = 2 * A1 + 0 * A3 A3 = 0 * A1 + 1 * A3 A4 = 2 * A1 + 1 * A3

​ 现在我们可以创建两个小等级矩阵,使得这两个矩阵之间的乘积将返回原始矩阵A.

    +----+----+
    | 1  |  3 |
    +----+----+              
x = | 2  |  8 |
    | 3  |  7 |
    +----+----+
    
	+----+----+----+----+
	| 1  | 2  |  0 |  2 |
y = +----+----+----+----+
	| 0  |  0 |  1 |  1 | 
	+----+----+----+----+

​ X包含A1和A3的列值,Y包含线性组合的系数。 ​ X和Y之间的点积导致矩阵'A'(原始矩阵)。

​ 考虑到与表7-2中所示相同的用户项矩阵,我们将其分解或分解为两个较小的秩矩阵。

  • 用户潜在因素矩阵
  • 项目潜在因素矩阵

​ 用户潜在因子矩阵包含映射到这些潜在因子的所有用户,类似地,项目潜在因子矩阵包含映射到每个潜在因子的列中的所有项目。使用机器学习优化技术(例如交替最小二乘法)完成找到这些潜在因素的过程。用户项目矩阵被分解成潜在因子矩阵,使得任何项目的用户评级是用户的潜在因子值和项目潜在因子值之间的乘积。主要目标是最小化整个用户项目矩阵评级和预测项目评级的误差平方和。例如,项目2的第二用户(26BB)的预测评级将是评级(user2,item2)=

​ 每个预测的评级都会有一些误差,因此成本函数成为预测评级和实际评级之间的平方误差的总和。训练推荐模型包括以这样一种方式学习这些潜在因素,即最小化整体评级的SSE(sum of squared errors)。我们可以使用ALS方法找到最低的SSE。 ALS的工作方式是首先修复用户潜在因子值并尝试改变项目潜在因子值,以使整体SSE降低。在下一步骤中,项目潜在因子值保持固定,并且更新用户潜在因子值以进一步减少SSE。这在用户矩阵和项目矩阵之间保持交替,直到SSE不再减少为止。

好处:

  • 不需要项目的内容信息,并且可以基于有价值的用户项目交互来做出推荐。
  • 基于其他用户的个性化体验。

限制:

  • 冷启动问题:如果用户没有项目交互的历史数据。 然后RC无法预测新用户的k近邻,也无法提出建议。
  • 缺少值:由于项目数量巨大,并且很少有用户与所有项目进行交互,因此某些项目从未被用户评级,因此无法推荐。
  • 无法推荐新项目或未评级项目:如果项目是新项目但用户尚未查看,则在其他用户与其进行交互之前,不建议现有用户使用该项目。
  • 准确性差:由于许多组件不断变化,例如用户的兴趣,物品的保质期有限以及物品评级很少,因此表现不佳。

混合推荐系统

​ 顾名思义,混合推荐系统包括来自多个推荐系统的输入,使其在向用户提出有意义的建议方面更加强大和相关。正如我们所看到的,使用单个推荐系统有一些限制,但结合使用它们可以克服其中的一小部分,因此能够推荐用户发现更有用和个性化的项目或信息。混合推荐系统可以以特定方式构建,以满足业务需求。其中一种方法是构建单独的推荐系统,并在将它们推荐给用户之前组合来自多个推荐系统输出的推荐,如图7-5所示。

​ 另一种方法是利用基于内容的推荐者优势,并将其用作基于协作过滤的推荐的输入,以向用户提供更好的推荐。 这种方法也可以颠倒过来,协同过滤可以用作基于内容的推荐的输入,如图7-6所示。

​ 混合建议还包括使用其他类型的建议,例如基于人口统计和基于知识的建议,以提高其建议的绩效。 混合推荐系统已成为各种业务的组成部分,以帮助其用户使用正确的内容,从而获得很多价值。

7.2 Code

Step 1: Create the SparkSession Object

​ 创建SparkSession

[In]: from pyspark.sql import SparkSession
[In]: spark=SparkSession.builder.appName('lin_reg').getOrCreate()

Step 2: Read the Dataset

​ 读取数据

[In]: df=spark.read.csv('movie_ratings_df.csv',inferSchema=True,header=True)

Step 3: Exploratory Data Analysis

​ 探索性数据分析

​ 数据大小

[In]: print((df.count(), len(df.columns)))
[Out]: (100000,3)

​ 列名

[In]: df.printSchema()
[Out]: root
        |-- userId: integer (nullable = true)
        |-- title: string (nullable = true)
        |-- rating: integer (nullable = true)

​ 总共有三列,其中两列是数字,标题是分类。 使用PySpark构建RS的关键是我们需要以数字形式使用user_id和item_id。 因此,我们稍后会将电影标题转换为数值。 我们现在使用rand函数查看数据帧的几行,以随机顺序混洗记录。

[In]: df.orderBy(rand()).show(10,False)
[In]: df.groupBy('userId').count().orderBy('count',ascending=False).show(10,False)
[In]: df.groupBy('userId').count().orderBy('count',ascending=True).show(10,False)

​ 记录数量最多的用户评分为737部电影,每位用户评分至少20部电影。

[In]: df.groupBy('title').count().orderBy('count',ascending=False).show(10,False)

​ 评分最高的电影是星球大战(1977),被评为583次,每部电影至少被1位用户评价。

Step 4: Feature Engineering

​ 我们现在使用StringIndexer将电影标题列从分类转换为数值。 我们从PySpark库导入stringIndexerIndextostring

[In]: from pyspark.sql.functions import *
[In]: from pyspark.ml.feature import StringIndexer, IndexToString

​ 接下来,我们通过提及输入列和输出列来创建stringindexer对象。 然后我们将对象放在数据框上并将其应用于影片标题列以创建具有数值的新数据框。

[In]: stringIndexer = StringIndexer(inputCol="title",outputCol="title_new")
[In]: model = stringIndexer.fit(df)
[In]: indexed = model.transform(df)

​ 让我们通过查看新数据帧(索引)的几行来验证标题列的数值。

[In]: indexed.show(10)
[Out]:

​ 我们可以看到,我们现在有一个额外的列(title_new),其中的数值表示电影标题。 如果user_id也是分类类型,我们必须重复相同的过程。 为了验证电影数量,我们在一个新的数据帧上重新运行groupBy

[In]: indexed.groupBy('title_new').count().
         orderBy('count',ascending=False).show(10,False)

Step 5: Splitting the Dataset

​ 现在我们已经准备好用于构建推荐器模型的数据,我们可以将数据集分成训练和测试集。 我们将其分成75到25比率来训练模型并测试其准确性。

[In]: train,test=indexed.randomSplit([0.75,0.25])
[In]: train.count()
[Out]: 75104
[In]: test.count()
[Out]: 24876

Step 6: Build and Train Recommender Model

​ 我们从PySpark ml库导入ALS函数,并在训练数据集上构建模型。可以调整多个超参数以改善模型的性能。 其中两个重要的是非负='True'不会在建议中创建负评级,而coldStartStrategy ='drop'可以防止任何NaN评级的预测。

[In]: from pyspark.ml.recommendation import ALS
[In]: rec=ALS(maxIter=10,
              regParam=0.01,
              userCol='userId',
              itemCol='title_new',
              ratingCol='rating',
              nonnegative=True,
              coldStartStrategy="drop")
[In]: rec_model=rec.fit(train)

Step 7: Predictions and Evaluation on Test Data

​ 整个练习的最后一部分是检查模型在看不见或测试数据上的表现。 我们使用transform函数对测试数据进行预测,使用RegressionEvaluate检查模型在测试数据上的RMSE值

[In]: predicted_ratings=rec_model.transform(test)
[In]: predicted_ratings.printSchema()
root
    |-- userId: integer (nullable = true)
    |-- title: string (nullable = true)
    |-- rating: integer (nullable = true)
    |-- title_new: double (nullable = false)
    |-- prediction: float (nullable = false)
[In]: predicted_ratings.orderBy(rand()).show(10)
[Out]:



[In]: from pyspark.ml.evaluation import RegressionEvaluator
[In]: evaluator=RegressionEvaluator(metricName='rmse',
                                    predictionCol='prediction',
                                    labelCol='rating')
[In]: rmse=evaluator.evaluate(predictions)
[In] : print(rmse)
[Out]: 1.0293574739493354

​ RMSE不是很高; 我们在实际评级和预测评级中出现一个误差。通过调整模型参数和使用混合方法可以进一步改善这一点。

Step 8: Recommend Top Movies That Active User Might Like

​ 在检查模型的性能并调整超参数之后,我们可以继续向用户推荐他们没有看到过的电影。

    # 第一步是在数据框中创建一个独特电影列表。

[In]: unique_movies=indexed.select('title_new').distinct()
[In]: unique_movies.count()
[Out]: 1664
    # 因此,我们在数据帧中共有1,664部不同的电影。

[In]: a = unique_movies.alias('a')  #  alias 对列进行重命名

    # 我们可以选择数据集中我们需要推荐其他电影的任何用户。在我们的例子中,我们继续使用userId = 85。
    
[In]: user_id=85
    
    # 我们将过滤此活跃用户已评级或看过的电影。
    
[In]: watched_movies=indexed.
                     filter(indexed['userId'] == user_id).
                     select('title_new').distinct()
[In]: watched_movies.count()
[Out]: 287
    
[In]: b=watched_movies.alias('b')  #  alias 对列进行重命名

    # 因此,在这个活跃用户已经评价的1,664部电影中,总共有287部独特电影。所以,我们想推荐其余1,377件商品中的电影。我们现在将两个表结合起来,通过从连接表中过滤空值来查找我们可以推荐的电影。

[In]: total_movies=a.join(b, a.title_new == b.title_new,how='left')
[In]: total_movies.show(10,False)


[In]: remaining_movies=total_movies.
                           where(col("b.title_new").isNull()).
                           select(a.title_new).distinct()
[In]: remaining_movies.count()
[Out]: 1377
    
[In]: remaining_movies=remaining_movies.withColumn("userId",lit(int(user_id)))
[In]: remaining_movies.show(10,False)

    # 最后,我们现在可以使用我们之前构建的推荐器模型对活动用户的剩余电影数据集进行预测。 我们仅过滤了一些预测评分最高的热门推荐。

[In]: recommendations=rec_model.
                      transform(remaining_movies).
                      orderBy('prediction',ascending=False)
[In]: recommendations.show(5,False)

    #因此,电影标题1433和1322具有该活动用户的最高预测评级(85)。 我们可以通过将电影标题添加回建议来使其更直观。 我们使用Indextostring函数创建一个返回电影标题的附加列。
    
[In]: movie_title = IndexToString(inputCol="title_new",
                                 outputCol="title",
                                 labels=model.labels)
[In]: final_recommendations=movie_title.transform(recommendations)
[In]: final_recommendations.show(10,False)   

​ 因此,对userId(85)的建议是Boys,Les(1997)和Faust(1994)。 这可以很好地包装在单个函数中,该函数按顺序执行上述步骤并为活动用户生成建议。 完整的代码可以在内置此功能的GitHub仓库中获得。

总结

​ 在本章中,我们讨论了各种类型的推荐模型以及每种模型的优势和局限性。 然后,我们使用ALS方法在PySpark中创建了一个基于协作过滤的推荐系统,以向用户推荐电影。