新闻中心

使用协同过滤实现电影推荐

2025-07-23
浏览次数:
返回列表
本文以Movielens数据集为例,基于PaddlePaddle2.0用协同过滤算法实现电影推荐。先介绍数据集,含用户、电影ID及评分等文件。接着处理数据,编码用户和电影,划分训练与验证集。然后构建模型,将用户和电影嵌入向量并计算匹配分数。经训练评估后,能为用户推荐预测高分电影。

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

使用协同过滤实现电影推荐 -

使用协同过滤实现电影推荐

一、介绍

此示例演示使用Movielens 数据集基于PaddlePaddle2.0向用户推荐电影的协作过滤算法。MovieLens 评级数据集列出了一组用户对一组电影的评分。我们的目标是能够预测用户尚未观看的电影的收视率。然后,可以向用户推荐预测收视率最高的电影。

模型中的步骤如下:

1.通过嵌入矩阵将用户 ID 映射到"用户向量"

2.通过嵌入矩阵将电影 ID 映射到"电影载体"

3.计算用户矢量和电影矢量之间的点产品,以获得用户和电影之间的匹配分数(预测评级)。

4.使用所有已知的用户电影对通过梯度下降训练嵌入。
       

引用:

  • Item-based collaborative filtering recommendation algorithms

  • Neural Collaborative Filtering

2. 环境设置

PaddlePaddle框架,AI Studio平台已经默认安装最新版2.0。

In [10]
import pandas as pdimport numpy as npimport paddleimport paddle.nn as nnfrom paddle.io import Dataset
   

3. 数据集

这个数据集(ml-latest-small)描述了MovieLens的五星评级和自由文本标记活动。它包含100836个收视率和3683个标签应用程序,涵盖9742部电影。这些数据由610名用户在1996年3月29日至2018年9月24日期间创建。

该数据集于2018年9月26日生成,用户是随机选择的。所有选定的用户都对至少20部电影进行了评分。不包括人口统计信息。每个用户都由一个id表示,不提供其他信息。数据包含在文件中links.csv, movies.csv, ratings.csv以及tags.csv。

用户ID

MovieLens的用户是随机选择的

电影ID

数据集中只包含至少具有一个分级或标记的电影,这些电影id与MovieLens网站上使用的一致.。

分级数据文件结构(ratings.csv)

ECMall 繁体UFT-8 ECMall 繁体UFT-8

与 ECShop 不同的是,ECMall 是一个允许店铺加盟的多店系统。它不仅可以帮助众多成熟的网络社区实现社区电子商务还可以推进各种地域性、垂直性明显的门户网站的电子商务进程。 ECMall是一个根据融合了电子商务以及网络社区特色的产品,它不仅能使您的电子商务进程变得异常轻松,同时通过和康盛创想相关产品的结合还能进一步提高用户的活跃度以及黏性,从而促进用户的忠诚度。 ECMall 2.3.0 正

ECMall 繁体UFT-8 0 查看详情 ECMall 繁体UFT-8

所有评级都包含在文件中ratings.csv. 文件头行后的每一行代表一个用户对一部电影的一个分级,格式如下: userId,movieId,rating,timestamp

标记数据文件结构(tags.csv)

文件中包含所有标记tags.csv. 文件头行后的每一行代表一个用户应用于一部电影的一个标记,格式如下: userId,movieId,tag,timestamp

电影数据文件结构(movies.csv)

格式如下: 电影ID、片名、类型

链接数据文件结构(links.csv)

格式如下: 电影ID,imdbId,tmdbId

In [11]
!unzip data/data71839/ml-latest-small.zip
       
Archive:  data/data71839/ml-latest-small.zip
   creating: ml-latest-small/
  inflating: ml-latest-small/links.csv  
  inflating: ml-latest-small/tags.csv  
  inflating: ml-latest-small/ratings.csv  
  inflating: ml-latest-small/README.txt  
  inflating: ml-latest-small/movies.csv
       

数据处理

执行一些预处理,将用户和电影编码为整数指数

