传统神经网络
以往:随着机器学习、深度学习的发展,语音、图像、自然语言处理逐渐取得了很大的突破,然而语音、图像、文本都是很简单的序列或者网格数据,是很结构化的数据,深度学习很善于处理该种类型的数据。
图神经网络
现实世界:并不是所有的事物都可以表示成一个序列或者一个网格,例如社交网络、知识图谱、复杂的文件系统等,也就是说很多事物都是非结构化的。
内容:
图的本体设计
图的种类(有向、无向、异质、二分、连接带权重)
节点连接数
图的基本表示-邻接矩阵
图的基本表示-连接列表和邻接列表
图的联通性
异质图
同质图:只包含一类型节点和一类型边
一个异质图G由一组节点V和一组边E构成。其中每个节点和每条边都对应着一种类型.T就是表示节点类型集合,R表示边类型集合。
二分图:G={V,E}
节点集V可以分为两种不相交的子集V1,V2。而E中的每条边都连接着V1中的一个节点和V2中的一个节点。二分图广泛用于捕获不同对象之间的互动。
只记录存在关系的节点对,每个节点依次排开,只记录与它有关系的节点
带权重的图
这里的features包括两种类型:结构(structural)特征、描述节点的属性(attribute)和properities特征
人工特征工程+机器学习
通过已知节点补全未知节点
目标:构造网络中的特征以及节点的位置
节点v的度数 k v k_{v} kv是节点v的邻居节点数(与v相连的边数)
缺陷:将所有邻居节点同等对待,无法捕捉邻居节点的重要性。(如果几个节点的度数相同,则特征向量相同,则模型对它们做出的预测相同。没办法区分它们)
那能否对三角形进行扩展,一般化为计算给定节点附近预先指定的子图的数量——graphlets,将仅仅对三角形的计数扩展到任意结构的子图。
graphlets:rooted(基于给定节点)连通的异构子图与motifs区分
因为graphlets是诱导子图( induced subgraph 节点的所有连接都要包含在内),所以节点在位置c不行,另两个节点必须要连接。
GDV提供了一种测量节点局部网络拓扑的方法,通过比较两个节点的GDV提供了一种比node degree和聚类系数更细节的测量局部拓扑相似性的方法。
node features可以分为:
Importance-based features:捕获节点在图中的重要性
node degree:只计算了节点邻居节点的数量
Node centrality:可以区别对待邻居节点Models importance of neighboring nodes
Structure-based features:捕获节点局部邻域的拓扑结构
node degree:只计算了节点邻居节点的数量
聚类系数:用来评价节点周围邻居节点的连接程度
GDV:计数不同的graphlets的数量
通过已知连接补全未知连接
链接预测任务的两种公式:
随机缺失边
移除一组随机的链接,然后目标是预测它们的连接情况。类似于化学键研究,不同的化学键的功能不一样。
随时间演化边
现在有一个按照时间 t 0 ′ {t_0}' t0′时候的边来定义的图 G [ t 0 , t 0 ′ ] G[t_0,{t_0}'] G[t0,t0′],输出一个排序后的边列表,这里的边不是之前 t 0 ′ {t_0}' t0′时候的边,而是按照时间预测出来的 G [ t 1 , t 1 ′ ] G[t_1,{t_1}'] G[t1,t1′]。这个类似于人随着时间发展扩展自己的朋友圈。采用的评价方式是 [ t 1 , t 1 ′ ] [t_1,{t_1}'] [t1,t1′]时间段内产生的新边期望和取L的最上面n个元素,并计算正确的边数。
两点间最短路径的长度 distance-based feature:
缺点:这种方式的问题在于没有考虑两个点邻居的重合度(the degree of neighborhood overlap),如B-H有2个共同邻居,B-E和A-B都只有1个共同邻居。
local neighborhood overlap的限制在于,如果两个点没有共同邻居,值就为0。
显然 A u v \mathbf{A}_{uv} Auv 代表u和v之间长度为1的路径的数量。上图计算了 P ( 1 ) \mathbf{P}^{(1)} P(1),接下来要计算 P ( 2 ) \mathbf{P}^{(2)} P(2),具体方法如下:
如图所示,计算u和v之间长度为2的路径数量,就是计算每个u 的邻 A u i \mathbf{A}_{ui} Aui(与u有长度为1的路径)与v之间长度为1的路径数量 P i v ( 1 ) \mathbf{P}_{iv}^{(1)} Piv(1) 即 A i v \mathbf{A}_{iv} Aiv的总和 ∑ i A u i ∗ A i v = A u v 2 \sum_{i} \mathbf{A}_{ui} *\mathbf{A}_{iv}=\mathbf{A}_{uv}^2 ∑iAui∗Aiv=Auv2
同理,更高的幂(更远的距离)就重复过程,继续乘起来。
从而得到Katz index的计算方式:
总结:
图级别特征构建目标:找到能够描述全图结构的特征。
类似于SVM的核函数,定义好以后,通过核函数矩阵的映射,就可以按照之前的方式来处理了。
图核:度量两个图之间的相似性:
回想之前NLP领域应用最多的词袋模型(Bag-of-Words (BoW)),它是将单词计数作为文档的特性(不考虑排序)。
这里我们把图看作一个向量,图中节点看作是单词。
如上图所示,光用node不够的话,可以设置一个degree kernel,用bag-of-degrees来描述图特征。
Key idea: 计算图表中不同的graphlets的数量这里graphlet的定义与节点级特性略有不同,俩处不同在于:
graphlet kernel就是直接点积两个图的graphlet count vector得到相似性。对于图尺寸相差较大的情况需进行归一化
graphlet kernel的限制:计算昂贵,原因如下:
接下来,就是对刚才graphlet核方法的改进。
相比graphlet kernel代价较小,效率更高。用节点邻居结构迭代地来扩充节点信息。
广义的节点度袋,因为节点度是单跳邻域信息。
color refinement示例
把邻居颜色聚集起来
对聚集后颜色取哈希值
把hash后的颜色聚集起来
进行K次迭代12后,用整个迭代过程中颜色出现的次数作为Weisfeiler-Lehman graph feature
通过颜色计数向量的内积计算WL核值
WL kernel的优势在于计算成本低
Graphlet Kernel
Weisfeiler-Lehman Kernel
# 导入工具包
import networkx as nx
import matplotlib.pyplot as plt
%matplotlib inline
plt.rcParams['font.sans-serif']=['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False # 用来正常显示负号
# 1.全连接无向图
G=nx.complete_graph(6)
nx.draw(G)
# 判断是否是有向图
print(G.is_directed())
# 全图连接数
G.size()
# 2.全连接有向图
J=nx.complete_graph(6,nx.DiGraph())
nx.draw(J)
# 判断是否是有向图
print(J.is_directed())
# 全图连接数
J.size()
# 1.导入 csv 文件定义的三元组连接表,构建有向图
import pandas as pd
df = pd.read_csv('./【A】networkx基本说明/【A3】创建图-连接表和邻接表创建图/triples.csv')
# print(df)
# 2.通过连接表Edge List创建图
G = nx.DiGraph()
edges = [edge for edge in zip(df['head'], df['tail'])] #生成节点列表
G.add_edges_from(edges) # 添加节点
# print(G.edges('关羽')) #查看节点参数
# 3.可视化
pos = nx.spring_layout(G, seed=123) # 节点排版布局-默认弹簧布局,随机数种子
plt.figure(figsize=(10,10))
nx.draw(G, pos=pos, with_labels=True)
# 4.查看全图参数
print(G)
len(G)
G.size()
G.nodes
# 5.保存并载入邻接表Adjacency List
for line in nx.generate_adjlist(G):
print(line)
# 将邻接表导出为本地文件 grid.edgelist
nx.write_edgelist(G, path="grid.edgelist", delimiter=":")
# 从本地文件 grid.edgelist 读取邻接表
H = nx.read_edgelist(path="grid.edgelist", delimiter=":")
# 可视化
plt.figure(figsize=(10,10))
pos = nx.spring_layout(H, iterations=3, seed=123)
nx.draw(H, pos, with_labels=True)
plt.show()
# 1.创建无节点、无连接的空图
G = nx.Graph()
G.nodes
# 2.添加单个节点
G.add_node('刘备')
# 3.添加多个节点
G.add_nodes_from(['诸葛亮', '曹操'])
G.add_nodes_from(range(100, 105))
# 4.添加带属性特征的节点
G.add_nodes_from([
('关羽',{'武器': '青龙偃月刀','武力值':90,'智力值':80}),
('张飞',{'武器': '丈八蛇矛','武力值':85,'智力值':75}),
('吕布',{'武器':'方天画戟','武力值':100,'智力值':70})
])
print(G.nodes) #节点数
# 可视化
# nx.draw(G)
# 5.将H的节点添加到G中
## 创建另一个首尾相连成串的线性串珠图
H = nx.path_graph(10)
G.add_nodes_from(H) # 将H的节点添加到G中
print(G.nodes) #节点数
# 可视化
nx.draw(G)
# 创建单个连接,设置属性特征
G.add_edge(0, 1, weight=0.5, like=3) # 特征属性的名字可以随便起
# 创建多个连接
G.add_edges_from([
(1,2, {'weight': 0.3, 'like':5}),
(2, 0, {'weight': 0.1, 'like':8})
])
#
G.edges[(0, 1)] # 查看连接属性,edges-连接
# 全图连接信息
print(G.number_of_edges())
G.size()
# G.edges()
G.edges(data=True) # 带属性的连接
# 遍历所有连接,data=True 表示输出连接特征属性信息
for edge in G.edges(data=True):
print(edge)
# 指定节点
node_id = 1
G.degree[node_id] # 节点连接数
# 指定节点的所有相邻节点
for neighbor in G.neighbors(node_id):
print("Node {} has neighbor {}".format(node_id, neighbor))
# 导入工具包
import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
# 规范中文格式
plt.rcParams['font.sans-serif']=['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False # 用来正常显示负号
# 创建4x4网格图
G = nx.grid_2d_graph(4, 4)
pos = nx.spring_layout(G, seed=123)
plt.figure(figsize=(4,4))
nx.draw(G, pos, with_labels=True)
# 不显示节点
plt.figure(figsize=(4,4))
nx.draw(G, pos, node_size=0, with_labels=False)
# 设置颜色
len(G.edges()) #边的长度
plt.figure(figsize=(4,4))
nx.draw(
G,
pos,
node_color='#A0CBE2', # 节点颜色
edgecolors='red', # 节点外边缘的颜色
edge_color="blue", # edge的颜色
# edge_cmap=plt.cm.coolwarm, # 配色方案
node_size=800,
with_labels=False,
width=3,
)
# 有向图
plt.figure(figsize=(4,4))
nx.draw(
G.to_directed(),
pos,
node_color="tab:orange",
edgecolors="tab:gray",
node_size=400,
with_labels=False,
arrowsize=10,
width=2,
)
给定一个图,提取features(node edge graph-level features),然后学习一个模型,最终将这个模型用于预测。
抽取d个特征,编码为D维向量。
时间大多花费在特征工程中(为了能找到最好描述网络的特征,最后将特征用在下流预测任务)。
对节点进行encoder(映射到embedding 空间),因此在embedding空间中的相似性近似于原始图中的相似性。学习这个encoder
比较简单的Encoder只是一个embeddiing-lookup(查找表)。只要找到一个embeddings的矩阵,就只需要查找对应编号的节点的embedding。Z是d×|V|维的矩阵,第i列为节点i的embedding。v是位置向量(indicator),是one-hot编码,除了表明是节点v的元素为1,其它元素都为0.
每一个节点被分配一个独一无二的embedding 向量,我们直接优化每一个每一个节点的embedding。
当然之后也会介绍deep encoder
学习节点嵌入是unsupervised/self-supervised的方式,因为:
使用灵活的,有偏向的random walks可以平衡网络的局部全局视角,使用BFS搜索(局部)DFS搜索(全局)搜寻节点u的邻居 N R ( u ) N_{R}(u) NR(u)。
有两个超参数p和q:p是返回上一个节点,q是走开远离参数。1代表和上一个节点同一水平。
Link Analysis approaches—计算图中节点重要性
以网页为例,节点是web pages 边是超链接,仅考虑早期导航类型的超链接,不考虑现在事务性的超链接(发布评论、购买)。web是有向边。
web pages的重要性并不相同,利用web graph的链接结构为pages的重要性排序。
基本思路
一个页面很重要:如果他被其他重要的pages指向。
利用M计算上述的Flow equation(如果利用Gaussian elimination则太复杂)
M的限制条件 :M的每列和要为1。
flow equation可以写为: r = M ∗ r r = M*r r=M∗r
rank vector(重要性得分)r 是随机邻接矩阵M特征值为1的特征向量
PageRank: