图神经网络实战——基于Node2Vec的电影推荐系统

2024-03-14 09:04

本文主要是介绍图神经网络实战——基于Node2Vec的电影推荐系统,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

图神经网络实战——基于Node2Vec的电影推荐系统

    • 0. 前言
    • 1. 基于 Node2Vec 的电影推荐系统
    • 2. 构建训练数据集
    • 3. 实现基于 Node2Vec 的电影推荐系统
    • 相关链接

0. 前言

Node2Vec 是一种用于获取节点嵌入 (node embedding) 的算法,它通过将图形数据转换为低维向量空间中的连续向量来捕捉节点之间的相似性。基于 Node2Vec 的电影推荐系统结合了图论和深度学习的方法来进行推荐。
在电影推荐系统中,可以将每部电影视为一个节点,而节点之间的连接则表示电影之间的关联或相似性。Node2Vec 算法可以在电影图谱上学习出每部电影的向量表示,这些向量可以捕获电影之间的隐含关系,例如共同的演员、导演、类型等等。一旦得到了电影的向量表示,就可以使用这些表示来计算电影之间的相似度,并基于相似度来进行推荐。通过将用户喜欢的电影与其向量表示进行比较,系统可以推荐与之相似的其他电影。在本节中,构建基于 Node2Vec 的电影推荐系统 (recommender system, RecSys)。

1. 基于 Node2Vec 的电影推荐系统

电影推荐系统 (recommender system, RecSys) 是图神经网络 (Graph Neural Networks, GNN) 最受欢迎的应用之一。我们知道 Word2Vec (以及 DeepWalk 和 Node2Vec) 的目标是生成能够测量相似度的向量。将电影(而非单词)进行编码,就能获取与给定输入标题最相似的电影,这就是 RecSys 的基本思想。
但问题在于如何对电影进行编码,我们首先想到可以创建电影的(有偏)随机游走,但这需要一个相似电影相互连接的图数据集,获取这类数据集并不容易。
另一种方法是根据用户评分来构建图。有多种基于评分构建图的技术,包括二分图、基于点互信息的边等。在本节中,我们将采用一种简单直观的方法,将受到同一用户喜爱的电影连接起来。然后,将使用所构建的图基于 Node2Vec 学习电影嵌入。

2. 构建训练数据集

(1) 首先,下载并解压电影数据集。在本节中,使用 MovieLens 数据集的子集,其中包含 100836 条评分、9742 部电影和 610 个用户。我们主要使用文件 atings.csvmovies.csv,第一个文件存储用户的所有评分,第二个文件可以用于将电影标识符转换为标题。

(2) 使用 pd.read_csv() 导入文件 atings.csv

import pandas as pdratings = pd.read_csv('ml-100k/u.data', sep='\t', names=['user_id', 'movie_id', 'rating', 'unix_timestamp'])
print(ratings)

输出结果如下所示:

       user_id  movie_id  rating  unix_timestamp
0          196       242       3       881250949
1          186       302       3       891717742
2           22       377       1       878887116
3          244        51       2       880606923
4          166       346       1       886397596
...        ...       ...     ...             ...
99995      880       476       3       880175444
99996      716       204       5       879795543
99997      276      1090       1       874795795
99998       13       225       2       882399156
99999       12       203       3       879959583
[100000 rows x 4 columns]

(3) 导入 movies.csv

movies = pd.read_csv('ml-100k/u.item', sep='|', usecols=range(2), names=['movie_id', 'title'], encoding='latin-1')
print(movies)

数据集输出结果如下所示:

      movie_id                                      title
0            1                           Toy Story (1995)
1            2                           GoldenEye (1995)
2            3                          Four Rooms (1995)
3            4                          Get Shorty (1995)
4            5                             Copycat (1995)
...        ...                                        ...
1677      1678                          Mat' i syn (1997)
1678      1679                           B. Monkey (1998)
1679      1680                       Sliding Doors (1998)
1680      1681                        You So Crazy (1994)
1681      1682  Scream of Stone (Schrei aus Stein) (1991)
[1682 rows x 2 columns]

(4) 由于我们想得用户可能喜欢的电影,因此意味着评分为 123 并不非常重要,我们可以舍弃这些评分,只保留评分为 45 的数据:

