python-flask-认识协同过滤算法

推荐系统系列


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

协同过滤是一种可以根据相似用户反应过滤掉用户可能喜欢的项目的技术。


提示:以下是本篇文章正文内容,下面案例可供参考

一、数据集

该矩阵显示了五个用户,他们以 1 到 5 的等级对某些项目进行了评分。例如,第一个用户对第三个项目的评分为 4。

在大多数情况下,矩阵中的单元格是空的,因为用户只对几个项目进行评分。每个用户都不太可能对每个可用项目进行评分或做出反应。具有大部分空单元格的矩阵称为稀疏矩阵,与之相反(大部分填充矩阵)称为密集矩阵。

已经收集了许多数据集并提供给公众用于研究和基准测试。以下是您可以选择的高质量数据源列表。

最好的入门方法是GroupLens Research 收集的MovieLens数据集。特别是,MovieLens 100k 数据集是一个稳定的基准数据集,有 943 个用户对 1682 部电影给出了 100,000 个评分,每个用户至少评分了 20 部电影。

该数据集由许多文件组成,其中包含有关电影、用户以及用户对他们观看的电影的评分的信息。感兴趣的是以下内容:

u.item:电影列表
u.data:用户给出的评分列表
包含评级的文件u.data是用户 ID、项目 ID、评级和时间戳的制表符分隔列表。文件的前几行如下所示:
在这里插入图片描述

如上所示,该文件告诉用户对特定电影的评分。该文件包含 100,000 个此类评分,将用于预测用户未看过的电影的评分。

二、协同过滤涉及的步骤

要构建一个可以根据其他用户的喜好自动向用户推荐物品的系统,第一步是找到相似的用户或物品。第二步是预测用户尚未评分的项目的评分。因此,您将需要这些问题的答案:

  • 您如何确定哪些用户或项目彼此相似?

  • 鉴于您知道哪些用户相似,您如何根据相似用户的评分确定用户对某项的评分?

  • 你如何衡量你计算的评级的准确性?

前两个问题没有单一答案。协同过滤是一系列算法,其中有多种方法可以找到相似的用户或项目,并且有多种方法可以根据相似用户的评分来计算评分。根据您所做的选择,您最终会得到一种协同过滤方法。您将在本文中看到查找相似性和预测评分的各种方法。

要记住的重要一点是,在纯粹基于协同过滤的方法中,相似度不是使用用户年龄、电影类型或任何其他有关用户或项目的数据等因素来计算的。它仅根据用户对项目的评分(显式或隐式)计算。例如,如果两个用户对十部电影给出相同的评分,尽管他们的年龄相差很大,则可以认为他们相似。

关于如何衡量预测准确性的第三个问题也有多个答案,其中包括可以在许多地方使用的误差计算技术,而不仅仅是基于协同过滤的推荐器。

测量结果准确性的方法之一是均方根误差 (RMSE),您可以在其中预测评分值已知的用户-项目对的测试数据集的评分。已知值和预测值之间的差异将是误差。将测试集的所有误差值平方,找到平均值(或平均值),然后取该平均值的平方根以获得 RMSE。

衡量准确性的另一个指标是平均绝对误差 (MAE),您可以在其中找到误差的绝对值,然后取所有误差值的平均值。

此时您无需担心 RMSE 或 MAE 的详细信息,因为它们很容易作为 Python 中各种包的一部分获得,您将在本文后面看到它们。

现在让我们看看协同过滤家族中不同类型的算法。

1.基于内存

第一类包括基于内存的算法,其中将统计技术应用于整个数据集以计算预测。

要找到用户U对项目I的评分R,该方法包括:

查找与U相似且对项目I进行评分的用户
根据上一步中找到的用户评分计算评分R
您将在以下部分中详细了解它们中的每一个。

如何根据评分找到相似用户
为了理解相似度的概念,让我们首先创建一个简单的数据集。

该数据包括四个用户A、B、C和D,他们对两部电影进行了评分。评分存储在列表中,每个列表包含两个数字,表示每部电影的评分:

