生物医学网络科学Biomedical Network Science
Example02 / 08

随机种子敏感性——社团划分的可重复程度

所属专题
研究问题、可复现分析与敏感性分析
下载
Notebook · .py

在 4 个大小不等、边界较模糊的模拟社团网络上,用 20 个随机种子运行 Louvain,记录社团数和模块度 Q, 并计算每个划分与种子 0 划分的调整兰德指数(ARI;1 表示完全一致,约 0 表示与随机划分相当)。 解读:Q 的波动通常很小,但社团数和具体划分可能变化;报告时应给出多次运行的范围或共识划分。

Output输出图

随机种子敏感性——社团划分的可重复程度:输出图 1

Output文字输出

社团数范围 4–5;Q 范围 0.377–0.423;与种子 0 的 ARI 范围 0.63–1.00

Code代码

# 在 4 个大小不等、边界较模糊的模拟社团网络上,用 20 个随机种子运行 Louvain,记录社团数和模块度 Q,
# 并计算每个划分与种子 0 划分的调整兰德指数(ARI;1 表示完全一致,约 0 表示与随机划分相当)。
# 解读:Q 的波动通常很小,但社团数和具体划分可能变化;报告时应给出多次运行的范围或共识划分。
import numpy as np
import networkx as nx

def ari(a, b):
    """调整兰德指数:两个标签数组的一致性。"""
    a = np.unique(a, return_inverse=True)[1]; b = np.unique(b, return_inverse=True)[1]
    M = np.zeros((a.max() + 1, b.max() + 1))
    np.add.at(M, (a, b), 1)
    c2 = lambda x: x * (x - 1) / 2
    s_ij, s_a, s_b, n2 = c2(M).sum(), c2(M.sum(1)).sum(), c2(M.sum(0)).sum(), c2(len(a))
    exp = s_a * s_b / n2
    return (s_ij - exp) / (0.5 * (s_a + s_b) - exp)

def labels_from(comms, n):
    lab = np.zeros(n, dtype=int)
    for i, c in enumerate(comms):
        lab[list(c)] = i
    return lab

G = nx.random_partition_graph([30, 25, 25, 20], 0.25, 0.04, seed=15)   # 模拟数据
n = G.number_of_nodes()
base = labels_from(nx.community.louvain_communities(G, seed=0), n)

res = []
for s in range(20):
    comms = nx.community.louvain_communities(G, seed=s)
    res.append((len(comms), nx.community.modularity(G, comms), ari(base, labels_from(comms, n))))
print(f"社团数范围 {min(r[0] for r in res)}–{max(r[0] for r in res)};"
      f"Q 范围 {min(r[1] for r in res):.3f}–{max(r[1] for r in res):.3f};"
      f"与种子 0 的 ARI 范围 {min(r[2] for r in res):.2f}–{max(r[2] for r in res):.2f}")

# 作图:种子 0 的划分(网络布局着色);20 个种子的社团数与 ARI
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 2, figsize=(10, 4))
pos = nx.spring_layout(G, seed=1)
nx.draw_networkx_edges(G, pos, ax=ax[0], edge_color="0.7", alpha=0.4, width=0.5)
nx.draw_networkx_nodes(G, pos, ax=ax[0], node_size=40, node_color=base, cmap="tab10", vmin=0, vmax=9)
ax[0].set_title("Louvain partition, seed 0", fontsize=10); ax[0].axis("off")
seeds = np.arange(20)
ax[1].plot(seeds, [r[2] for r in res], "o-", label="ARI vs seed 0")
ax[1].set_xlabel("random seed"); ax[1].set_ylabel("ARI"); ax[1].set_ylim(0, 1.05)
ax2 = ax[1].twinx()
ax2.plot(seeds, [r[0] for r in res], "s--", color="C1", label="number of communities")
ax2.set_ylabel("number of communities (orange)")
ax[1].set_title("Partitions vary across seeds while Q barely changes", fontsize=10)
plt.tight_layout(); plt.show()

Run在浏览器中运行

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

随机种子敏感性——社团划分的可重复程度