Python构建基于Item的简单推荐系统实战

晚来风
晚来风
发布时间:2026-10-13 | 4人浏览过
原创

本文详解如何使用Python和Pandas库构建基于Item的简易推荐系统。通过加载MovieLens数据集,利用pivot_table生成用户-电影评分矩阵,并计算电影间的Pearson相关系数。文章涵盖数据清洗、阈值设定以过滤低评分数量电影,以及通过计算相似度进行电影推荐的具体代码实现与结果分析。

Python构建基于Item的简单推荐系统实战

本文将演示如何利用Python搭建一个基础的推荐系统。

数据集介绍与准备

实验采用明尼苏达大学Grouplens研究小组整理的MovieLens数据集,该数据集包含1,10和2亿个评级。MovieLens官网允许用户注册、撰写评论并获取电影推荐,我们将以此为基础进行实战操作。

数据加载与预处理

本教程旨在构建一个基于Item(物品)的简易推荐系统。首先,需要导入pandas和numPy这两个核心数据处理库。


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

随后,利用pandas的read_csv()函数加载数据集。由于数据以制表符分隔,需在sep参数中传入\ t。同时,通过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表示无线性相关,即两部完全不相似的电影相关系数为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的简易推荐系统

接下来,我们将快速创建一个基于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),我们希望根据这两部电影的观看记录向该用户推荐其他相似电影。这可以通过计算这两部电影的评级与数据集中其他电影评级之间的相关性来实现。第一步是创建一个包含movie_matrix中这两部电影评级的dataframe。


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之后急剧下降。因此,可将100设为阈值,当然也可根据需求调整其他合适值。为此,需将两个dataframe与rating dataframe中的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)与自身的相关性最高,这符合预期。紧随其后的是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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表