In [12]
df = pd.read_csv('ml-latest-small/ratings.csv')
user_ids = df["userId"].unique().tolist()
user2user_encoded = {x: i for i, x in enumerate(user_ids)}
userencoded2user = {i: x for i, x in enumerate(user_ids)}
movie_ids = df["movieId"].unique().tolist()
movie2movie_encoded = {x: i for i, x in enumerate(movie_ids)}
movie_encoded2movie = {i: x for i, x in enumerate(movie_ids)}
df["user"] = df["userId"].map(user2user_encoded)
df["movie"] = df["movieId"].map(movie2movie_encoded)

num_users = len(user2user_encoded)
num_movies = len(movie_encoded2movie)
df["rating"] = df["rating"].values.astype(np.float32)# 最小和最大额定值将在以后用于标准化额定值min_rating = min(df["rating"])
max_rating = max(df["rating"])print(    "Number of users: {}, Number of Movies: {}, Min rating: {}, Max rating: {}".format(
        num_users, num_movies, min_rating, max_rating
    )
)
       
Number of users: 610, Number of Movies: 9724, Min rating: 0.5, Max rating: 5.0
       

准备训练和验证数据

In [13]
df = df.sample(frac=1, random_state=42)
x = df[["user", "movie"]].values# 规范化0和1之间的目标。使训练更容易。y = df["rating"].apply(lambda x: (x - min_rating) / (max_rating - min_rating)).values# 假设对90%的数据进行训练,对10%的数据进行验证。train_indices = int(0.9 * df.shape[0])
x_train, x_val, y_train, y_val = (
    x[:train_indices],
    x[train_indices:],
    y[:train_indices],
    y[train_indices:],
)
y_train = y_train[: ,np.newaxis]
y_val = y_val[: ,np.newaxis]
y_train = y_train.astype(np.float32)
y_val = y_val.astype(np.float32)# 自定义数据集#映射式(map-style)数据集需要继承paddle.io.Datasetclass SelfDefinedDataset(Dataset):
    def __init__(self, data_x, data_y, mode = 'train'):
        super(SelfDefinedDataset, self).__init__()
        self.data_x = data_x
        self.data_y = data_y
        self.mode = mode    def __getitem__(self, idx):
        if self.mode == 'predict':           return self.data_x[idx]        else:           return self.data_x[idx], self.data_y[idx]    def __len__(self):
        return len(self.data_x)
        
traindataset = SelfDefinedDataset(x_train, y_train)for data, label in traindataset:    print(data.shape, label.shape)    print(data, label)    breaktrain_loader = paddle.io.DataLoader(traindataset, batch_size = 128, shuffle = True)for batch_id, data in enumerate(train_loader()):
    x_data = data[0]
    y_data = data[1]    print(x_data.shape)    print(y_data.shape)    breaktestdataset = SelfDefinedDataset(x_val, y_val)
test_loader = paddle.io.DataLoader(testdataset, batch_size = 128, shuffle = True)        
for batch_id, data in enumerate(test_loader()):
    x_data = data[0]
    y_data = data[1]    print(x_data.shape)    print(y_data.shape)    break
       
(2,) (1,)
[ 431 4730] [0.8888889]
[128, 2]
[128, 1]
[128, 2]
[128, 1]
       

4. 模型组网

将用户和电影嵌入到 50 维向量中。

该模型计算用户和电影嵌入之间的匹配分数,并添加每部电影和每个用户的偏差。比赛分数通过 sigmoid 缩放到间隔[0, 1]。

In [14]
EMBEDDING_SIZE = 50class RecommenderNet(nn.Layer):
    def __init__(self, num_users, num_movies, embedding_size):
        super(RecommenderNet, self).__init__()
        self.num_users = num_users
        self.num_movies = num_movies
        self.embedding_size = embedding_size
        weight_attr_user = paddle.ParamAttr(
            regularizer = paddle.regularizer.L2Decay(1e-6),
            initializer = nn.initializer.KaimingNormal()
            )
        self.user_embedding = nn.Embedding(
            num_users,
            embedding_size,
            weight_attr=weight_attr_user
        )
        self.user_bias = nn.Embedding(num_users, 1)
        weight_attr_movie = paddle.ParamAttr(
            regularizer = paddle.regularizer.L2Decay(1e-6),
            initializer = nn.initializer.KaimingNormal()
            )
        self.movie_embedding = nn.Embedding(
            num_movies,
            embedding_size,
            weight_attr=weight_attr_movie
        )
        self.movie_bias = nn.Embedding(num_movies, 1)    def forward(self, inputs):
        user_vector = self.user_embedding(inputs[:, 0])
        user_bias = self.user_bias(inputs[:, 0])
        movie_vector = self.movie_embedding(inputs[:, 1])
        movie_bias = self.movie_bias(inputs[:, 1])
        dot_user_movie = paddle.dot(user_vector, movie_vector)
        x = dot_user_movie + user_bias + movie_bias
        x = nn.functional.sigmoid(x)        return x
   