A的评分为[1.0, 2.0]。
B的评分为[2.0, 4.0]。
C的评级是[2.5, 4.0]。
D评分为[4.5, 5.0].
从视觉线索开始,将用户对两部电影的评分绘制在图表上并寻找模式。该图如下所示:
在这里插入图片描述
在上图中,每个点代表一个用户,并根据他们对两部电影的评分进行绘制。

查看点之间的距离似乎是估计相似度的好方法,对吧?您可以使用两点之间的欧几里德距离公式找到距离。您可以使用scipy以下程序中所示的功能:

代码如下(示例):

'''
如何根据评分找到相似用户

'''

>>> from scipy import spatial

>>> a = [1, 2]
>>> b = [2, 4]
>>> c = [2.5, 4]
>>> d = [4.5, 5]

>>> spatial.distance.euclidean(c, a)
2.5
>>> spatial.distance.euclidean(c, b)
0.5
>>> spatial.distance.euclidean(c, d)
2.23606797749979

如上图,可以scipy.spatial.distance.euclidean用来计算两点之间的距离。用它来计算A、B和D的评分与C的评分之间的距离表明,就距离而言,C的评分最接近B的评分。

即使通过查看图表,您也可以看到用户C最接近B。但是只有A和D,C更接近谁?

您可以说C在距离方面更接近D。但从排名来看, C的选择似乎与A的选择一致,而不是D,因为A和C对第二部电影的喜爱程度几乎是第一部电影的两倍,但D都喜欢这两部电影相等。

那么,你可以用什么来识别欧几里得距离无法识别的模式呢?可以使用将点连接到原点的线之间的角度来做出决定吗?您可以查看将图形原点连接到各个点的线之间的角度,如下所示:

在这里插入图片描述
该图显示了将每个点连接到原点的四条线。A和B的线重合,使它们之间的角度为零。

你可以认为,如果线之间的角度增加,那么相似度就会降低,如果角度为零,那么用户非常相似。

要使用角度计算相似度,您需要一个函数,该函数为较小的角度返回较高的相似度或较小的距离,并为较高的角度返回较低的相似度或较大的距离。角度的余弦是随着角度从 0 增加到 180 时从 1 减小到 -1 的函数。

您可以使用角度的余弦来查找两个用户之间的相似性。角度越高,余弦越低,因此用户的相似度越低。您还可以通过从 1 中减去该角度的余弦值来获得用户之间的余弦距离。

scipy有一个计算向量余弦距离的函数。它为更高的角度返回更高的值:

>>> from scipy import spatial
>>> a = [1, 2]
>>> b = [2, 4]
>>> c = [2.5, 4]
>>> d = [4.5, 5]

>>> spatial.distance.cosine(c,a)
0.004504527406047898

>>> spatial.distance.cosine(c,b)
0.004504527406047898

>>> spatial.distance.cosine(c,d)
0.015137225946083022

>>> spatial.distance.cosine(a,b)
0.0

C和A的向量之间的较小角度给出了较低的余弦距离值。如果您想以这种方式对用户相似度进行排名,请使用余弦距离。

注意:在上面的例子中,只考虑了两部电影,这样更容易在二维中可视化评分向量。这样做只是为了使解释更容易。

具有多个项目的实际用例将涉及评级向量中的更多维度。您可能还想研究余弦相似度的数学。

请注意,尽管用户A和B具有不同的评级,但在余弦相似度度量中被认为是绝对相似的。这在现实世界中其实是很常见的,像用户A这样的用户,就是你可以称之为难打分的人。一个例子是一个电影评论家,他总是给出低于平均水平的评分,但他们列表中项目的排名将类似于像B这样的平均评分者。

要考虑此类个人用户偏好,您需要通过消除他们的偏见将所有用户带到同一水平。您可以通过从该用户评分的每个项目中减去该用户对所有项目的平均评分来做到这一点。这是它的样子:

对于用户A,评分向量[1, 2]具有平均值1.5。从每个评级中减去1.5会给你向量[-0.5, 0.5]。
对于用户B,评分向量[2, 4]具有平均值3。从每个评级中减去3会给你向量[-1, 1]。
通过这样做,您将每个用户的平均评分值更改为 0。尝试对用户C和D执行相同的操作,您会看到评分现在已调整为所有用户的平均评分为 0 ,这使它们都处于同一水平并消除了它们的偏见。

