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

k_nn(k)、相关指数 mu、r 与 Spearman rho——三类网络对照

所属专题
度相关性与网络结构的高阶统计
下载
Notebook · .py

从同一个度序列(BA 模型,N=3000, m=2)出发,用 Xulvi-Brunet–Sokolov 重连得到同配版与异配版。 重连只交换边的端点,所以三张网络的度序列完全相同,差别只在“谁连谁”。 对每张网络:对数分箱计算 k_nn(k),在双对数坐标下拟合 k_nn ~ k^mu;同时报告 r 与边两端度的 Spearman rho。 解读:mu、r、rho 的符号一致;同配版在高 k 处 k_nn 走平甚至下降,这是结构截断的痕迹。

Output输出图

k_nn(k)、相关指数 mu、r 与 Spearman rho——三类网络对照:输出图 1

Output文字输出

BA 原始: r = -0.081   Spearman rho = -0.299   拟合 mu = -0.15
同配重连: r = +0.519   Spearman rho = +0.986   拟合 mu = +0.88
异配重连: r = -0.274   Spearman rho = -0.956   拟合 mu = -0.65
图已保存为 knn_three_networks.png

Code代码

# 从同一个度序列(BA 模型,N=3000, m=2)出发,用 Xulvi-Brunet–Sokolov 重连得到同配版与异配版。
# 重连只交换边的端点,所以三张网络的度序列完全相同,差别只在“谁连谁”。
# 对每张网络:对数分箱计算 k_nn(k),在双对数坐标下拟合 k_nn ~ k^mu;同时报告 r 与边两端度的 Spearman rho。
# 解读:mu、r、rho 的符号一致;同配版在高 k 处 k_nn 走平甚至下降,这是结构截断的痕迹。
import numpy as np
import networkx as nx
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from scipy.stats import spearmanr

plt.rcParams["font.sans-serif"] = ["PingFang SC", "Microsoft YaHei", "SimHei", "Noto Sans CJK SC", "DejaVu Sans"]
plt.rcParams["axes.unicode_minus"] = False


def xbs_rewire(G, n_swaps, mode, p=1.0, seed=0):
    """Xulvi-Brunet & Sokolov 重连:随机取两条边,把四个端点按度排序后,
    以概率 p 按 mode 确定性配对(assortative: 大配大、小配小;disassortative: 大配小),
    以概率 1-p 随机配对。拒绝产生自环或重边的交换,因此保持简单图与度序列。"""
    rng = np.random.default_rng(seed)
    G = G.copy()
    deg = dict(G.degree())
    edges = list(G.edges())
    done = 0
    while done < n_swaps:
        i, j = rng.choice(len(edges), 2, replace=False)
        (a, b), (c, d) = edges[i], edges[j]
        nodes = [a, b, c, d]
        if len(set(nodes)) < 4:
            continue
        if rng.random() < p:
            s = sorted(nodes, key=lambda x: deg[x], reverse=True)
            new = [(s[0], s[1]), (s[2], s[3])] if mode == "assortative" else [(s[0], s[3]), (s[1], s[2])]
        else:
            rng.shuffle(nodes)
            new = [(nodes[0], nodes[1]), (nodes[2], nodes[3])]
        if any(G.has_edge(*e) for e in new):
            continue
        G.remove_edges_from([(a, b), (c, d)])
        G.add_edges_from(new)
        edges[i], edges[j] = new
        done += 1
    return G


def knn_logbinned(G, n_bins=12):
    deg = dict(G.degree())
    knn_i = nx.average_neighbor_degree(G)
    k = np.array([deg[i] for i in G], float)
    kn = np.array([knn_i[i] for i in G], float)
    bins = np.unique(np.round(np.logspace(0, np.log10(k.max() + 1), n_bins)))
    kc, kv = [], []
    for lo, hi in zip(bins[:-1], bins[1:]):
        sel = (k >= lo) & (k < hi)
        if sel.sum() >= 3:
            kc.append(k[sel].mean())
            kv.append(kn[sel].mean())
    return np.array(kc), np.array(kv)


def edge_spearman(G):
    deg = dict(G.degree())
    x = [deg[u] for u, v in G.edges()] + [deg[v] for u, v in G.edges()]
    y = [deg[v] for u, v in G.edges()] + [deg[u] for u, v in G.edges()]
    return spearmanr(x, y)[0]


G0 = nx.barabasi_albert_graph(3000, 2, seed=3)
M = G0.number_of_edges()
nets = {
    "BA 原始": G0,
    "同配重连": xbs_rewire(G0, 3 * M, "assortative", p=1.0, seed=1),
    "异配重连": xbs_rewire(G0, 3 * M, "disassortative", p=1.0, seed=2),
}
fig, ax = plt.subplots(figsize=(5, 4))
for name, G in nets.items():
    assert sorted(d for _, d in G.degree()) == sorted(d for _, d in G0.degree())
    kc, kv = knn_logbinned(G)
    mu = np.polyfit(np.log(kc), np.log(kv), 1)[0]
    r = nx.degree_assortativity_coefficient(G)
    rho = edge_spearman(G)
    print(f"{name}: r = {r:+.3f}   Spearman rho = {rho:+.3f}   拟合 mu = {mu:+.2f}")
    ax.loglog(kc, kv, "o-", label=f"{name} (r={r:+.2f})")
k = np.array([d for _, d in G0.degree()], float)
ax.axhline((k**2).mean() / k.mean(), color="gray", ls="--", label="中性预测 <k²>/<k>")
ax.set_xlabel("度 k")
ax.set_ylabel("k_nn(k)")
ax.legend(fontsize=8)
fig.tight_layout()
fig.savefig("knn_three_networks.png", dpi=120)
print("图已保存为 knn_three_networks.png")

Run在浏览器中运行

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

k_nn(k)、相关指数 mu、r 与 Spearman rho——三类网络对照