5. 模型训练

后台可通过VisualDl观察Loss曲线。

In [15]
model = RecommenderNet(num_users, num_movies, EMBEDDING_SIZE)
    In [16]
model = paddle.Model(model)

optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.0003)
loss = nn.BCELoss()
metric = paddle.metric.Accuracy()# # 设置visualdl路径log_dir = './visualdl'callback = paddle.callbacks.VisualDL(log_dir=log_dir)

model.prepare(optimizer, loss, metric)
model.fit(train_loader, epochs=5, s*e_dir='./checkpoints', verbose=1, callbacks=callback)
       
The loss value printed in the log is the current step, and the metric is the *erage value of previous step.
Epoch 1/5
step 709/709 [==============================] - loss: 0.6742 - acc: 0.8687 - 3ms/step        
s*e checkpoint at /home/aistudio/checkpoints/0
Epoch 2/5
step 709/709 [==============================] - loss: 0.6505 - acc: 0.8687 - 3ms/step        
s*e checkpoint at /home/aistudio/checkpoints/1
Epoch 3/5
step 709/709 [==============================] - loss: 0.6052 - acc: 0.8687 - 3ms/step        
s*e checkpoint at /home/aistudio/checkpoints/2
Epoch 4/5
step 709/709 [==============================] - loss: 0.5992 - acc: 0.8687 - 3ms/step        
s*e checkpoint at /home/aistudio/checkpoints/3
Epoch 5/5
step 709/709 [==============================] - loss: 0.5755 - acc: 0.8687 - 3ms/step        
s*e checkpoint at /home/aistudio/checkpoints/4
s*e checkpoint at /home/aistudio/checkpoints/final
       

6. 模型评估

In [17]
model.evaluate(test_loader, batch_size=64, verbose=1)
       
Eval begin...
The loss value printed in the log is the current batch, and the metric is the *erage value of previous step.
step 79/79 [==============================] - loss: 0.6166 - acc: 0.8713 - 2ms/step         
Eval samples: 10084
       
{'loss': [0.6166183], 'acc': 0.8712812376041253}
               

7. 模型预测

In [18]
movie_df = pd.read_csv('ml-latest-small/movies.csv')# Let us get a user and see the top recommendations.user_id = df.userId.sample(1).iloc[0]
movies_watched_by_user = df[df.userId == user_id]
movies_not_watched = movie_df[
    ~movie_df["movieId"].isin(movies_watched_by_user.movieId.values)
]["movieId"]
movies_not_watched = list(    set(movies_not_watched).intersection(set(movie2movie_encoded.keys()))
)
movies_not_watched = [[movie2movie_encoded.get(x)] for x in movies_not_watched]
user_encoder = user2user_encoded.get(user_id)
user_movie_array = np.hstack(
    ([[user_encoder]] * len(movies_not_watched), movies_not_watched)
)
testdataset = SelfDefinedDataset(user_movie_array, user_movie_array, mode = 'predict')
test_loader = paddle.io.DataLoader(testdataset, batch_size = 9703, shuffle = False, return_list=True,)   

ratings = model.predict(test_loader)
ratings = np.array(ratings)
ratings = np.squeeze(ratings, 0)
ratings = np.squeeze(ratings, 2)
ratings = np.squeeze(ratings, 0)
top_ratings_indices = ratings.argsort()[::-1][0:10]print(top_ratings_indices)
recommended_movie_ids = [
    movie_encoded2movie.get(movies_not_watched[x][0]) for x in top_ratings_indices
]print("Showing recommendations for user: {}".format(user_id))print("====" * 9)print("Movies with high ratings from user")print("----" * 8)
top_movies_user = (
    movies_watched_by_user.sort_values(by="rating", ascending=False)
    .head(5)
    .movieId.values
)
movie_df_rows = movie_df[movie_df["movieId"].isin(top_movies_user)]for row in movie_df_rows.itertuples():    print(row.title, ":", row.genres)print("----" * 8)print("Top 10 movie recommendations")print("----" * 8)
recommended_movies = movie_df[movie_df["movieId"].isin(recommended_movie_ids)]for row in recommended_movies.itertuples():    print(row.title, ":", row.genres)
       