调整后的向量之间夹角的余弦称为中心余弦。这种方法通常在向量中存在大量缺失值时使用,您需要放置一个公共值来填充缺失值。

用随机值填充评级矩阵中的缺失值可能会导致不准确。填充缺失值的一个好选择可能是每个用户的平均评分,但用户A和B的原始平均值1.5分别3为.1.53

但是在调整值之后,两个用户的居中平均值0为0

欧几里得距离和余弦相似度是您可以用来查找彼此相似的用户甚至彼此相似的项目的一些方法。(上面使用的函数计算余弦距离。要计算余弦相似度,请从 1 中减去距离。)

2.如何计算评级

在确定了与用户U相似的用户列表后,您需要计算U对某个项目I的评分R。同样,就像相似性一样,您可以通过多种方式做到这一点。

您可以预测,用户对项目I的评分R将接近与U最相似的前 5 名或前 10 名用户对I的评分平均值。n 个用户给出的平均评分的数学公式如下所示:
在这里插入图片描述

平均评分公式
这个公式表明,n个相似用户给出的平均评分等于他们给出的评分之和除以相似用户的数量,即n。

在某些情况下,您找到的n 个相似用户与目标用户U的相似度不同。其中前 3 个可能非常相似,其余的可能不像前 3 个那样与U相似。在这种情况下,您可以考虑一种方法,其中最相似用户的评分比第二相似用户更重要等等。加权平均可以帮助我们实现这一目标。

在加权平均方法中,您将每个评分乘以相似性因子(它表明用户的相似程度)。通过乘以相似性因子,您可以为评分添加权重。重量越重,评级就越重要。

将充当权重的相似性因子应该是上面讨论的距离的倒数,因为较小的距离意味着较高的相似性。例如,您可以从 1 中减去余弦距离以获得余弦相似度。

使用与目标用户U相似的每个用户的相似性因子S,您可以使用以下公式计算加权平均值:
在这里插入图片描述

在上面的公式中,每个评分都乘以给出评分的用户的相似度。用户U的最终预测评分将等于加权评分之和除以权重之和。

注意:如果您想知道为什么加权评分的总和是除以权重的总和而不是除以n,请考虑这一点:在前面的平均值公式中,您除以n时,权重的值是1。

在寻找平均值时,分母始终是权重的总和,在正常平均值的情况下,权重为 1 意味着分母将等于n。

使用加权平均值,您可以按照相似度的顺序更多地考虑相似用户的评分。

现在,您知道如何找到相似的用户以及如何根据他们的评分计算评分。还有一种协同过滤的变体,您可以通过查找彼此相似的项目而不是用户并计算评分来预测评分。您将在下一节中了解这种变化。


基于用户与基于项目的协同过滤

上面解释的示例中的技术,其中评级矩阵用于根据他们给出的评级来找到相似的用户,称为基于用户或用户-用户协同过滤。如果你使用评分矩阵根据用户给它们的评分来寻找相似的物品,那么这种方法称为基于物品或物品的协同过滤。

这两种方法在数学上非常相似,但两者之间存在概念上的差异。以下是两者的比较:

  • 基于用户:对于一个用户U,根据给定项目评分组成的评分向量确定一组相似用户,通过从相似度中挑选出 N
    个用户来找到尚未评分的项目I的评分列出谁对项目I进行了评分,并根据这 N 个评分计算评分。
  • 基于项目:对于一个项目I,具有基于由接收到的用户评分组成的评分向量确定的一组相似项目,通过从相似度中挑选 N
    个项目来找到尚未对其评分的用户U的评分列出已被U评分的列表,并根据这 N 个评分计算评分。
    基于项目的协同过滤是由亚马逊开发的。在用户多于项目的系统中,基于项目的过滤比基于用户的过滤更快、更稳定。它之所以有效,是因为通常一个项目收到的平均评分不会像用户对不同项目的平均评分那样快速变化。当评分矩阵稀疏时,它也比基于用户的方法表现更好。

