美文网首页
python 简易推荐系统实现

python 简易推荐系统实现

作者: 杨昊_6c65 | 来源:发表于2019-06-06 09:30 被阅读0次

本文是参考了阿里云的推荐系统搭建文章的一个学习笔记,因为原文章的数据集找不到了,所以用的是不同的数据集(可能是有所更新,在其公布的原数据网站未发现其所使用的数据集),将利用python构建一个简单的推荐系统,在此之前读者需要对pandas和numpy等数据分析包有所了解。

数据集

我们将使用到MovieLes数据集,该数据集是关于电影评分的,由明尼苏达大学的Grouplens研究小组整理,分为1M,10M,20M三个规格。Movielens还有一个网站,可以注册,撰写评论并获取电影推荐。若不想用此数据集,你也可以从Dataquest的数据资源中找到更多用于各种数据科学任务的数据集。
本文运用的是20M的数据集

推荐系统构建

我们将使用movielens构建一个基于项目相似度的推荐系统,首先导入pandas和numpy。

import pandas as pd 
import numpy as np
import warnings
warnings.filterwarnings('ignore')

后面两句仅是忽略python warning即警告的模块语句
接下来加载数据集

df = pd.read_csv('ratings.csv')
df.head()
电影评分数据

相比只知道电影的ID,能看到它们的标题更为方便。接下来,讲下载的压缩包中的并将它们整合到数据集中。

title = pd.read_csv('movies.csv')
title.head()
电影标题

用movieid把两个表串在一起,导入电影名字
删掉的特征genres是电影类型,此处删掉,但也可以不删,也是可以后面应用的点

df = pd.merge(df,title, on='movieId')
df = df.drop(['genres'],axis = 1)
df.head()

属性释义:
User_id:用户ID
Item_id:电影ID
Rating:用户给电影的评分,介于1到5分之间
Timestamp:对电影进行评分的时间点
Title:电影标题

我们可以先看下用户对所有电影的评价评分


用户对电影的平均评分

整体数据的信息,

df.info()
#df['rating'] = df['rating'].astype(np.int64) 转float为int
数据集信息

通过上一步,可以知道电影的平均分约为3.53分,最高为5分。

接下来构建一个包含每部电影的平均评分和被评分次数的dataframe,用来计算电影间的相关性。相关性是一种统计度量,用来表示两个或多个变量在一起波动的程度,电影之间的相关系数越高,越相似。

在本例中,我们将使用皮尔逊相关系数,它的变化范围为-1到1。当相关系数为1时,为完全正相关;当相关系数为-1时,为完全负相关;相关系数越接近于0,相关度越弱。利用pandas 中的groupby功能创建dataframe,按标题列对数据集进行分组,并计算每部电影的平均分。

ratings = pd.DataFrame(df.groupby('title')['rating'].mean())
ratings.head()
#电影与评分
电影与对应平均评分

接下来计算每部电影被评分的次数,观察它与电影平均评分之间的关系。一部5分的电影很可能只有一个用户评分。从统计学上来说,把它视为5分电影是不合理的。
因此,在构建推荐系统时,我们需要为评分次数设置一个阈值。使用pandas中的 groupby功能创建number_of_ratings列,按title列进行分组,然后使用count函数计算每部电影的被评分次数。之后,使用head()函数查看新的dataframe。

ratings['number_of_ratings'] = df.groupby('title')['rating'].count()
ratings.head()
#点击率
电影与对应平均评分与对应点击数

接下来对点击数进行一个可视化

import matplotlib.pyplot as plt
%matplotlib inline
ratings['rating'].hist(bins=50)
点击数在不同分数的分布

从直方图中可以清楚地看出大多数电影都只有较少的评分,猜测那些评分次数多的电影都拥有较高的知名度。

接下来探索电影评分和被评分次数之间的关系。使用seaborn绘制散点图,通过jointplot()函数实现。

import seaborn as sns
sns.jointplot(x='rating', y='number_of_ratings', data=ratings)
电影评分和被评分次数之间的关系散点图

围绕此图,可以用中间切线的方法看,横着切看,就是以点击频次看,会发现左上角是空的,这意味着被评分次数高的电影分数也高,即他们呈正相关关系。在为每部电影的评分设置阈值时,这一点尤其重要。

接下来构建基于项目的推荐系统。我们需要将数据集转换为一个矩阵,即一个评分矩阵,以电影标题为列,以user_id为索引,以评分为值。之后会得到一个dataframe,其中列是movie标题,行是user_id。每列代表所有用户对所有电影的评分。若评分为NaN(Not a Number),则表示用户没有对某一部电影进行评分。矩阵被用来计算电影之间的相关性。使用pandas中的 pivot_table创建电影矩阵。

movie_matrix = df.pivot_table(index='user_id', columns='title', values='rating')
movie_matrix.head()
每个用户对电影的评分