Predict begin...
step 1/1 [==============================] - 17ms/step
Predict samples: 9149
[ 427 7916 2135 1725 6763  898 3749 5269 6498 1281]
Showing recommendations for user: 91
====================================
Movies with high ratings from user
--------------------------------
Nightmare Before Christmas, The (1993) : Animation|Children|Fantasy|Musical
Monty Python and the Holy Grail (1975) : Adventure|Comedy|Fantasy
Aliens (1986) : Action|Adventure|Horror|Sci-Fi
Shrek (2001) : Adventure|Animation|Children|Comedy|Fantasy|Romance
Tremors (1990) : Comedy|Horror|Sci-Fi
--------------------------------
Top 10 movie recommendations
--------------------------------
Schindler's List (1993) : Drama|War
Full Metal Jacket (1987) : Drama|War
Big Lebowski, The (1998) : Comedy|Crime
American History X (1998) : Crime|Drama
American Beauty (1999) : Drama|Romance
Amelie (Fabuleux destin d'Amélie Poulain, Le) (2001) : Comedy|Romance
Eternal Sunshine of the Spotless Mind (2004) : Drama|Romance|Sci-Fi
Departed, The (2006) : Crime|Drama|Thriller
Dark Knight, The (2008) : Action|Crime|Drama|IMAX
Inception (2010) : Action|Crime|Drama|Mystery|Sci-Fi|Thriller|IMAX
       

以上就是使用协同过滤实现电影推荐的详细内容,更多请关注其它相关文章!


# 将在  # 福建营销关键词排名优化  # 嘉兴网站购物推广公司  # 网站建设服务项目明细  # 济南seo搜索优化软件  # 邯郸网站建设创意  # 邗江关键词排名  # 乐至网站建设和优化服务  # 滨州网站开发二维码推广  # 宝安优质网站建设哪家快  # 丹阳网站建设企业  # 额定值  # 还能  # python  # 还可以  # 出了  # 的是  # 官网  # 中文网  # 是一个  # 一言  # type  # udio  # red  # ai 


相关栏目: 【 行业资讯67740 】 【 技术百科0 】 【 网络运营39195


相关推荐: 什么是域名解析 域名解析中采用了什么  点焊机接触器上power是什么意思  折叠屏手机哪个有性价比  typescript 如何解决 null  如何自己加装固态硬盘  抖音GMV是什么_抖音GMV是什么意思  阿里云盘扩容是什么_扩容阿里云盘方法是什么教程  如何更新typescript  苹果16系统有哪些系列  壁挂炉power常亮是什么意思  移动固态硬盘如何使用  税负是什么意思  怎么更新typescript  typescript中文怎么读  热水器没热水显示power是什么意思  课程伴侣电脑怎么登录  选哪个折叠屏手机好用  如何在一串数字前面去掉四位数的命令  春运抢票如何抢连坐的票  萝卜快跑的收费标准是什么  命令不执行如何处理  单片机软件keil怎么运行  如何体验苹果16系统  element ui的好处  一年多少周  命令行如何打开文件  cos150度等于多少  市盈率当中17A 18E是什么意思  苹果16promax有哪些颜色  typescript怎么写游戏  春运抢票哪个城市好抢  折叠屏有哪些手机  怎么看手机是不是双模5g手机  typescript如何使用  固态硬盘质量如何  meet是什么意思  春运抢票要用抢票软件吗  春运抢票准备什么  typescript性能如何  ftp$如何执行宏命令  vi命令如何退出  linux如何打开命令窗口  市盈率估值1stdv是什么意思  固态硬盘装完如何使用  ai文件里无法找到链接文件怎么解决  如何更新固态硬盘固件  哪个品牌有折叠屏手机卖  如何通过命令行聊天  手机全功能type-c接口是什么意思  如何用命令连接mysql 

搜索