图机器学习(11)——链接预测

图机器学习(11)——链接预测

    • 0. 链接预测
    • 1. 基于相似性的方法
      • 1.1 基于指标的方法
      • 1.2 基于社区的方法
    • 2. 基于嵌入的方法

0. 链接预测

链接预测 (link prediction),也称为图补全,是处理图时常见的问题。具体而言,给定一个部分观测的图(即某些节点对之间是否存在边无法确定),我们的目标是预测未知状态节点对之间是否存在边,如下图所示。

链接预测

设图 G=(V,E)G=(V,E)G=(V,E) 的节点集为 VVV,边集为 E=Eo∪EuE=E_o\cup E_uE=EoEu。其中,边集 EoE_oEo 表示已知边(观测到的链接),而边集 EuE_uEu 表示未知边(待预测的链接)。链接预测的目标是利用 VVVEoE_oEo 的信息来估计 EuE_uEu。该问题在时序图数据中同样常见。在此设定下,假设 GtG_tGt 是在时间点 ttt 观测到的图,我们的目标是预测该图在时间点 t+1t+1t+1 的边。
链接预测问题在各领域均有广泛应用:在社交网络中用于推荐好友关系,在电子商务平台中用于推荐商品;在生物信息学中则用于分析蛋白质相互作用。接下来,我们将介绍解决链接预测问题的两类方法——即基于相似性的方法和基于嵌入的方法。

1. 基于相似性的方法

本节介绍若干解决标签预测问题的简单算法,其核心思想是通过计算图中节点对的相似度函数来预测连接概率:若节点相似度高,则它们有较高的概率通过一条边连接。这些算法可分为两类:基于索引的方法和基于社区的方法。前者通过简单计算节点邻居关系指标得出结果,后者则使用关于节点所属社区的信息进行计算。接下来,以 networkx 库(具体模块为 networkx.algorithms.link_prediction )的标准实现为例进行演示。

1.1 基于指标的方法

本节介绍 networkx 中计算未连接节点间边概率的算法,这些算法均通过分析两节点邻居关系来构建简单指标。

资源分配指数 (resource allocation index)
该方法通过以下公式计算所有节点对的资源分配指数,进而估计节点 vvvuuu 之间存在连接的概率::
r(u,v)=∑w∈N(u)∩N(v)1∣N(w)∣r(u,v)=\sum_{w\in N(u)\cap N(v)}\frac 1{|N(w)|} r(u,v)=wN(u)N(v)N(w)1
在以上公式中,函数 N(v)N(v)N(v) 用于计算节点 vvv 的邻居集合,www 代表同时是 uuuvvv 邻居的节点。我们可以使用 networkx 计算该指数:

import networkx as nx
edges = [[1,3],[2,3],[2,4],[4,5],[5,6],[5,7]]
G = nx.from_edgelist(edges)
preds = nx.resource_allocation_index(G,[(1,2),(2,5),(3,4)])

resource_allocation_index 函数的第一个参数是输入图,第二个参数是待计算的潜在边列表。代码运行结果如下所示:

[(1, 2, 0.5), (2, 5, 0.5), (3, 4, 0.5)]

输出结果是一个包含 (1,2)(2,5)(3,4) 等节点对的列表及其对应的资源分配指数值。根据输出可知,这些节点对之间存在连接边的概率均为 0.5

Jaccard 系数
该算法基于 Jaccard 系数计算节点 uuuvvv 之间的连接概率:
J(u,v)=∣N(u)∩N(v)∣∣N(u)∪N(v)∣J(u,v)=\frac {|N(u)\cap N(v)|}{|N(u)\cup N(v)|} J(u,v)=N(u)N(v)N(u)N(v)
其中 N(v)N(v)N(v) 表示节点 vvv 的邻居集合。在 networkx 中可通过以下代码实现:

import networkx as nx
edges = [[1,3],[2,3],[2,4],[4,5],[5,6],[5,7]]
G = nx.from_edgelist(edges)
preds = nx.resource_allocation_index(G,[(1,2),(2,5),(3,4)])

代码运行结果如下所示:

[(1, 2, 0.5), (2, 5, 0.25), (3, 4, 0.3333333333333333)]

