基于协同过滤算法的电影推荐系统(Python 实现)

一、项目背景与目标

1.1 背景

协同过滤(Collaborative Filtering, CF)是推荐系统中最常用的技术之一,分为两种主要类型:

  • 基于用户的协同过滤(UserCF) :通过分析用户之间的相似性,找到与目标用户兴趣相近的其他用户,并推荐这些用户喜欢的电影。
  • 基于物品的协同过滤(ItemCF) :通过分析电影之间的相似性,为目标用户推荐与其已评分电影相似的其他电影。

1.2 目标

本项目的目标是:

  1. 计算用户之间的杰尔德相似性和物品之间的杰尔德相似性。
  2. 为每个用户找到最相似的两个用户。
  3. 基于用户协同过滤和物品协同过滤为指定用户推荐 3 到 5 部电影。

二、数据准备

2.1 数据集来源

我们使用 MovieLens 提供的小型数据集 ml-latest-small,包含以下四个文件:

获取数据点这里

  • ratings.csv :用户对电影的评分信息(用户ID、电影ID、评分、时间戳)。
  • movies.csv :电影的基本信息(电影ID、电影标题、电影类型)。
  • links.csv :电影在外部数据库中的链接信息(电影ID、IMDb ID、TMDB ID)。
  • tags.csv :用户对电影的标签信息(用户ID、电影ID、标签、时间戳)。

2.2 数据加载与预览

加载数据并显示前五行数据,快速了解数据结构:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics.pairwise import pairwise_distances
from collections import defaultdict
import warnings

# 忽略 DataConversionWarning 警告
warnings.filterwarnings("ignore", category=UserWarning)
warnings.filterwarnings("ignore", category=RuntimeWarning)

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体
plt.rcParams['axes.unicode_minus'] = False    # 解决负号显示问题

# 加载数据
ratings_path = r"d:\Users\Administrator\Desktop\3 电影推荐系统(学生)\ml-latest-small\ratings.csv"
movies_path = r"d:\Users\Administrator\Desktop\3 电影推荐系统(学生)\ml-latest-small\movies.csv"
links_path = r"d:\Users\Administrator\Desktop\3 电影推荐系统(学生)\ml-latest-small\links.csv"
tags_path = r"d:\Users\Administrator\Desktop\3 电影推荐系统(学生)\ml-latest-small\tags.csv"

ratings = pd.read_csv(ratings_path)
movies = pd.read_csv(movies_path)
links = pd.read_csv(links_path)
tags = pd.read_csv(tags_path)
# 显示每个数据集的前五个数据
print("\n评分数据 (ratings) 的前五行:")
display(ratings.head())

print("\n电影数据 (movies) 的前五行:")
display(movies.head())

print("\n链接数据 (links) 的前五行:")
display(links.head())

print("\n标签数据 (tags) 的前五行:")
display(tags.head())

三、数据处理与特征工程

3.1 构建用户-电影评分矩阵

为了便于后续计算用户和电影之间的相似性,我们将评分数据转换为用户-电影评分矩阵,其中行表示用户,列表示电影,矩阵值为评分:

# 构建用户-电影评分矩阵
user_movie_matrix = ratings.pivot(index='userId', columns='movieId', values='rating').fillna(0)

# 用户-电影评分矩阵稀疏性可视化
plt.figure(figsize=(10, 6))
sns.heatmap(user_movie_matrix != 0, cbar=False, cmap='viridis')
plt.title("用户-电影评分矩阵稀疏性")
plt.xlabel("电影ID")
plt.ylabel("用户ID")
plt.show()

3.2 数据稀疏性可视化

用户-电影评分矩阵通常具有较高的稀疏性,我们可以通过热力图直观地展示其分布情况:

四、模型构建

4.1 用户相似性计算

使用杰尔德相似性(Jaccard Similarity)计算用户之间的相似度,并生成用户相似性矩阵:

# 计算用户之间的杰尔德相似性
user_similarity = 1 - pairwise_distances(user_movie_matrix.to_numpy(), metric="jaccard")
user_similarity_df = pd.DataFrame(user_similarity, index=user_movie_matrix.index, columns=user_movie_matrix.index)

# 用户相似性矩阵可视化
plt.figure(figsize=(10, 8))
sns.heatmap(user_similarity_df, annot=True, cmap='coolwarm')
plt.title("用户相似性矩阵(杰尔德相似性)")
plt.xlabel("用户ID")
plt.ylabel("用户ID")
plt.show()

4.2 物品相似性计算

同样使用杰尔德相似性计算电影之间的相似度,并生成电影相似性矩阵

# 计算物品之间的杰尔德相似性
item_similarity = 1 - pairwise_distances(user_movie_matrix.T.to_numpy(), metric="jaccard")
item_similarity_df = pd.DataFrame(item_similarity, index=user_movie_matrix.columns, columns=user_movie_matrix.columns)

# 物品相似性矩阵可视化
plt.figure(figsize=(10, 8))
sns.heatmap(item_similarity_df, annot=True, cmap='coolwarm')
plt.title("物品相似性矩阵(杰尔德相似性)")
plt.xlabel("电影ID")
plt.ylabel("电影ID")
plt.show()

 

五、推荐系统实现

