如何用Python来搭建一个简单的推荐系统
作者:先荐 发布时间:2022-07-20 22:17:33
在这篇文章中,我们会介绍如何用Python来搭建一个简单的推荐系统。
本文使用的数据集是MovieLens数据集,该数据集由明尼苏达大学的Grouplens研究小组整理。它包含1,10和2亿个评级。 Movielens还有一个网站,我们可以注册,撰写评论并获得电影推荐。接下来我们就开始实战演练。
在这篇文章中,我们会使用Movielens构建一个基于item的简易的推荐系统。在开始前,第一件事就是导入pandas和numPy。
import pandas as pd import numpy as np import warnings warnings.filterwarnings('ignore')
接下来,我们使用pandas read_csv()加载数据集。数据集由制表符分隔,所以我们将\ t传递给sep参数。然后,使用names参数传入列名。
df = pd.read_csv('u.data', sep='\t', names=['user_id','item_id','rating','titmestamp'])
接下来查看表头,检查一下正在处理的数据。
df.head()
如果我们能够看到电影的标题而不仅仅是ID,那再好不过了。之后加载电影标题并把它与此数据集合并。
movie_titles = pd.read_csv('Movie_Titles') movie_titles.head()
由于item_id列相同,我们可以在此列上合并这些数据集。
df = pd.merge(df, movie_titles, on='item_id') df.head()
数据集中的每一列分部代表:
user_id - 评 * 的用户的ID。
item_id- 电影的ID。
rating - 用户为电影提供的评级,介于1和5之间。
timestamp - 电影评级的时间。
title - 电影标题。
使用describe或info命令,就可以获得数据集的简要描述。如果想要真正了解正在使用的数据集的话,这一点非常重要。
df.describe()
可以看出,数据集共有100003条记录,电影的平均评分介于3.52-5之间。
现在我们再创建一个dataframe,其中包含每部电影的平均评分和评分数量。之后,这些评分将用来计算电影之间的相关性。相关性是一种统计指标,表示两个或多个变量一起波动的程度。相关系数越高,电影越为相似。
以下例子将使用Pearson相关系数 (Pearson correlation coefficient),该数字介于-1和1之间,1表示正线性相关,-1表示负相关, 0表示没有线性相关。也就是说,具有零相关性的电影完全不相似。
我们会使用pandas groupby 功能来创建dataframe。按照标题对数据集进行分组,并计算其平均值获得每部电影的平均评分。
ratings = pd.DataFrame(df.groupby('title')['rating'].mean()) ratings.head()
接下来我们创建number_of_ratings列,这样就能看到每部电影的评分数量。完成这步操作后,就可以看到电影的平均评分与电影获得的评分数量之间的关系。五星 * 很有可能只被一个人评价,而这种五星电影在统计上是不正确的。
因此,在构建推荐系统时,我们需要设置阈值。我们可以使用pandas groupby功能来创建新列,然后按标题栏分组,使用计数函数计算每部电影的评分。之后,便可以使用head()函数查看新的dataframe。
rating ['number_of_ratings'] = df.groupby('title')['rating'].count() ratings.head()
接下来我们使用pandas绘制功能来绘制直方图,显示评级的分布:
import matplotlib.pyplot as plt %matplotlib inline ratings['rating'].hist(bins=50)
可以看到,大多数电影的评分都在2.5-4之间。通过类似的方法还可以将number_of_ratings列可视化。
ratings['number_of_ratings'].hist(bins=60)
从上面的直方图中可以清楚地看出,多数电影的评分都很低,评分最高的电影是一些非常有名的电影。
现在让我们再来看一下电影评级与评分数量之间的关系。我们可以使用seaborn绘制散点图,然后使用jointplot()函数执行此操作。
import seaborn as sns sns.jointplot(x='rating', y='number_of_ratings', data=ratings)
从图中我们可以看出,电影平均评分与评分数量之间呈正相关关系,电影获得的评分数量越多,其平均评分越高。
创建基于item的简易推荐系统
接下来我们会快速创建一个基于item的简单的推荐系统。
首先,我们需要将数据集转换为矩阵,电影标题为列,user_id为索引,评级为值。完成这一步,我们将得到一个dataframe,其中列是电影标题,行是用户ID。每列代表所有用户对电影的所有评级。评级为NAN表示用户未对这部电影评分。
我们可以用该矩阵来计算单个电影的评级与矩阵中其余电影的相关性,该矩阵可以通过pandas pivot_table实现。
movie_matrix = df.pivot_table(index ='user_id',columns ='title',values ='rating') movie_matrix.head()
接下来让我们找到评分数量最多的电影,并选择其中的两部电影。然后使用pandas sort_values并将升序设置为false,以便显示评分最多的电影。然后使用head()函数来查看评分数目最多的前十部电影。
ratings.sort_values('number_of_ratings', ascending=False).head(10)
假设一个用户曾看过Air Force One(1997)和Contact(1997),我们想根据这两条观看记录向该用户推荐其他类似的电影,那么这一点可以通过计算这两部电影的评级与数据集中其他电影的评级之间的相关性来实现。第一步是创建一个dataframe,其中包含来自movie_matrix的这些电影的评级。
AFO_user_rating = movie_matrix['Air Force One (1997)'] contact_user_rating = movie_matrix['Contact (1997)']
Dataframe可以显示user_id和这两部电影的评分。
AFO_user_rating.head() contact_user_rating.head()
使用pandas corwith功能计算两个dataframe之间的相关性。有了这一步,就能够获得每部电影的评级与Air Force One电影的评级之间的相关性。
similar_to_air_force_one = movie_matrix.corrwith(AFO_user_rating)
可以看到,Air Force One电影和Till There Was You(1997)之间的相关性是0.867。这表明这两部电影之间有很强的相似性。
similar_to_air_force_one.head()
还可以计算Contact(1997)的评级与其他电影评级之间的相关性,步骤同上:
similar_to_contact = movie_matrix.corrwith(contact_user_rating)
可以从中发现,Contact(1997)和Till There Was You(1997)之间存在非常强的相关性(0.904)。
similar_to_contact.head()
前边已经提到,并非所有用户都对所有电影进行了评分,因此,该矩阵中有很多缺失值。为了让结果看起来更有吸引力,删除这些空值并将相关结果转换为dataframe。
corr_contact = pd.DataFrame(similar_to_contact, columns=['Correlation']) corr_contact.dropna(inplace=True) corr_contact.head()corr_AFO = pd.DataFrame(similar_to_air_force_one, columns=['correlation']) corr_AFO.dropna(inplace=True) corr_AFO.head()
上面这两个dataframe分别展示了与Contact(1997)和Air Force One(1997)电影最相似的电影。然而,问题出现了,有些电影的实际质量非常低,但可能因为一两位用户给他们5星评级而被推荐。
这个问题可以通过设置评级数量的阈值来解决。从早期的直方图中看到,评级数量从100开始急剧下降。因此可以将此设置为阈值,但是也可以考虑其他合适的值。为此,我们需要将两个dataframe与rating datframe中的number_of_ratings列一起加入。
corr_AFO = corr_AFO.join(ratings['number_of_ratings']) corr_contact = corr_contact.join(ratings['number_of_ratings'])corr_AFO.head()corr_contact.head()
现在,我们就能得到与Air Force One(1997)最相似的电影,并把这些电影限制在至少有100条评论的电影中,然后可以按相关列对它们进行排序并查看前10个。
corr_AFO [corr_AFO ['number_of_ratings']> 100] .sort_values(by ='correlation',ascending = False).head(10)
我们注意到Air Force One(1997)与自身相关性最高,这并不奇怪。下一部与Air Force One(1997)最相似的电影是Hunt for Red October,相关系数为0.554。
显然,通过更改评论数量的阈值,我们可以按之前的方式得到不同的结果。限制评级数量可以让我们获得更好的结果。
现在重复上边的步骤,可以看到与Contact(1997)电影最相关的电影:
corr_contact [corr_contact ['number_of_ratings']> 100] .sort_values(by ='Correlation',ascending = False).head(10)
与Contact(1997)最相似的电影是Philadelphia(1993),相关系数为0.446,有137个评级。所以,如果有人喜欢Contact(1997),我们可以向他们推荐上述电影。
以上是构建推荐系统的一种非常简单的方法,但并不符合行业标准。后续的话我们可以通过构建基于存储器的协同过滤系统来改进该系统。在这种情况下,将数据划分为训练集和测试集,使用诸如余弦相似性来计算电影之间的相似性;或者构建基于模型的协作过滤系统,然后使用Root Mean Squared Error(RMSE)等技术评估模型。
Github: https://github.com/mwitiderrick/simple-recommender-
英文:How to build a Simple Recommender System in Python
来源:https://blog.51cto.com/13945147/2427200
猜你喜欢
- pycharm报错提示:无法加载文件\venv\Scripts\activate.ps1,因为在此系统上禁止运行脚本在pycharm终端出现
- 论坛里面有不少人在使用Javascript编写Asp,经常有人在论坛提问,为什么Asp对象在对比指定值时返回结果不对?现在在这里给大家写点关
- 我生平不爱学习,所以说不出什么洋洋洒洒的大道理,貌似也写不出妙语连珠的学术文章,有感于现在宅到极致的生活状态,故一篇图文并茂的文章诞生了(大
- import os import sys import string #以指定模式打开指定文件,获取文件句柄 def getFileIns(
- 样式表是一种为超文本标签语言提供增强补充服务的技术,可对每一个html的标签做精雕细刻的修饰。只用html制作的网页,对页面内各部分的修饰能
- 了然于胸 - collectModules时序图经过loadConfig和applyConfigDefaults,我们已经将用户自定义信息和
- 导入依赖"element-ui": "2.13.0","file-saver":
- 做网站数据库,是选SQL Server还是Access好,可能您会说:选MySQL好,不过现在只是讨论IIS+ASP这种架构下的选择,不讨论
- 本文实例讲述了JS仿Windows开机启动Loading进度条的方法。分享给大家供大家参考。具体实现方法如下:<html><
- 导语一直以来,中国象棋都是中华民族的一种象征,当然也是人们最为喜感的一种娱乐方式。在若干年前,人们都习惯于约上自己的棋友,来一种激战。可是,
- 1.open使用open打开文件后一定要记得调用文件对象的close()方法。比如可以用try/finally语句来确保最后能关闭文件。fi
- 1. 可选链从 v3.7 可用这是当你尝试访问嵌套数据时的一个痛点,嵌套数据越多,代码就会变得越繁琐。在下面的例子中,要访问address,
- 1. 获取abi文件合约的接口在remix工具中编译合约后,会有一个abi,复制然后新建一个xx.abi文件,把赋值的粘贴到里面注意:代码变
- 代码伺候:先看如下代码:例1: message = Message.objects.filter(pk=message_id2)messag
- 光的干涉干涉即两束光在叠加过程中出现的强度周期性变化情况,其最简单的案例即为杨氏双缝干涉。如图所示,光从 S S S点发出,通过两个狭缝 S
- 当用人问你MySQL 查询条件中 in 会不会用到索引,你该怎么回答?答案:可能会用到索引 动手来测试下1.创建一张表,给字段port建立索
- folder.htm<html><head><title>闪亮日子之在线创建文件夹</title&
- CSS处理斜角导航条的一个例子,这个是写着测试用的。暂没有实际的应用。斜角处理比较麻烦,主要有两个地方。1、图片处理。2、负数的理解。这两个
- 代码如下:<% '功能:取得文件扩展名 Function getFileExt(sFileNam
- 在学习tensorflow的过程中,有一个问题,tensorflow在训练的过程中读取的是二进制图像数据库文件,而不是图像文件,因此在进行训