虽然,基于项目的方法对于具有浏览或娱乐相关项目(如 MovieLens)的数据集表现不佳,但它给出的建议对目标用户来说似乎非常明显。这样的数据集使用矩阵分解技术可以看到更好的结果,您将在下一节中看到,或者使用混合推荐器,通过使用基于内容的过滤也考虑到数据的内容,如流派。

您可以使用库Surprise快速尝试不同的推荐算法。(您将在本文后面看到更多关于此的内容。)

基于模型

第二类涵盖基于模型的方法,其中涉及减少或压缩大型但稀疏的用户项目矩阵的步骤。为了理解这一步,对降维的基本了解会很有帮助。

降维
在 user-item 矩阵中,有两个维度:

用户数
商品数量
如果矩阵大部分是空的,减少维度可以提高算法在空间和时间方面的性能。您可以使用矩阵分解或自动编码器等各种方法来执行此操作。

矩阵分解可以看作是将大矩阵分解为较小矩阵的乘积。这类似于整数的因式分解,其中12可以写为6 x 2或4 x 3。在矩阵的情况下,具有维度的矩阵Am x n可以简化为两个具有维度的矩阵X和Ym x p的乘积和p x n。

注意:在矩阵乘法中,只有当X中的列数等于 Y 中的行数时,矩阵X才能与Y相乘。因此,两个约化矩阵具有共同的维度p。

根据用于降维的算法,降维矩阵的数量也可以多于两个。

简化后的矩阵实际上分别代表了用户和项目。第一个矩阵中的m行代表m个用户,p列告诉您用户的特征或特征。具有n 个项目和p个特征的项目矩阵也是如此。这是矩阵分解的示例:

使用降维将矩阵分解为两个矩阵
矩阵分解
在这里插入图片描述

在上图中,矩阵被简化为两个矩阵。左边是m个用户的用户矩阵,上边是n个项目的项目矩阵。评级4被降低或分解为:

用户向量(2, -1)
项向量(2.5, 1)
用户矩阵中的两列和项目矩阵中的两行称为潜在因子,表示用户或项目的隐藏特征。分解的可能解释如下所示:

假设在一个用户向量(u, v)中,u表示用户对恐怖类型的喜欢程度,并v表示他们对浪漫类型的喜爱程度。

用户向量(2, -1)因此代表喜欢恐怖电影并给予正面评价并且不喜欢浪漫电影并给予负面评价的用户。

假设在一个项目向量(i, j)中,i表示一部电影在多大程度上属于恐怖类型,并j表示该电影在多大程度上属于浪漫类型。

这部电影(2.5, 1)的恐怖等级为2.5,浪漫等级为1。使用矩阵乘法规则将其乘以用户向量可以得到(2 * 2.5) + (-1 * 1) = 4.

因此,这部电影属于恐怖类型,用户本可以对其进行评分5,但稍微加入浪漫导致最终评分下降到4.

因子矩阵可以提供有关用户和项目的此类见解,但实际上它们通常比上面给出的解释复杂得多。这些因素的数量可以从一到数百甚至数千不等。这个数字是模型训练过程中需要优化的事情之一。

在示例中,您有两个电影类型的潜在因素,但在实际场景中,无需过多分析这些潜在因素。这些是数据中的模式,无论您是否破译它们的潜在含义,它们都会自动发挥作用。

潜在因素的数量以某种方式影响推荐,其中因素的数量越多,推荐就越个性化。但是太多的因素会导致模型过拟合。

使用 Python 构建推荐器

Python 中有很多库和工具包,它们提供了各种算法的实现,您可以使用这些算法来构建推荐器。但是在理解推荐系统时你应该尝试的是Surprise。

Surprise 是一个 Python SciKit,它带有各种推荐算法和相似度指标,可以轻松构建和分析推荐系统。

以下是使用 pip 安装它的方法:

$ pip install numpy
$ pip install scikit-surprise

以下是使用 conda 安装它的方法:

$ conda install -c conda-forge scikit-surprise
注意:如果您希望按照示例进行操作,也建议您安装Pandas 。

要使用 Surprise,您应该首先了解其中可用的一些基本模块和类:

该Dataset模块用于从文件、Pandas 数据框甚至可用于实验的内置数据集中加载数据。(MovieLens 100k 是 Surprise 中的内置数据集之一。)要加载数据集,一些可用的方法是:

