如何用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: mwitiderrick/simple-recommender-

文章来源:How to build a Simple Recommender System in Python

转载于:https://my.oschina.net/u/4004373/blog/3084329

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,为了简单起见,我假设这个宿舍管理系统只需要实现基本的学生信息管理和宿舍房间管理。我们可以用Python的Flask框架来搭建这个系统。 第一步是安装必要的依赖项,包括Flask、Flask-RESTful等库。可以在命令行中输入以下命令进行安装: ``` pip install flask flask-restful ``` 第二步是创建一个Flask应用,我们可以在一个名为app.py的文件中编写以下代码: ```python from flask import Flask, request from flask_restful import Resource, Api app = Flask(__name__) api = Api(app) student_list = [] room_dict = {} class Student(Resource): def get(self, student_id): for student in student_list: if student["id"] == student_id: return student return {"error": "Student not found."}, 404 def post(self): student = request.get_json(force=True) student_list.append(student) return {"message": "Student added."} def put(self, student_id): for student in student_list: if student["id"] == student_id: updated_student = request.get_json(force=True) student.update(updated_student) return {"message": "Student updated."} return {"error": "Student not found."}, 404 def delete(self, student_id): for student in student_list: if student["id"] == student_id: student_list.remove(student) return {"message": "Student deleted."} return {"error": "Student not found."}, 404 class Room(Resource): def get(self, room_number): if room_number in room_dict: return room_dict[room_number] return {"error": "Room not found."}, 404 def post(self): room = request.get_json(force=True) room_number = room["room_number"] room_dict[room_number] = room return {"message": "Room added."} def put(self, room_number): if room_number in room_dict: updated_room = request.get_json(force=True) room_dict[room_number].update(updated_room) return {"message": "Room updated."} return {"error": "Room not found."}, 404 def delete(self, room_number): if room_number in room_dict: del room_dict[room_number] return {"message": "Room deleted."} return {"error": "Room not found."}, 404 api.add_resource(Student, "/students", "/students/<string:student_id>") api.add_resource(Room, "/rooms", "/rooms/<int:room_number>") if __name__ == "__main__": app.run(debug=True) ``` 这个代码创建了一个名为app的Flask应用,并创建了两个资源类:Student和Room。Student类包含了获取、添加、修改和删除学生信息的方法,而Room类包含了获取、添加、修改和删除宿舍房间信息的方法。我们在这里使用了一个全局变量student_list来保存学生信息,以及一个字典room_dict来保存宿舍房间信息。 最后,我们将这两个资源类添加到Flask的API中,以及指定了API的路由。如果我们运行这个代码,它将在本地启动一个Web服务器,可以通过访问http://localhost:5000/students和http://localhost:5000/rooms来访问这两个资源。 这个代码只是一个框架,你可以根据自己的实际需求添加更多的功能和逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值