4. 节点相似性特征:共同邻居、Jaccard系数、Adamic-Adar指数、资源分配指数
图数据里最基础也最实用的特征,就是节点相似性。
说白了,就是判断两个节点“像不像”。
我刚开始做图算法时,觉得这玩意儿太简单了。后来发现,相似性特征做得好,模型效果能直接提升5-10个点。今天咱们就把这四种经典方法掰开揉碎了讲。
4.1 共同邻居(Common Neighbors)
这是最直观的思路。
两个节点共享的邻居越多,它们就越可能相似。比如在社交网络里,你和某个人有10个共同好友,那你们大概率认识。
数学定义:
CN(u, v) = |N(u) ∩ N(v)|
其中 N(u) 表示节点 u 的邻居集合。
我个人的习惯:在稀疏图上,共同邻居往往比复杂指标更稳定。我曾经在一个电商推荐项目里,只用共同邻居就干掉了好几个花里胡哨的模型。
代码实现:
import networkx as nx
def common_neighbors(G, u, v):
return len(list(nx.common_neighbors(G, u, v)))
小技巧:如果图特别大,可以先用度数过滤一下。只计算度数大于阈值的节点对,能省不少时间。
4.2 Jaccard系数
共同邻居有个问题:它没考虑节点本身的度数。
你想想看,一个超级大V有1000个好友,你和他的共同邻居有50个。另一个普通用户只有100个好友,你和他的共同邻居也是50个。这两个50能一样吗?
Jaccard系数就是来解决这个问题的。
数学定义:
Jaccard(u, v) = |N(u) ∩ N(v)| / |N(u) ∪ N(v)|
说白了,就是共同邻居占所有邻居的比例。
我曾经踩过的坑:在计算Jaccard时,如果两个节点没有邻居,分母为0。一定要加个平滑处理,比如加1或者直接返回0。
代码实现:
def jaccard_coefficient(G, u, v):
neighbors_u = set(G.neighbors(u))
neighbors_v = set(G.neighbors(v))
intersection = len(neighbors_u & neighbors_v)
union = len(neighbors_u | neighbors_v)
if union == 0:
return 0.0
return intersection / union
4.3 Adamic-Adar指数
这个指标很有意思。它给每个共同邻居加了个权重——度数越低的邻居,权重越高。
为什么?因为你和某个冷门用户有共同好友,比你和大众网红有共同好友,更能说明问题。
数学定义:
AA(u, v) = Σ [1 / log(|N(w)|)] (w ∈ N(u) ∩ N(v))
每个共同邻居 w 的贡献是 1/log(度数)。度数越大,贡献越小。
我建议:在链路预测任务中,Adamic-Adar通常比Jaccard表现更好。我做过一个论文合作网络的项目,AA指数比Jaccard的AUC高了将近3个点。
代码实现:
import math
def adamic_adar(G, u, v):
common = list(nx.common_neighbors(G, u, v))
if not common:
return 0.0
score = 0.0
for w in common:
degree = G.degree(w)
if degree > 1:
score += 1.0 / math.log(degree)
return score
注意:log里的度数如果为1,分母为0。我一般会加个判断,度数为1的节点直接跳过。
4.4 资源分配指数(Resource Allocation Index)
这个指标和Adamic-Adar很像,但更激进。
它把每个共同邻居看作一个资源分配器。度数越高,分配能力越弱。公式里直接用 1/度数,而不是 1/log(度数)。
数学定义:
RA(u, v) = Σ [1 / |N(w)|] (w ∈ N(u) ∩ N(v))
说白了,就是对高度数节点的惩罚更狠。
代码实现:
def resource_allocation(G, u, v):
common = list(nx.common_neighbors(G, u, v))
if not common:
return 0.0
score = 0.0
for w in common:
degree = G.degree(w)
if degree > 0:
score += 1.0 / degree
return score
4.5 四种方法对比
| 指标 | 核心思想 | 是否考虑度数 | 适用场景 |
|---|---|---|---|
| 共同邻居 | 邻居交集大小 | 否 | 稠密图、快速筛选 |
| Jaccard系数 | 交集占并集比例 | 是(归一化) | 度数差异大的图 |
| Adamic-Adar | 对数惩罚高度数节点 | 是(对数惩罚) | 社交网络、论文合作 |
| 资源分配 | 线性惩罚高度数节点 | 是(线性惩罚) | 稀疏图、极端度数分布 |
我的经验:实际项目中,我通常会把这四个指标都算出来,作为特征一起喂给模型。有时候模型自己会学到哪个指标更重要。别偷懒,全上就对了。
4.6 知识体系图
下面这张图展示了四种相似性指标的核心逻辑和关系:
从这张图可以看得很清楚:四种方法一脉相承。从最简单的共同邻居开始,逐步加入对节点度数的考量,惩罚力度也越来越大。
选型建议:
- 图很稠密?用共同邻居或Jaccard,速度快
- 图很稀疏?用资源分配,对高度数节点惩罚更狠
- 不确定?四个全算,让模型自己选
嗯,这四种相似性特征就讲完了。别看公式简单,实际项目里它们往往是最稳定、最解释性强的特征。我每次做图项目,都会先把这四个特征跑一遍,看看效果再说。