Dataset.load_builtin()
Dataset.load_from_file()
Dataset.load_from_df()
该类Reader用于解析包含评级的文件。它接受数据的默认格式是,每个评级按顺序存储在单独的行中user item rating。可以使用参数配置此顺序和分隔符:

line_format是一个字符串,它存储数据的顺序,字段名称用空格分隔,如"item user rating".
sep用于指定字段之间的分隔符,例如’,’.
rating_scale用于指定评分等级。默认值为(1, 5).
skip_lines用于指示在文件开头要跳过的行数。默认值为0.
这是一个可用于从 Pandas 数据帧或内置 MovieLens 100k 数据集加载数据的程序:

# load_data.py

import pandas as pd
from surprise import Dataset
from surprise import Reader

# This is the same data that was plotted for similarity earlier
# with one new user "E" who has rated only movie 1
ratings_dict = {
    "item": [1, 2, 1, 2, 1, 2, 1, 2, 1],
    "user": ['A', 'A', 'B', 'B', 'C', 'C', 'D', 'D', 'E'],
    "rating": [1, 2, 2, 4, 2.5, 4, 4.5, 5, 3],
}

df = pd.DataFrame(ratings_dict)
reader = Reader(rating_scale=(1, 5))

# Loads Pandas dataframe
data = Dataset.load_from_df(df[["user", "item", "rating"]], reader)
# Loads the builtin Movielens-100k data
movielens = Dataset.load_builtin('ml-100k')

在上面的程序中,数据存储在字典中,该字典被加载到 Pandas 数据帧中,然后从 Surprise 中加载到 Dataset 对象中。

基于 K-Nearest Neighbors (k-NN) 的算法
推荐函数的算法选择取决于您要使用的技术。对于上面讨论的基于内存的方法,符合要求的算法是Centered k-NN,因为该算法非常接近上面解释的中心余弦相似度公式。它在 Surprise 中以KNNWithMeans.

要找到相似性,您只需通过将字典作为参数传递给推荐函数来配置函数。字典应具有所需的键,例如:

name包含要使用的相似性度量。选项是cosine、msd、pearson或pearson_baseline。默认值为msd.
user_based是一个boolean告诉该方法是基于用户还是基于项目的方法。默认值为True,这意味着将使用基于用户的方法。
min_support是用户之间考虑相似性所需的最小公共项目数。对于基于项目的方法,这对应于两个项目的最小共同用户数。
以下程序配置该KNNWithMeans功能:

# recommender.py

from surprise import KNNWithMeans

# To use item-based cosine similarity
sim_options = {
    "name": "cosine",
    "user_based": False,  # Compute  similarities between items
}
algo = KNNWithMeans(sim_options=sim_options)

上述程序中的推荐功能被配置为使用余弦相似度并使用基于项目的方法来查找相似项目。

要试用此推荐器,您需要创建一个Trainsetfrom data。Trainset是使用相同的数据构建的,但包含有关数据的更多信息,例如算法使用的用户数和项目数 ( n_users, )。n_items您可以使用整个数据或部分数据来创建它。您还可以将数据划分为折叠,其中一些数据将用于训练和一些用于测试。
注意:仅使用一对训练和测试数据通常是不够的。当您将原始数据集拆分为训练和测试数据时,您应该创建一对以上,以允许在测试数据的训练中出现多个观察结果。

算法应该使用多个折叠进行交叉验证。通过使用不同的配对,您会看到推荐人给出的不同结果。MovieLens 100k 提供五种不同的训练和测试数据拆分:u1.base、u1.test、u2.base、u2.test … u5.base、u5.test,用于 5 折交叉验证

下面是一个示例,用于了解用户E如何评价电影 2:

>>> from load_data import data
>>> from recommender import algo

>>> trainingSet = data.build_full_trainset()

>>> algo.fit(trainingSet)
Computing the cosine similarity matrix...
Done computing similarity matrix.
<surprise.prediction_algorithms.knns.KNNWithMeans object at 0x7f04fec56898>

>>> prediction = algo.predict('E', 2)
>>> prediction.est
4.15
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值