根据输出结果,节点 (1,2) 之间存在边的概率为 0.5,节点 (2,5) 之间为 0.25,节点 (3,4) 之间为 0.333
除此之外,networkx 库还提供了许多其他基于相似度得分的节点连接概率计算方法,例如 nx.adamic_adar_indexnx.preferential_attachment,分别基于 Adamic/Adar 指数和偏好连接指数计算。这些函数的参数格式与前述方法一致,均需输入图结构和待计算的节点对列表。

1.2 基于社区的方法

与基于指标的方法类似,本类算法同样通过计算指数来评估未连接节点的连接概率。二者的核心区别在于:基于社区的方法在生成指数前,需先计算节点所属社区信息,同时基于社区的算法逻辑融合了社区拓扑特征。接下来,我们将介绍一些常见的基于社区的方法。

社区公共邻居 (community common neighbor)
为了估算两个节点连接的概率,该算法计算公共邻居的数量,并将属于同一社区的公共邻居数量加到该值中。对于两个节点 uuuvvv,社区公共邻居值的计算方式如下:
c(u,v)=∣N(u)∪N(v)∣+∑w∈N(u)∩N(v)f(w)c(u,v)=|N(u)\cup N(v)|+\sum_{w\in N(u)\cap N(v)}f(w) c(u,v)=N(u)N(v)+wN(u)N(v)f(w)
其中,N(v)N(v)N(v) 表示节点 vvv 的邻居集合,当节点 wwwuuu 属于同一社区时 f(w)=1f(w)=1f(w)=1,否则为 000。在 networkx 中通过以下代码计算:

import networkx as nx
edges = [[1,3],[2,3],[2,4],[4,5],[5,6],[5,7]]
G = nx.from_edgelist(edges)
G.nodes[1]["community"] = 0
G.nodes[2]["community"] = 0
G.nodes[3]["community"] = 0
G.nodes[4]["community"] = 1
G.nodes[5]["community"] = 1
G.nodes[6]["community"] = 1
G.nodes[7]["community"] = 1
preds = nx.cn_soundarajan_hopcroft(G,[(1,2),(2,5),(3,4)])

从上述代码中可以看到,我们需要为图中的每个节点分配社区属性 (community property)。该属性用于在计算前文定义的 f(v)f(v)f(v) 函数时,识别属于同一社区的节点,社区属性值也可以通过特定算法自动计算获得。cn_soundarajan_hopcroft 函数接受输入图和我们希望计算得分的节点对。代码执行结果如下所示:

[(1, 2, 2), (2, 5, 1), (3, 4, 1)]

与前述其它函数的主要区别在于指标值的范围。可以看到,该函数的输出值并不限定在 (0,1) 区间内。

社区资源分配 (community resource allocation)
与社区共同邻居算法类似,社区资源分配算法将从节点邻居处获得的信息与节点所属社区特征合并:
c(u,v)=∑w∈N(u)∩N(v)f(w)∣N(w)∣c(u,v)=\sum_{w\in N(u)\cap N(v)}\frac {f(w)}{|N(w)|} c(u,v)=wN(u)N(v)N(w)f(w)
其中,N(v)N(v)N(v) 表示节点 vvv 的邻居集合,当节点 wwwuuuvvv 属于同一社区时 f(w)=1f(w)=1f(w)=1,否则为 000。在 networkx 中的实现代码如下:

import networkx as nx
edges = [[1,3],[2,3],[2,4],[4,5],[5,6],[5,7]]
G = nx.from_edgelist(edges)
G.nodes[1]["community"] = 0
G.nodes[2]["community"] = 0
G.nodes[3]["community"] = 0
G.nodes[4]["community"] = 1
G.nodes[5]["community"] = 1
G.nodes[6]["community"] = 1
G.nodes[7]["community"] = 1
preds = nx. ra_index_soundarajan_hopcroft(G,[(1,2),(2,5),(3,4)])

从以上代码中可以看到,我们需要为图中的每个节点分配社区属性。该属性在计算前文定义的函数时,用于识别属于同一社区的节点,这些社区值也可以通过特定的算法自动计算获得。ra_index_soundarajan_hopcroft 函数接受输入图和我们希望计算得分的节点对。代码执行结果如下所示:

[(1, 2, 0.5), (2, 5, 0), (3, 4, 0)]

从输出结果可以明显看出社区属性对指数计算的影响:同属一个社区的节点 12 获得了较高的指数值 0.5,相反,分属不同社区的节点对 (2,5)(3,4) 则得分为 0
networkx 还提供了另外两种结合社区信息的连接概率计算方法:nx.within_inter_cluster (基于集群内外连接分析)和 nx.common_neighbor_centrality (基于共同邻居中心性)。
在下一节中,我们将介绍如何结合机器学习和边嵌入 (edge embedding) 来预测未知边。

