生物医学网络科学Biomedical Network Science
Example04 / 09

与 ER 随机图和保度随机化零模型比较

所属专题
网络分析流程与 NetworkX 实践
下载
Notebook · .py

把《悲惨世界》网络(按无权图处理)与 (a) 同 N、M 的 ER 随机图、(b) 双边交换得到的保度随机化网络 各生成 10 次比较:计算平均聚集系数 C、平均最短路径 L、Louvain 模块度 Q 的均值与 z 分数, 并以 ER 为参照计算小世界系数 sigma = (C/C_rand)/(L/L_rand)。 解读:z 分数衡量真实值偏离零模型分布的程度。保度零模型更严格:它的平均 C 更接近真实值, 聚集系数的 z 随之变小;但 z 还取决于零分布的离散程度(如 Q),不宜跨零模型直接比较 z 的大小。 零模型网络若不连通,只在最大连通分支上计算指标。

Output输出图

与 ER 随机图和保度随机化零模型比较:输出图 1

Output文字输出

真实网络:      C = 0.573, L = 2.641, Q = 0.558
ER 零模型均值: C = 0.091, L = 2.487, Q = 0.333
保度零模型均值:C = 0.199, L = 2.522, Q = 0.278
z(ER)   C, L, Q = [48.5, 8.6, 18.8]
z(保度) C, L, Q = [17.9, 2.0, 33.2]
小世界系数 sigma = 5.92

Code代码

# 把《悲惨世界》网络(按无权图处理)与 (a) 同 N、M 的 ER 随机图、(b) 双边交换得到的保度随机化网络
# 各生成 10 次比较:计算平均聚集系数 C、平均最短路径 L、Louvain 模块度 Q 的均值与 z 分数,
# 并以 ER 为参照计算小世界系数 sigma = (C/C_rand)/(L/L_rand)。
# 解读:z 分数衡量真实值偏离零模型分布的程度。保度零模型更严格:它的平均 C 更接近真实值,
# 聚集系数的 z 随之变小;但 z 还取决于零分布的离散程度(如 Q),不宜跨零模型直接比较 z 的大小。
# 零模型网络若不连通,只在最大连通分支上计算指标。
import numpy as np
import networkx as nx

G = nx.Graph(nx.les_miserables_graph())
for u, v in G.edges():
    G[u][v].pop("weight", None)              # 去掉权重,做无权分析
N, M = G.number_of_nodes(), G.number_of_edges()

def lcc(H):
    return H.subgraph(max(nx.connected_components(H), key=len)).copy()

def measures(H, seed=0):
    H = lcc(H)
    Q = nx.community.modularity(H, nx.community.louvain_communities(H, seed=seed))
    return nx.average_clustering(H), nx.average_shortest_path_length(H), Q

real = measures(G)
er_list, ds_list = [], []
for s in range(10):
    er_list.append(measures(nx.gnm_random_graph(N, M, seed=s), seed=s))
    H = G.copy()
    nx.double_edge_swap(H, nswap=5 * M, max_tries=100 * M, seed=s)   # 保度随机化
    ds_list.append(measures(H, seed=s))
er, ds = np.array(er_list), np.array(ds_list)

z_er = (np.array(real) - er.mean(0)) / er.std(0)
z_ds = (np.array(real) - ds.mean(0)) / ds.std(0)
sigma = (real[0] / er[:, 0].mean()) / (real[1] / er[:, 1].mean())

print("真实网络:      C = %.3f, L = %.3f, Q = %.3f" % real)
print("ER 零模型均值: C = %.3f, L = %.3f, Q = %.3f" % tuple(er.mean(0)))
print("保度零模型均值:C = %.3f, L = %.3f, Q = %.3f" % tuple(ds.mean(0)))
print("z(ER)   C, L, Q =", np.round(z_er, 1).tolist())
print("z(保度) C, L, Q =", np.round(z_ds, 1).tolist())
print("小世界系数 sigma = %.2f" % sigma)

# 作图:每个指标的真实值与两种零模型的 10 次取值
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 3, figsize=(10, 3.6))
for j, (a, nm) in enumerate(zip(ax, ["clustering C", "path length L", "modularity Q"])):
    a.plot(np.zeros(10) + np.linspace(-0.1, 0.1, 10), er[:, j], "o", color="0.5", ms=4, label="ER")
    a.plot(np.ones(10) + np.linspace(-0.1, 0.1, 10), ds[:, j], "s", color="C0", ms=4, label="degree-preserving")
    a.axhline(real[j], color="C3", lw=2, label="observed")
    a.set_xticks([0, 1]); a.set_xticklabels(["ER", "deg.-pres."]); a.set_xlim(-0.5, 1.5); a.set_title(nm, fontsize=10)
ax[0].legend(fontsize=7)
fig.suptitle(f"Les Miserables vs null models (small-world sigma = {sigma:.2f})", fontsize=11)
plt.tight_layout(); plt.show()

Run在浏览器中运行

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

与 ER 随机图和保度随机化零模型比较