5.1 基于用户的协同过滤(UserCF)

为每个用户找到最相似的两个用户,并为其推荐未评分的电影:

# 找到每个用户最相似的两个用户
most_similar_users = {}
for user in user_similarity_df.index:
    similar_users = user_similarity_df[user].sort_values(ascending=False)[1:3]
    most_similar_users[user] = similar_users

# 输出结果
print("每个用户最相似的两个用户:")
for user, similar_users in most_similar_users.items():
    print(f"用户 {user} 最相似的两个用户:")
    display(similar_users)

 基于用户的协同过滤函数

# 基于用户的协同过滤推荐函数
def recommend_movies_usercf(user_id, top_n=5):
    user_ratings = user_movie_matrix.loc[user_id]
    unrated_movies = user_ratings[user_ratings == 0].index
    similar_users = most_similar_users[user_id].index
    recommendations = defaultdict(float)
    for movie in unrated_movies:
        for similar_user in similar_users:
            if user_movie_matrix.loc[similar_user, movie] > 0:
                recommendations[movie] += user_similarity_df.loc[user_id, similar_user] * user_movie_matrix.loc[similar_user, movie]
    recommendations = sorted(recommendations.items(), key=lambda x: x[1], reverse=True)[:top_n]
    return [(movies[movies['movieId'] == movie]['title'].values[0], score) for movie, score in recommendations]

5.2 基于物品的协同过滤(ItemCF)

为目标用户推荐与其已评分电影相似的其他电影:

 

# 基于物品的协同过滤推荐函数
def recommend_movies_itemcf(user_id, top_n=5):
    user_ratings = user_movie_matrix.loc[user_id]
    rated_movies = user_ratings[user_ratings > 0].index
    recommendations = defaultdict(float)
    for movie in item_similarity_df.index:
        if movie not in rated_movies:
            for rated_movie in rated_movies:
                recommendations[movie] += item_similarity_df.loc[movie, rated_movie] * user_ratings[rated_movie]
    recommendations = sorted(recommendations.items(), key=lambda x: x[1], reverse=True)[:top_n]
    return [(movies[movies['movieId'] == movie]['title'].values[0], score) for movie, score in recommendations]

 

六、结果展示

6.1 示例推荐

为用户 1 和用户 16分别推荐电影:

(可自定义)

user_ids = [1, 16]
for user_id in user_ids:
    recommendations_usercf = recommend_movies_usercf(user_id)
    print(f"\n为用户 {user_id} 推荐的电影(基于用户的协同过滤):")
    for title, score in recommendations_usercf:
        print(f"{title} (推荐分数: {score:.2f})")

    recommendations_itemcf = recommend_movies_itemcf(user_id)
    print(f"\n为用户 {user_id} 推荐的电影(基于物品的协同过滤):")
    for title, score in recommendations_itemcf:
        print(f"{title} (推荐分数: {score:.2f})")

 按照相似度推荐评分最高的几个进行推荐

 

七、总结

本文介绍了如何使用 Python 构建一个基于协同过滤算法的电影推荐系统。通过计算用户和电影之间的相似性,我们可以为用户提供个性化的电影推荐。本项目的主要步骤包括:

  1. 数据加载与预处理。
  2. 用户和电影相似性计算。
  3. 基于用户和基于物品的协同过滤推荐。

八、不足之处与改进方向

8.1 杰尔德相似性的局限性

在本项目中,我们使用了杰尔德相似性(Jaccard Similarity)来计算用户和电影之间的相似度。然而,这种方法存在一定的局限性,尤其是在处理评分数据时:

  • 评分信息的丢失 :杰尔德相似性仅关注用户是否对某部电影进行了评分,而忽略了评分的具体数值。例如,用户 A 和用户 B 对同一部电影分别评分为 5 分和 1 分,这两种评分在杰尔德相似性中被视为完全相同(即都为“有评分”),这显然不符合实际情况。
  • 不适合区间分值的数据 :电影评分是一个具有连续区间的数值(如 1 到 5 分),而杰尔德相似性更适合处理二值化数据(如“喜欢/不喜欢”或“已评分/未评分”)。因此,杰尔德相似性在这种场景下可能会导致推荐结果不够精准。

8.2 改进方向:使用余弦相似性

为了更好地利用评分数据中的区间信息,可以改用 余弦相似性(Cosine Similarity) 。余弦相似性通过计算两个向量之间的夹角余弦值来衡量相似性,能够直接考虑评分的具体数值,从而更准确地反映用户之间的兴趣相似度或电影之间的内容相似度。

8.3 其他改进方向

除了更换相似性度量方法外,还可以从以下几个方面进一步优化推荐系统:

  1. 数据预处理
    • 对评分矩阵进行归一化处理,减少不同用户评分尺度的差异。
    • 使用矩阵分解技术(如 SVD)降低稀疏性问题的影响。
  2. 模型扩展
    • 引入基于内容的推荐算法,结合电影的类型、标签等特征进行推荐。
    • 使用混合推荐模型,将协同过滤与深度学习相结合,进一步提升推荐效果。
  3. 冷启动问题
    • 针对新用户或新电影的冷启动问题,可以引入基于流行度的推荐策略或利用外部数据源(如 IMDb 或 TMDB 的元数据)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值