2. 基于嵌入的方法

在本节中,我们将介绍一种更先进的链路预测方法。该方法的核心理念是将链路预测问题转化为监督式分类任务。具体而言,对于给定图数据,每对节点均通过特征向量 (xxx) 表示,并分配类别标签 (yyy)。形式化定义为:设图 G=(V,E)G=(V,E)G=(V,E),对于任意节点对 i,ji,ji,j,构建如下公式:
x=[f0,0,...,fi,j,...,fn,n]y=[y0,0,...,yi,j,...,yn,n]x=[f_{0,0},...,f_{i,j},...,f_{n,n}]\\ y=[y_{0,0},...,y_{i,j},...,y_{n,n}] x=[f0,0,...,fi,j,...,fn,n]y=[y0,0,...,yi,j,...,yn,n]
其中,fi,j∈xf_{i,j}\in xfi,jx 表示节点对 i,ji,ji,j 的特征向量,yi,j∈yy_{i,j}\in yyi,jy 为其对应标签。yi,jy_{i,j}yi,j 的取值规则为:若图 GGG 中存在连接节点 i,ji,ji,j 的边,则 yi,j=1y_{i,j}=1yi,j=1;否则 yi,j=0y_{i,j}=0yi,j=0。通过特征向量和标签数据,我们可以训练机器学习算法来预测特定节点对是否可能构成图中的合理边。
虽然节点对的标签向量构建相对简单,但特征空间的构建则更具挑战性。为生成每对节点的特征向量,我们将采用嵌入技术(如 node2vecedge2vec)。这些嵌入算法能显著简化特征空间的生成过程。整个流程可概括为两个核心步骤:

  1. 使用 node2vec 算法计算图 GGG 中每个节点的嵌入向量
  2. 对图中所有可能的节点对,使用 edge2vec 算法计算其嵌入表示

随后,我们可以将生成的嵌入特征向量输入通用机器学习算法来解决分类问题。为便于理解,我们通过代码示例演示完整流程(从图构建到链路预测),数据集采用论文引用网络数据集 Cora。

(1) 首先,基于该数据集构建 networkx 图结构:

import networkx as nx
import pandas as pd
from torch_geometric.utils import from_networkxedgelist = pd.read_csv("cora.cites", sep='\t', header=None, names=["target", "source"])
G = nx.from_pandas_edgelist(edgelist)
# 将图转换为PyG格式
pyg_data = from_networkx(G)
draw_graph(G, nx.spring_layout(G))

(2) 接下来,基于图 G 创建训练集和测试集。具体而言,数据集不仅需要包含图 G 中真实边的子集,还需包含不构成真实边的节点对。真实边对应的节点对将作为正样本(类别标签 1),而非真实边的节点对作为负样本(类别标签 0):

from sklearn.model_selection import train_test_split
import numpy as npedges = list(G.edges())
non_edges = list(nx.non_edges(G))train_edges, test_edges = train_test_split(edges, test_size=0.1, random_state=42)
train_non_edges, test_non_edges = train_test_split(non_edges, test_size=0.1)# Rebuild train graph without test edges
graph_train = nx.Graph()
graph_train.add_nodes_from(G.nodes())
graph_train.add_edges_from(train_edges)

(3) 对于每个实例,需要生成它们的特征向量。在本节中,使用 node2vec 库来生成节点嵌入:

from node2vec import Node2Vec
from node2vec.edges import HadamardEmbeddernode2vec = Node2Vec(graph_train)
model = node2vec.fit()
edges_embs = HadamardEmbedder(keyed_vectors=model.wv)# Create training data
samples_train = train_edges + train_non_edges
labels_train = [1]*len(train_edges) + [0]*len(train_non_edges)
train_embeddings = [edges_embs[str(x[0]), str(x[1])] for x in samples_train]# Create testing data
samples_test = test_edges + test_non_edges
labels_test = [1]*len(test_edges) + [0]*len(test_non_edges)
test_embeddings = [edges_embs[str(x[0]), str(x[1])] for x in samples_test]

(4) 使用 train_embeddings 特征空间和 train_labels 标签分配,最终训练机器学习算法来解决标签预测问题:

