基于图有很多任务,比如:
- 节点分类:预测哪些网站是诈骗网站;
- 关系预测:判断图中两个节点的关系;
- 图分类:分子性质预测;
- 聚类:社交网络分析,将相似用户聚类在一起,再推荐适合该簇的商品;
- 图生成:药物分子生成,药物发现;
图基础内容
节点的度:节点的边的数量。对于有向图,度还可以分为入度和出度。
其中,C节点的度为3,入度为2,出度为1。对于上面的图,有7个节点,可以得到一个度矩阵,度矩阵只在对角线上有值,分别为7个节点的度。
邻接矩阵用于表示整个图的权重连接关系。度矩阵通常用 D D D表示,邻接矩阵通常用 A A A表示。无向图的邻接矩阵是沿着对角线对称的。
图遍历
深度优先:
- 从图中某个初始顶点 v v v出发,首先访问初始顶点 v v v;
- 选择一个与顶点 v v v相邻且没有被访问过的顶点 w w w,再从 w w w出发进行深度优先搜索,直到图中与当前顶点 v v v相邻的所有顶点都被访问过为止。
广度优先:
- 从图中某个初始顶点 v v v出发,首先访问初始顶点 v v v;
- 接着访问 v v v的所有未被访问过的相邻顶点 v 1 , . . . , v t v_1,...,v_t v1,...,vt;按照 v 1 , . . . , v t v_1,...,v_t v1,...,vt的次序,访问每一个顶点的所有未被访问过的相邻顶点;
- 直到访问过所有顶点为止。
DFS和BFS的举例如下:
Dijkstra是一种求解最短路径的算法,其本质是一个贪心算法,因此可能无法求得全局最优解,时间复杂度为 O ( n 2 ) O(n^2) O(n2)。详细见其他算法-Dijkstra。
初始化一个数组dis
来保存源点到各个顶点的最短距离,和一个保存已经找到了最短路径的顶点的集合T
,初始时,原点s
的路径权重被赋为 0 ,若对于顶点s
存在能直接到达的边(s,m)
,则把dis[m]
设为w(s,m)
,同时把所有其他顶点的路径长度设为无穷大。初始时,集合T
只有顶点s
。然后,从dis
数组选择最小值,则该值就是源点s
到该值对应的顶点的最短路径,并且把该点加入到T
中,然后,我们需要看看新加入的顶点是否可以到达其他顶点并且看看通过该顶点到达其他点的路径长度是否比源点直接到达短,如果是,那么就替换这些顶点在dis
中的值。然后,又从dis
中找出最小值,重复上述动作,直到T
中包含了图的所有顶点。
Floyd也是一种最短路径算法。首先,根据节点的边的权重,初始化一个矩阵,用于记录初始情况下的最短路径,然后分别计算允许通过其他节点时的最短路径,直到遍历完所有的情况。
图聚类
模块度Modularily用于衡量一个社区的紧密度,一个节点如果加入某个社区让模块度变大,则该节点属于这个社区。 M = 1 2 m ∑ i j [ A i j − k i k j 2 m ] U ( c i , c j ) M=\frac{1}{2m}\sum_{ij}[A_{ij}-\frac{k_{i}k_{j}}{2m}]U(c_i,c_j) M=2m1ij∑[Aij−2mkikj]U(ci,cj)其中,如果 c i = c j c_i=c_j ci=cj,则 U ( c i , c j ) = 1 U(c_i,c_j)=1 U(ci,cj)=1,如果 c i ≠ c j c_i\neq c_j ci=cj,则 U ( c i , c j ) = 0 U(c_i,c_j)=0 U(ci,cj)=0, m m m表示边的总数, A A A表示边的权重, k i k_i ki表示所有指向节点 i i i的边的权重和。
Louvain是基于模块度的社区算法,该算法在效率和效果都比较好,算法过程如下:
- 每个点作为一个社区,然后考虑每个社区的邻居节点,再合并到社区,然后看模块度是否改变,选择模块度增益最大的邻居节点进行合并,直到社区不再改变;
谱聚类的思想是将带权无向图划分为子图,子图的内部尽可能相似,子图之间尽量远离,谱聚类分为以下步骤:
- 计算相似度矩阵 W W W:一共 n n n个样本,计算任意两个样本之间的距离,在相似度矩阵中,两个距离近的样本相似度较高,根据相似度矩阵构建图,图的边仅保留相似度高的节点对;
- 计算度矩阵:根据相似度矩阵构建的图计算度矩阵 D D D;
- 计算拉普拉斯矩阵: L = D − W L=D-W L=D−W;
- 计算 L L L的特征值,将特征值从小到大排序,取前 k k k个特征值,并计算前 k k k个特征值的特征向量;
- 将 k k k个特征向量组成矩阵 U U U,维度为 n × k n\times k n×k;
- 使用K-means对 n n n个特征向量进行聚类;
谱聚类算法的主要优点有:
- 谱聚类只需要数据之间的相似度矩阵,因此对于处理稀疏数据的聚类很有效。这点传统聚类算法比如K-Means很难做到。
- 由于使用了降维,因此在处理高维数据聚类时的复杂度比传统聚类算法好。
谱聚类算法的主要缺点有:
- 聚类效果依赖于相似矩阵,不同的相似矩阵得到的最终聚类效果可能很不同。
Node2Vec
Node2Vec是指对节点的embedding学习。一种直接的想法是采用和Word2Vec一样的字典式方式。
从图的结构直观看,两个节点的embedding相似应该出现在以下情况:节点相连,两节点具有同样的邻居,两个节点处在相似结构的子图中。
随机游走(RandomWalk)是自监督学习embedding的方法,不需要利用节点标签,也不需要利用节点特征,训练好的embedding也不依赖于特定任务,如同Word2Vec。
首先随机选择一个节点,走到该处后再随机选择一个邻居,重复length
次。length
是指随机游走的长度。使用随机游走从起始节点到终止节点的概率值,实际上可以用来表示相似度,即从
u
u
u节点到
v
v
v节点的概率值,正比于
u
u
u节点和
v
v
v节点embedding点乘的结果:
z
v
T
z
u
∝
P
(
v
∣
u
)
z_{v}^{T}z_{u}\propto P(v|u)
zvTzu∝P(v∣u)给定图
G
=
(
V
,
E
)
G=(V,E)
G=(V,E),定义
N
R
(
u
)
N_{R}(u)
NR(u)表示用策略
R
R
R得到
u
u
u的邻居节点,目标是学习一个映射关系
z
:
u
→
R
d
z:u\rightarrow R^{d}
z:u→Rd,优化目标为:
m
a
x
∑
u
∈
V
l
o
g
P
(
N
R
(
u
)
∣
z
u
)
max\sum_{u\in V}log P(N_{R}(u)|z_{u})
maxu∈V∑logP(NR(u)∣zu)给定
u
u
u的embedding
z
u
z_{u}
zu,我们希望其邻居节点出现的概率最大,最终损失函数表示为:
L
=
−
∑
u
∈
V
∑
v
∈
N
R
(
u
)
l
o
g
P
(
v
∣
z
u
)
L=-\sum_{u\in V}\sum_{v\in N_{R}(u)}logP(v|z_{u})
L=−u∈V∑v∈NR(u)∑logP(v∣zu)
P
(
v
∣
z
u
)
=
e
x
p
(
z
u
T
z
v
)
∑
n
∈
V
e
x
p
(
z
u
T
z
n
)
P(v|z_{u})=\frac{exp(z_{u}^{T}z_{v})}{\sum_{n\in V}exp(z_{u}^{T}z_{n})}
P(v∣zu)=∑n∈Vexp(zuTzn)exp(zuTzv)随机游走的每一步都是无偏游走,即走到下一个邻居节点的概率都相同,游走的结果可能会只关注局部信息类似BFS(甚至两个节点来回跳),或者只关注最深的一条路类似DFS。为了优化游走的策略,Node2Vec做出改进,这里有两个参数:
- p p p用来控制返回上一个节点;
- q q q用来控制远离上一个节点;
- 参数的调整相当于是调整BFS或DFS的比例;
对于这个例子,假设已经穿过了边(S1,W)
走到节点W
,下一步的路径概率如下:
- 如果是返回原节点,则概率为 1 / p 1/p 1/p;
- 如果是远离原节点,则概率为 1 / q 1/q 1/q;
- 如果下一步节点和原节点距离与
(S1,W)
一样,则概率为1;
显然,如果我们想采用BFS,那么只需要调低 p p p的值,如果想采取DFS,只需要调低 q q q的值。这样游走的过程中,我们就可以自由的控制是想得到更多的局部信息还是全局信息。