使用Python实现一个简单的推荐系统

今天 4阅读

在当今的互联网环境中,推荐系统已经成为许多应用的核心功能之一。无论是电商平台的商品推荐、视频网站的内容推荐,还是社交媒体的信息流排序,推荐系统都在提升用户体验和增加平台收益方面发挥了重要作用。

本文将介绍如何使用 Python 实现一个简单的基于协同过滤(Collaborative Filtering)的推荐系统。我们将使用 scikit-surprise 库来构建模型,并通过电影评分数据集进行训练与预测。


推荐系统简介

推荐系统大致可以分为以下几类:

基于内容的推荐(Content-based Recommendation)协同过滤推荐(Collaborative Filtering)混合推荐(Hybrid Recommendation)

我们本次要实现的是协同过滤推荐系统,它又分为两种类型:

用户协同过滤(User-based CF):根据相似用户的喜好推荐物品。物品协同过滤(Item-based CF):根据相似物品的喜好推荐物品。

我们将使用经典的 MovieLens 数据集 来演示如何训练一个推荐模型。


环境准备

首先,我们需要安装必要的库:

pip install scikit-surprise pandas matplotlib

然后导入相关模块:

import pandas as pdfrom surprise import Dataset, Reader, KNNBasicfrom surprise.model_selection import train_test_splitfrom surprise import accuracyimport os

加载数据集

我们可以从 MovieLens 官网下载 small 版本的数据集(约 1MB),解压后包含以下几个文件:

ratings.csv:用户对电影的评分movies.csv:电影信息

接下来,我们读取并处理这些数据:

# 加载评分数据ratings_path = 'ratings.csv'ratings_df = pd.read_csv(ratings_path)# 只保留需要的列ratings_df = ratings_df[['userId', 'movieId', 'rating']]# 创建 Surprise 的 Reader 对象reader = Reader(rating_scale=(0.5, 5.0))# 将 DataFrame 转换为 Surprise 的 Datasetdata = Dataset.load_builtin('ml-100k')trainset, testset = train_test_split(data, test_size=0.25)

注意:如果你手动下载了 ratings.csv,也可以使用 Dataset.load_builtin() 或者自定义方式加载。


构建推荐模型

我们将使用 KNN(最近邻算法)来构建一个基于用户的协同过滤推荐模型。

# 配置参数sim_options = {    "name": "cosine",    "user_based": True  # 基于用户的协同过滤}# 构建模型model = KNNBasic(sim_options=sim_options)# 训练模型model.fit(trainset)# 测试模型predictions = model.test(testset)# 评估 RMSEaccuracy.rmse(predictions)  # 输出 RMSE 值

输出示例:

RMSE: 0.789

这表示我们的模型在测试集上的平均误差约为 0.79 分(满分为 5 分),已经具有一定的预测能力。


进行推荐

接下来,我们可以为某个用户推荐他/她可能喜欢的电影。

步骤:

获取所有未被该用户评分过的电影。使用模型预测这些电影的评分。按照预测评分排序,返回前 N 部电影。
def get_top_n_recommendations(model, user_id, n=10):    # 获取训练集中所有的电影 ID    all_movies = ratings_df['movieId'].unique()    # 获取该用户已评分的电影    rated_movies = ratings_df[ratings_df['userId'] == user_id]['movieId']    # 找出未评分的电影    unrated_movies = [movie for movie in all_movies if movie not in rated_movies.values]    # 预测评分    predictions = [model.predict(user_id, movie_id) for movie_id in unrated_movies]    # 排序并返回 top-n    predictions.sort(key=lambda x: x.est, reverse=True)    top_n = predictions[:n]    return [(pred.iid, pred.est) for pred in top_n]

示例调用:

user_id = 196top_movies = get_top_n_recommendations(model, user_id)print(f"Top 10 recommendations for user {user_id}:")for movie_id, rating in top_movies:    title = movies_df[movies_df['movieId'] == int(movie_id)]['title'].values[0]    print(f"{title} - Predicted Rating: {rating:.2f}")

输出示例:

Top 10 recommendations for user 196:Toy Story (1995) - Predicted Rating: 4.32The Shawshank Redemption (1994) - Predicted Rating: 4.28...

可视化分析

我们可以绘制用户评分分布图,观察数据特点:

import matplotlib.pyplot as pltplt.hist(ratings_df['rating'], bins=10, edgecolor='black')plt.title('Distribution of Ratings')plt.xlabel('Rating')plt.ylabel('Count')plt.show()

总结与改进方向

本篇文章介绍了如何使用 Python 和 surprise 库构建一个基于协同过滤的推荐系统。虽然我们实现了基本的推荐功能,但还有许多优化空间:

改进方向:

使用更复杂的模型:如 SVD、SVD++、深度学习模型(NeuMF)冷启动问题:引入基于内容的推荐作为补充实时性增强:增量更新模型而不是全量训练多策略融合:结合协同过滤与基于内容的推荐部署上线:使用 Flask/Django 构建 API 接口提供服务

完整代码汇总

以下是本文中使用的完整代码整合版本(需配合 MovieLens 数据集运行):

import pandas as pdfrom surprise import Dataset, Reader, KNNBasicfrom surprise.model_selection import train_test_splitfrom surprise import accuracyfrom collections import defaultdict# 加载数据ratings_path = 'ratings.csv'movies_path = 'movies.csv'ratings_df = pd.read_csv(ratings_path)movies_df = pd.read_csv(movies_path)ratings_df = ratings_df[['userId', 'movieId', 'rating']]reader = Reader(rating_scale=(0.5, 5.0))data = Dataset.load_builtin('ml-100k')# 划分训练集和测试集trainset, testset = train_test_split(data, test_size=0.25)# 构建 KNN 模型sim_options = {    "name": "cosine",    "user_based": True}model = KNNBasic(sim_options=sim_options)model.fit(trainset)# 测试模型predictions = model.test(testset)accuracy.rmse(predictions)# 推荐函数def get_top_n_recommendations(model, user_id, n=10):    all_movies = ratings_df['movieId'].unique()    rated_movies = ratings_df[ratings_df['userId'] == user_id]['movieId']    unrated_movies = [movie for movie in all_movies if movie not in rated_movies.values]    predictions = [model.predict(user_id, movie_id) for movie_id in unrated_movies]    predictions.sort(key=lambda x: x.est, reverse=True)    top_n = predictions[:n]    return [(pred.iid, pred.est) for pred in top_n]# 示例推荐user_id = 196top_movies = get_top_n_recommendations(model, user_id)print(f"Top 10 recommendations for user {user_id}:")for movie_id, rating in top_movies:    title = movies_df[movies_df['movieId'] == int(movie_id)]['title'].values[0]    print(f"{title} - Predicted Rating: {rating:.2f}")

参考资料

Surprise DocumentationMovieLens Dataset《推荐系统实践》——项亮

如需进一步扩展,可以考虑使用 TensorFlow/Keras 实现神经网络推荐系统,或者使用 Spark MLlib 处理大规模数据。

如果你对这个项目感兴趣,欢迎在 GitHub 上开源分享,也欢迎继续深入研究更多推荐算法!


如需获取完整项目结构或源码,请留言或联系作者邮箱。

免责声明:本文来自网站作者,不代表CIUIC的观点和立场,本站所发布的一切资源仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。客服邮箱:ciuic@ciuic.com

目录[+]

您是本站第32604名访客 今日有26篇新文章

微信号复制成功

打开微信,点击右上角"+"号,添加朋友,粘贴微信号,搜索即可!