使用Python实现一个简单的推荐系统
在当今的互联网环境中,推荐系统已经成为许多应用的核心功能之一。无论是电商平台的商品推荐、视频网站的内容推荐,还是社交媒体的信息流排序,推荐系统都在提升用户体验和增加平台收益方面发挥了重要作用。
本文将介绍如何使用 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 上开源分享,也欢迎继续深入研究更多推荐算法!
如需获取完整项目结构或源码,请留言或联系作者邮箱。