使用Python实现一个简单的推荐系统
推荐系统是现代互联网应用中不可或缺的一部分,广泛应用于电商平台、社交媒体、视频网站等领域。本文将介绍如何使用Python构建一个简单的基于协同过滤的推荐系统,并提供完整的代码示例。
我们将使用电影评分数据集来构建推荐系统,通过分析用户对电影的评分来为用户推荐他们可能感兴趣的电影。
1. 推荐系统简介
推荐系统主要分为以下几类:
基于内容的推荐:根据物品的特征或用户的兴趣进行推荐。协同过滤推荐:基于用户的协同过滤(User-based):找出与目标用户兴趣相似的其他用户,推荐这些用户喜欢但目标用户未接触过的物品。基于物品的协同过滤(Item-based):找出与目标物品相似的其他物品,推荐给喜欢该物品的用户。混合推荐系统:结合多种推荐方法。本文将实现的是基于用户的协同过滤推荐系统。
2. 数据准备
我们使用经典的 MovieLens 小型数据集,包含以下文件:
movies.csv
:包含电影ID和标题。ratings.csv
:包含用户ID、电影ID、评分和时间戳。你可以从 MovieLens 官网 下载最新版本的数据集,或者使用小型数据集如 ml-latest-small.zip
。
安装依赖库
pip install pandas numpy scikit-learn
3. 实现步骤
步骤一:导入必要的库并加载数据
import pandas as pdimport numpy as npfrom sklearn.metrics.pairwise import cosine_similarityfrom sklearn.preprocessing import MinMaxScaler# 加载数据movies = pd.read_csv('movies.csv')ratings = pd.read_csv('ratings.csv')# 合并数据data = pd.merge(ratings, movies, on='movieId')print(data.head())
输出结果:
userId | movieId | rating | timestamp | title |
---|---|---|---|---|
1 | 31 | 2.5 | 1260759144 | Dangerous Minds (1995) |
1 | 1029 | 3.0 | 1260759179 | Dances with Wolves (1990) |
... | ... | ... | ... | ... |
步骤二:构建用户-物品评分矩阵
# 构建用户-电影评分矩阵user_movie_matrix = data.pivot_table(index='userId', columns='title', values='rating')print(user_movie_matrix.head())
输出示例:
title | $1,000,000 Duck (1971) | 'Til There Was You (1997) | ... |
---|---|---|---|
userId | |||
1 | NaN | NaN | ... |
2 | 3.0 | NaN | ... |
... | ... | ... | ... |
步骤三:计算用户之间的相似度
我们使用余弦相似度(cosine similarity)来衡量用户之间的相似性。
# 填充NaN值为0user_movie_matrix_filled = user_movie_matrix.fillna(0)# 计算用户之间的相似度user_similarity = cosine_similarity(user_movie_matrix_filled)print("用户相似度矩阵:")print(user_similarity)
输出结果是一个 N×N 的矩阵,表示每个用户与其他用户的相似度。
步骤四:预测用户对未观看电影的评分
我们可以使用加权平均法来预测某个用户对某部电影的评分:
$$\text{predicted_rating} = \frac{\sum{u' \in U} \text{similarity}(u, u') \times \text{rating}{u'}(i)}{\sum_{u' \in U} |\text{similarity}(u, u')|}$$
其中:
$ u $ 是目标用户;$ i $ 是目标电影;$ u' $ 是其他用户;分母用于归一化。def predict_ratings(similarity_matrix, ratings_matrix): # 归一化相似度(避免相似度高的用户主导) mean_user_rating = ratings_matrix.mean(axis=1) ratings_diff = (ratings_matrix.subtract(mean_user_rating, axis=0)).fillna(0) pred_ratings = similarity_matrix.dot(ratings_diff) / np.array([np.abs(similarity_matrix).sum(axis=1)]) pred_ratings += mean_user_rating.values.reshape(-1, 1) return pred_ratingspredicted_ratings = predict_ratings(user_similarity, user_movie_matrix)
步骤五:为用户推荐电影
现在我们为指定用户推荐评分最高的未看过的电影。
def recommend_movies(user_id, predicted_ratings_matrix, original_ratings_matrix, movie_titles, n_recommendations=10): user_index = user_id - 1 # 索引从0开始 scores = predicted_ratings_matrix[user_index] # 找出用户未评分的电影 watched_mask = np.isnan(original_ratings_matrix.iloc[user_index]) scores_unwatched = pd.Series(scores[watched_mask], index=original_ratings_matrix.columns[watched_mask]) top_movies = scores_unwatched.sort_values(ascending=False).head(n_recommendations) return pd.DataFrame({'title': top_movies.index, 'predicted_score': top_movies.values})# 示例:为用户1推荐10部电影recommendations = recommend_movies( user_id=1, predicted_ratings_matrix=predicted_ratings, original_ratings_matrix=user_movie_matrix, movie_titles=movies['title'])print("推荐电影列表:")print(recommendations)
输出示例:
title | predicted_score |
---|---|
The Shawshank Redemption (1994) | 4.8 |
The Godfather (1972) | 4.7 |
Pulp Fiction (1994) | 4.6 |
... | ... |
4. 总结与改进方向
以上我们实现了一个基于用户的协同过滤推荐系统,虽然简单,但展示了推荐系统的基本原理和流程:
构建用户-物品评分矩阵;计算用户相似度;预测评分;根据预测评分推荐物品。改进方向:
引入稀疏矩阵优化:使用scipy.sparse
来处理大规模稀疏矩阵,提高性能。使用K近邻算法(KNN):只考虑最相似的前K个邻居,减少计算量。加入冷启动策略:对于新用户或新物品,可采用基于内容的推荐作为补充。使用深度学习模型:如AutoEncoder、NeuMF等模型可以提升推荐质量。5. 完整代码汇总
import pandas as pdimport numpy as npfrom sklearn.metrics.pairwise import cosine_similarity# 加载数据movies = pd.read_csv('movies.csv')ratings = pd.read_csv('ratings.csv')data = pd.merge(ratings, movies, on='movieId')# 用户-电影评分矩阵user_movie_matrix = data.pivot_table(index='userId', columns='title', values='rating')# 填充缺失值user_movie_matrix_filled = user_movie_matrix.fillna(0)# 计算用户相似度user_similarity = cosine_similarity(user_movie_matrix_filled)# 预测评分函数def predict_ratings(similarity_matrix, ratings_matrix): mean_user_rating = ratings_matrix.mean(axis=1) ratings_diff = (ratings_matrix.subtract(mean_user_rating, axis=0)).fillna(0) pred_ratings = similarity_matrix.dot(ratings_diff) / np.array([np.abs(similarity_matrix).sum(axis=1)]) pred_ratings += mean_user_rating.values.reshape(-1, 1) return pred_ratingspredicted_ratings = predict_ratings(user_similarity, user_movie_matrix)# 推荐电影函数def recommend_movies(user_id, predicted_ratings_matrix, original_ratings_matrix, movie_titles, n_recommendations=10): user_index = user_id - 1 scores = predicted_ratings_matrix[user_index] watched_mask = np.isnan(original_ratings_matrix.iloc[user_index]) scores_unwatched = pd.Series(scores[watched_mask], index=original_ratings_matrix.columns[watched_mask]) top_movies = scores_unwatched.sort_values(ascending=False).head(n_recommendations) return pd.DataFrame({'title': top_movies.index, 'predicted_score': top_movies.values})# 推荐示例recommendations = recommend_movies( user_id=1, predicted_ratings_matrix=predicted_ratings, original_ratings_matrix=user_movie_matrix, movie_titles=movies['title'])print("推荐电影列表:")print(recommendations)
本篇文章介绍了如何,并给出了完整的技术实现过程和代码。希望读者能够理解协同过滤的核心思想,并在此基础上进一步探索更复杂的推荐算法和工程实践。