ratings = ratings[ratings.rating >= 4]
print(ratings)

得到输出结果如下所示:

       user_id  movie_id  rating  unix_timestamp
5          298       474       4       884182806
7          253       465       5       891628467
11         286      1014       5       879781125
12         200       222       5       876042340
16         122       387       5       879270459
...        ...       ...     ...             ...
99988      421       498       4       892241344
99989      495      1091       4       888637503
99990      806       421       4       882388897
99991      676       538       4       892685437
99996      716       204       5       879795543
[55375 rows × 4 columns]

(5) 我们已经获取了由 610 个用户给出的 48580 条评分。下一步是统计两部电影被同一用户喜欢的次数,对数据集中的每个用户重复这一过程。为了简化操作,使用 defaultdict 数据结构,它可以自动创建缺失条目,而不会引发错误,使用这种结构统计同时被喜欢的电影的次数:

from collections import defaultdictpairs = defaultdict(int)

(6) 循环浏览数据集中的用户列表:

for group in ratings.groupby("user_id"):

(7) 获取当前用户已赞过的电影列表:

    user_movies = list(group[1]["movie_id"])

(8) 每当一对电影在同一个列表中同时出现时,就递增一个特定的计数器:

    for i in range(len(user_movies)):for j in range(i+1, len(user_movies)):pairs[(user_movies[i], user_movies[j])] += 1

(9) pairs 对象存储了两部电影被同一用户点赞的次数,可以利用这些信息来构建图中的边。使用 networkx 库创建图 G

G = nx.Graph()

(10) 对于 pairs 中的每对电影,解包这两部电影及其相应的评分:

for pair in pairs:movie1, movie2 = pairscore = pairs[pair]

(11) 如果得分高于 20,就会在图中添加一个加权连接,根据得分将两部电影连接起来。忽略低于 20 的分数,因为这样会创建一个较大的图,而其中的连接并无太大意义:

    if score >= 20:G.add_edge(movie1, movie2, weight=score)

(12) 最终得到的图有 410 个节点(电影)和 14,936 条边,接下来训练 Node2Vec 学习节点嵌入:

print("Total number of graph nodes:", G.number_of_nodes())
print("Total number of graph edges:", G.number_of_edges())# Total number of graph nodes: 410
# Total number of graph edges: 14936

3. 实现基于 Node2Vec 的电影推荐系统

我们可以重复使用 Node2Vec 一节中的 Node2Vec 实现,但在 Python 中有一个专门用于 Node2Vec 的库,在本节中,我们将使用此库实现 Node2Vec

(1) 首先,使用 pip 命令安装 node2vec 库:

pip install node2vec

(2) 在代码中,导入 Node2Vec 类,并创建一个 Node2Vec 实例,根据 pq 参数自动生成有偏随机游走序列:

from node2vec import Node2Vecnode2vec = Node2Vec(G, dimensions=64, walk_length=20, num_walks=200, p=2, q=1, workers=1)

(3) 窗口大小设置为 10 (前 5 个节点,后 5 个节点),对这些有偏随机游走序列进行模型训练:

model = node2vec.fit(window=10, min_count=1, batch_words=4)

Node2Vec 模型完成训练后,可以像使用 gensim 库中的 Word2Vec 对象一样使用它。接下来,创建函数根据给定的标题推荐电影。

(4) 创建 recommend() 函数,将电影标题作为输入。首先,将标题转换为电影 ID

def recommend(movie):movie_id = str(movies[movies.title == movie].movie_id.values[0])

(5) 循环遍历五个最相似的单词向量。将这些 ID 转换成电影标题,并打印出相应的相似度分数:

    for id in model.wv.most_similar(movie_id)[:5]:title = movies[movies.movie_id == int(id[0])].title.values[0]print(f'{title}: {id[1]:.2f}')

(6) 调用该函数来获得与《Star Wars (1977)》相似度最高的五部电影的余弦相似度:

recommend('Star Wars (1977)')

得到的输出结果如下所示:

Return of the Jedi (1983): 0.62
Raiders of the Lost Ark (1981): 0.57
Monty Python and the Holy Grail (1974): 0.53
Toy Story (1995): 0.47
Silence of the Lambs, The (1991): 0.46