from sklearn.ensemble import RandomForestClassifier
from sklearn import metrics# Train classifier
rf = RandomForestClassifier(n_estimators=200)
rf.fit(train_embeddings, labels_train)# Predict and evaluate
y_pred = rf.predict(test_embeddings)print('Precision:', metrics.precision_score(labels_test, y_pred))
print('Recall:', metrics.recall_score(labels_test, y_pred))
print('F1-Score:', metrics.f1_score(labels_test, y_pred))

在本节中,使用了一个简单的 RandomForestClassifier 类,我们可以将训练好的模型应用到 test_embeddings 特征空间中,以量化分类的质量:

print('Precision:', metrics.precision_score(labels_test, y_pred))
print('Recall:', metrics.recall_score(labels_test, y_pred))
print('F1-Score:', metrics.f1_score(labels_test, y_pred))

结果输出如下:

Precision::0.8557114228456913
Recall:0.8102466793168881
F1-Score:0.8323586744639375

上述方法只是一个通用的框架,流程中的每个部分——例如训练/测试拆分、节点/边嵌入和机器学习算法——都可以根据具体问题进行修改。该方法在处理时序图的链接预测时尤为有效,此时在时间点 ttt 获取的边信息可用于训练模型,进而预测时间点 t+1t+1t+1 可能出现的边。
本节我们系统阐述了链接预测问题,通过多种示例详细介绍了链接预测的不同解决方案,展示了从基于简单指标的技术到基于嵌入的复杂技术的多元解决路径。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/91753.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/91753.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

简单2步配置CadenceSkill开发编辑器,支持关键字高亮

Cadence 使用过程中难免会与skill打交道,有时候网上找到的开源skill,想要查看或者编辑一下,常规的txt编辑器没有关键字高亮,看起来极为不方便。 利用Sublime Text可以很快速配置出支持skill关键字高亮的编辑器。 一、安装 Sublime…

Leetcode刷题营第三十三题:对称二叉树

101. 对称二叉树 给你一个二叉树的根节点 root , 检查它是否轴对称。 示例 1: 输入:root [1,2,2,3,4,4,3] 输出:true示例 2: 输入:root [1,2,2,null,3,null,3] 输出:false 提示:…

day055-Dockerfile与常用指令

文章目录0. 老男孩思想-女性的第一需求1. Dockerfile1.1 Dockerfile的基本结构1.2 案例-制作小鸟飞飞镜像1.2.1 编写Dockerfile文件1.2.2 构建镜像1.2.3 启动容器1.3 Dockerfile常用指令1.4 面试题:Dockerfile中CMD和ENTRYPOINT的区别?1.5 案例-制作zrlo…

Spring Boot 应用优雅停机与资源清理:深入理解关闭钩子

在开发和部署 Spring Boot 应用程序时,除了关注其启动和运行,理解如何实现**优雅停机(Graceful Shutdown)**也同样至关重要。优雅停机意味着在应用程序关闭时,能够有序地释放资源、完成正在进行的任务,并避…

淘宝扭蛋机小程序开发:重构电商娱乐化体验的新范式

在电商行业同质化竞争加剧的当下,消费者对购物体验的期待已从“功能满足”转向“情感共鸣”。淘宝扭蛋机小程序凭借“盲盒式随机奖励游戏化交互”的创新模式,成为撬动年轻用户消费力的新支点。其开发逻辑不仅是对传统电商的升级,更是对“娱乐…

YOLO演变史(一)

在YOLOV1发布后,作者并没有满足于此,而是持续对YOLO进行了改进。 YOLOV2:Better, Faster, Stronger YOLOv2(又称YOLO9000)发表于2017年CVPR,是YOLO系列的第二代版本。其论文标题“Better, Faster, Stronger…

专题:2025智能体研究报告|附70份报告PDF、原数据表汇总下载

原文链接:https://tecdat.cn/?p43035 智能体正在改写商业规则:某城商行的智能客服用公有云部署,把单笔交互成本从5.7元砍到1.2元,投诉率直降42%(《赛迪智库:2025全球智能体进展报告》P24)&…

Axios 完整功能介绍和完整示例演示

Axios 是一个基于 Promise 的现代化 HTTP 客户端库,用于浏览器和 Node.js 环境。它提供了简洁的 API 和强大的功能,是前端开发中最常用的网络请求工具之一。核心功能 浏览器 & Node.js 双平台支持 浏览器中使用 XMLHttpRequestNode.js 中使用 http 模…

