生物医学网络科学Biomedical Network Science
Example07 / 15

用 Brandes 算法手工计算介数中心性

所属专题
网络结构指标与随机图
下载
Notebook · .py

Brandes(2001):对每个源点 s 做一次 BFS,记录最短路径条数 σ_sv 与前驱;再按距离从远到近回溯, 累加依赖度 δ_s(v) = Σ_{w: v 是 w 的前驱} σ_sv/σ_sw · (1 + δ_s(w))。总代价 O(NM)。 无向图中每对节点被两个源点各计一次,最后除以 2。输出:与 nx.betweenness_centrality 完全一致。

Output输出图

用 Brandes 算法手工计算介数中心性:输出图 1

Output文字输出

与 NetworkX 最大差异 = 1.42e-14
介数最大的 3 个节点: [0, 33, 32] [231.1, 160.6, 76.7]

Code代码

# Brandes(2001):对每个源点 s 做一次 BFS,记录最短路径条数 σ_sv 与前驱;再按距离从远到近回溯,
# 累加依赖度 δ_s(v) = Σ_{w: v 是 w 的前驱} σ_sv/σ_sw · (1 + δ_s(w))。总代价 O(NM)。
# 无向图中每对节点被两个源点各计一次,最后除以 2。输出:与 nx.betweenness_centrality 完全一致。
import networkx as nx
from collections import deque


def brandes_betweenness(G):
    bc = dict.fromkeys(G, 0.0)
    for s in G:
        stack, pred = [], {v: [] for v in G}
        sigma = dict.fromkeys(G, 0); sigma[s] = 1
        dist = dict.fromkeys(G, -1); dist[s] = 0
        Q = deque([s])
        while Q:                                   # 阶段 1:BFS 计数最短路径
            v = Q.popleft(); stack.append(v)
            for w in G.neighbors(v):
                if dist[w] < 0:
                    dist[w] = dist[v] + 1; Q.append(w)
                if dist[w] == dist[v] + 1:
                    sigma[w] += sigma[v]; pred[w].append(v)
        delta = dict.fromkeys(G, 0.0)
        while stack:                               # 阶段 2:反向累加依赖度
            w = stack.pop()
            for v in pred[w]:
                delta[v] += sigma[v] / sigma[w] * (1 + delta[w])
            if w != s:
                bc[w] += delta[w]
    return {v: b / 2 for v, b in bc.items()}      # 无向图去重


G = nx.karate_club_graph()
mine = brandes_betweenness(G)
ref = nx.betweenness_centrality(G, normalized=False)
print("与 NetworkX 最大差异 = %.2e" % max(abs(mine[v] - ref[v]) for v in G))
print("介数最大的 3 个节点:", sorted(mine, key=mine.get, reverse=True)[:3],
      [round(mine[v], 1) for v in sorted(mine, key=mine.get, reverse=True)[:3]])

# 作图:节点大小与颜色 ∝ Brandes 介数,标出介数最大的 3 个节点
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(6.4, 4.2))
pos = nx.spring_layout(G, seed=4)
bvals = [mine[v] for v in G]
nx.draw_networkx_edges(G, pos, ax=ax, edge_color="0.7", alpha=0.4)
nc = nx.draw_networkx_nodes(G, pos, ax=ax, node_size=[40 + 0.6 * b for b in bvals], node_color=bvals,
                            cmap="YlOrRd", edgecolors="0.4", linewidths=0.5)
top3 = sorted(mine, key=mine.get, reverse=True)[:3]
nx.draw_networkx_labels(G, pos, ax=ax, labels={v: str(v) for v in top3}, font_size=9)
fig.colorbar(nc, ax=ax, label="betweenness (unnormalized)")
ax.set_title("Brandes betweenness = NetworkX (max diff %.1e)" % max(abs(mine[v] - ref[v]) for v in G), fontsize=10)
ax.axis("off"); plt.tight_layout(); plt.show()

Run在浏览器中运行

首次加载 Python 环境约需 20–40 秒;可以修改参数后重新运行。

用 Brandes 算法手工计算介数中心性