可以看到,《Return of the Jedi》和《Raiders of the Lost Ark》与《Monty Python and the Holy Grail》最为相似,但得分相对较低( < 0.7)。尽管如此,对于我们初次构建推荐系统模型而言,这是一个相当不错的结果。在后续学习中,我们将使用更强大的模型和方法来构建更优秀的推荐系统模型。

相关链接

图神经网络实战(1)——图神经网络(Graph Neural Networks, GNN)基础
图神经网络实战(2)——图论基础
图神经网络实战(3)——基于DeepWalk创建节点表示
图神经网络实战(4)——基于Node2Vec改进嵌入质量

这篇关于图神经网络实战——基于Node2Vec的电影推荐系统的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/807909

相关文章

SpringBoot中四种AOP实战应用场景及代码实现

《SpringBoot中四种AOP实战应用场景及代码实现》面向切面编程(AOP)是Spring框架的核心功能之一,它通过预编译和运行期动态代理实现程序功能的统一维护,在SpringBoot应用中,AO... 目录引言场景一:日志记录与性能监控业务需求实现方案使用示例扩展:MDC实现请求跟踪场景二:权限控制与

Windows系统宽带限制如何解除?

《Windows系统宽带限制如何解除?》有不少用户反映电脑网速慢得情况,可能是宽带速度被限制的原因,只需解除限制即可,具体该如何操作呢?本文就跟大家一起来看看Windows系统解除网络限制的操作方法吧... 有不少用户反映电脑网速慢得情况,可能是宽带速度被限制的原因,只需解除限制即可,具体该如何操作呢?本文

CentOS和Ubuntu系统使用shell脚本创建用户和设置密码

《CentOS和Ubuntu系统使用shell脚本创建用户和设置密码》在Linux系统中,你可以使用useradd命令来创建新用户,使用echo和chpasswd命令来设置密码,本文写了一个shell... 在linux系统中,你可以使用useradd命令来创建新用户,使用echo和chpasswd命令来设

电脑找不到mfc90u.dll文件怎么办? 系统报错mfc90u.dll丢失修复的5种方案

《电脑找不到mfc90u.dll文件怎么办?系统报错mfc90u.dll丢失修复的5种方案》在我们日常使用电脑的过程中,可能会遇到一些软件或系统错误,其中之一就是mfc90u.dll丢失,那么,mf... 在大部分情况下出现我们运行或安装软件,游戏出现提示丢失某些DLL文件或OCX文件的原因可能是原始安装包

电脑显示mfc100u.dll丢失怎么办?系统报错mfc90u.dll丢失5种修复方案

《电脑显示mfc100u.dll丢失怎么办?系统报错mfc90u.dll丢失5种修复方案》最近有不少兄弟反映,电脑突然弹出“mfc100u.dll已加载,但找不到入口点”的错误提示,导致一些程序无法正... 在计算机使用过程中,我们经常会遇到一些错误提示,其中最常见的就是“找不到指定的模块”或“缺少某个DL

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推

Python列表去重的4种核心方法与实战指南详解

《Python列表去重的4种核心方法与实战指南详解》在Python开发中,处理列表数据时经常需要去除重复元素,本文将详细介绍4种最实用的列表去重方法,有需要的小伙伴可以根据自己的需要进行选择... 目录方法1:集合(set)去重法(最快速)方法2:顺序遍历法(保持顺序)方法3:副本删除法(原地修改)方法4:

在Spring Boot中浅尝内存泄漏的实战记录

《在SpringBoot中浅尝内存泄漏的实战记录》本文给大家分享在SpringBoot中浅尝内存泄漏的实战记录,结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录使用静态集合持有对象引用,阻止GC回收关键点:可执行代码:验证:1,运行程序(启动时添加JVM参数限制堆大小):2,访问 htt

mysql的基础语句和外键查询及其语句详解(推荐)

《mysql的基础语句和外键查询及其语句详解(推荐)》:本文主要介绍mysql的基础语句和外键查询及其语句详解(推荐),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋... 目录一、mysql 基础语句1. 数据库操作 创建数据库2. 表操作 创建表3. CRUD 操作二、外键

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析