math.h函数

math.c函数作用 1. 基本三角函数(参数为弧度) sin(double x):计算正弦值。cos(double x):计算余弦值。tan(double x):计算正切值。asin(double x):反正弦(返回值范围:[-π/2, π/2]&…

在Next.js里玩转pdf预览

1.背景在项目开发中,pdf预览是一个很常见的业务。各大公司为了保护自己的知识产权,也会对pdf预览进行限制,比如:不允许下载、打印,不允许提取文字等等。要想在实现预览功能的基础上还要附加这些限制,有很多…

算法竞赛备赛——【图论】求最短路径——Floyd算法

floyd算法 基于动态规划 应用:求多源最短路 时间复杂度:n^3 dijkstra:不能解决负边权 floyd:能解决负边权 不能解决负边权回路问题 求最短路径:dijkstra bfs floyd 思路 1.让任意两点之间的距离变短:引入…

双指针(滑动窗口)相关算法题

双指针算法有时候也叫尺取法或者滑动窗口,是⼀种优化暴力枚举策略的手段:当我们发现在两层 for 循环的暴力枚举过程中,两个指针是可以不回退的,此时我们就可以利用两个指针不回退的性质来优化时间复杂度。因为双指针算法中&#x…

ScratchCard刮刮卡交互元素的实现

效果展示 刮刮卡是⼀种常见的网页交互元素,通过模拟物理世界的刮涂层来揭示下方的内容。这种效果主要依赖于HTML5的 元素来实现。以下是⼀个基于TypeScript的刮刮卡实现示例,包括配置项、初始化方法和核心的刮开逻辑。下面是展示的效果部分刮开效果&…

【Python LeetCode 专题】热题 100,重在思路

哈希1. 两数之和49. 字母异位词分组128. 最长连续序列双指针283. 移动零11. 盛最多水的容器15. 三数之和42. 接雨水滑动窗口3. 无重复字符的最长子串438. 找到字符串中所有字母异位词子串560. 和为 K 的子数组239. 滑动窗口最大值普通数组53. 最大子数组和56. 合并区间189. 轮转…

openEuler 22.03 LTS Rootless Docker 安装指南

openEuler 22.03 LTS Rootless Docker 安装指南 1.创建普通用户(用于无根模式) sudo useradd -m docker-user sudo passwd docker-user # 设置密码 sudo usermod --add-subuids 100000-165535 docker-user sudo usermod --add-subgids 100000-165535 do…

CMake指令:常见内置命令行工具( CMake -E )

目录 1.简介 2.核心作用 3.常用命令介绍 3.1.文件操作命令 3.2.系统命令执行 3.3.校验与哈希 3.4.流程控制与等待 3.5.路径与文件处理 3.6.归档与压缩 3.7.网络与下载 3.8.实用工具 4.使用示例 5.与 shell 命令的对比 6.在 CMake 脚本中使用 7.总结 相关链接 1…

YOLO融合CAF-YOLO中的ACFM模块

YOLOv11v10v8使用教程: YOLOv11入门到入土使用教程 YOLOv11改进汇总贴:YOLOv11及自研模型更新汇总 《CAF-YOLO: A Robust Framework for Multi-Scale Lesion Detection in Biomedical Imagery》 一、 模块介绍 论文链接:https://arxiv.org…

Webpack 项目构建优化详解

1. 相关面试题 1.1. 做过哪些Webpack打包构建优化? 代码分割:使用 Webpack 的 SplitChunksPlugin 进行代码分割,将第三方库、公共代码与业务代码分离,提高缓存利用率和加载速度。 Tree Shaking:通过配置 mode: production 或使用 TerserPlugin,移除未引用的代码,减少…

【深度学习基础】张量与Tensor的区别?从标量到深度学习的多维世界

目录引言一、张量(Tensor)的定义与特性1. 数学中的张量2. 深度学习中的Tensor二、标量(Scalar)是什么?三、深度学习中的其他核心量1. 向量(Vector)2. 矩阵(Matrix)3. 高阶…

设计模式一: 模板方法模式 (Template Method Pattern)

模板方法模式是一种行为设计模式,它通过定义一个算法的骨架,而将一些步骤延迟到子类中实现。Template Method 使得子类可以不改变(复用)一个算法结构 即可重定义(override 重写)该算法的某些特定步骤。基本…