因为用户不是对每个电影都会评价,所以会呈现空值

接下来,使用pandas中的 sort_values工具,设置升序为false,以便从评分最高的电影中进行选择,然后使用head()函数查看分数前5的电影。

ratings.sort_values('number_of_ratings',ascending=False).head()
分数前5的电影

Forrest Gump :阿甘正传 为方便 简称FG
Pulp Fiction : 低俗小说 为方便 简称PF

假设某用户看过《阿甘正传》和《低俗小说》,我们想根据观看历史向该用户推荐电影。通过计算这两个电影和数据集中其他电影的之间的相关性,寻找与之最为相似的电影,为用户进行推荐。首先,用movie_matrix中的电影评分创建一个dataframe。

FG_user_rating = movie_matrix['Forrest Gump (1994)']#阿甘正传
FG_user_rating.head()
PF_user_rating = movie_matrix['Pulp Fiction (1994)']#低俗小说
PF_user_rating.head()
阿甘正传评分(未处理空值) 低俗小说评分(未处理空值)

接下来处理阿甘正传,计算每部电影与其的相关性,使用pandas中的corwith功能就能计算两个dataframe对象的行或列的两两相关关系

similar_FG =movie_matrix.corrwith(FG_user_rating)
similar_FG.head()
未处理空值的阿甘正传与其他电影相关性
similar_PF =movie_matrix.corrwith(PF_user_rating)
similar_PF.head()
未处理空值的低俗小说其他电影相关性

因为未处理空值,所以显示前面是类似的,因为没筛选掉,但可以看见阿甘正传和创造的种子这部电影是-0.14表面相关度不大

The Seeds of Creation

之前由于只有部分用户对部分电影进行了评分,导致矩阵中有许多缺失的值。为了使结果看起来更有吸引力,我们将删除null值并将correlation results转化为dataframe。

corr_FG = pd.DataFrame(similar_FG, columns=['Correlation'])
corr_FG.dropna(inplace=True)
corr_FG.head()
阿甘正传的电影相关性
corr_PF = pd.DataFrame(similar_PF, columns=['correlation'])
corr_PF.dropna(inplace=True)
corr_PF.head()
低俗小说的电影相关性

过上述步骤,计算出了与《阿甘正传》和《低俗小说》最为相似的电影。然而,有些电影被评价的次数很低,最终可能仅仅因为一两个人给了5分而被推荐。设置阈值可解决这个问题。从之前的直方图中我们看到评分次数从100急剧下降,于是我们将阈值设为100,不过你可以根据自己的需求进行调整。接下来,利用number_of_ratings列将两个dataframe连接起来。

corr_FG = corr_FG.join(ratings['number_of_ratings'])
corr_FG .head()
corr_PF = corr_contact.join(ratings['number_of_ratings'])
corr_PF.head()
image.png
image.png

对上诉两表引入了number_of_ratings,然后可以对其设置一个阀值进行筛选

corr_FG[corr_FG['number_of_ratings'] > 100].sort_values(by='Correlation', ascending=False).head()

这里对点击数进行的阀值是大于100,实际操作还是要看情况设置,但比如之前的salem lot 可以看出筛选掉,它是一个恐怖电影和上诉没有什么关系,可以看出它是原电影评分的一个异常点,可能有少数的用户对其进行了高评分而造成一个误判,但在设置完点击次数后 可以筛选出它了


salem lot 阿甘正传相关电影

排名第二的是银河护卫队,因为都是喜剧 所以接近是理论上都可以接受的,并且相关性也仅是0.49

corr_PF[corr_PF['number_of_ratings'] > 100].sort_values(by='Correlation', ascending=False).head(10)
低俗小说相关性的电影
也比之前的合理多了,排名第二的是落水狗,同为昆汀·塔伦蒂诺拍摄的电影,可以看出设置阀值是很关键的一步,而翻回之前,还是能看到那个salem lot 的干扰电影 Reservoir Dogs

改进

本文所构建的推荐系统可以通过基于记忆的协同过滤方法进行改进。我们可以将数据集划分为训练集和测试集,使用诸如余弦相似度之类的方法来计算电影之间的相似度。还可以通过建立基于模型的协同过滤系统,更好地处理可伸缩性和稀疏性问题。同时也可以利用如均方根误差(RMSE)之类的方法对模型进行评估。除此之外,当所处理的数据量十分庞大时,还可以结合深度学习构建推荐系统。自动编码器和受限的Boltzmann机器也常用于构建高级推荐系统。

给新上路的朋友一个关于推荐系统简单原理和算法的学习视频:https://www.bilibili.com/video/av38554878/?p=4

相关文章

网友评论

      本文标题:python 简易推荐系统实现

      本文链接:https://www.haomeiwen.com/subject/qzwexctx.html