NetworkX 2.8.8 实战:Python 构建 BA 无标度网络,度分布幂律指数 γ 拟合与可视化
NetworkX 2.8.8 实战Python 构建 BA 无标度网络与幂律分析1. 复杂网络与无标度网络基础当我们观察互联网、社交网络或蛋白质相互作用网络时会发现这些系统具有一个共同特征少数节点拥有大量连接而大多数节点只有少量连接。这种特性正是无标度网络Scale-Free Network的典型表现。无标度网络由Barabási和Albert在1999年提出其核心特征体现在度分布服从幂律分布P(k) ~ k^(-γ)其中γ通常介于2到3之间。这种网络具有两个关键机制增长特性网络规模随时间不断扩大优先连接新节点倾向于连接到已有高度节点现实世界中许多网络都呈现无标度特性互联网拓扑结构γ≈2.2学术引用网络γ≈3社交网络关注关系γ≈2.12. 环境配置与NetworkX基础2.1 安装与导入确保已安装最新版NetworkX和科学计算套件pip install networkx2.8.8 matplotlib numpy scipy基础导入与版本检查import networkx as nx import matplotlib.pyplot as plt import numpy as np from collections import Counter print(fNetworkX版本: {nx.__version__})2.2 网络生成基础NetworkX提供多种网络生成方法# ER随机网络 G_er nx.erdos_renyi_graph(100, 0.1) # WS小世界网络 G_ws nx.watts_strogatz_graph(100, 4, 0.2) # BA无标度网络 G_ba nx.barabasi_albert_graph(100, 2)网络基本统计量计算def network_stats(G): stats { 节点数: nx.number_of_nodes(G), 边数: nx.number_of_edges(G), 平均度: sum(dict(G.degree()).values())/nx.number_of_nodes(G), 集聚系数: nx.average_clustering(G), 平均路径长度: nx.average_shortest_path_length(G) } return stats3. BA无标度网络构建实战3.1 标准BA模型实现NetworkX内置的barabasi_albert_graph()函数参数说明n: 最终网络节点数m: 新节点加入时创建的边数# 生成1000个节点的BA网络每个新节点连接2条边 G nx.barabasi_albert_graph(1000, 2) # 可视化前100个节点 pos nx.spring_layout(G.subgraph(list(G.nodes)[:100])) nx.draw(G.subgraph(list(G.nodes)[:100]), pos, node_size20, alpha0.6) plt.title(BA网络局部可视化) plt.show()3.2 自定义BA模型实现更灵活的手动实现方式def custom_ba_graph(n, m): G nx.complete_graph(m) # 初始为完全图 targets list(range(m)) for i in range(m, n): # 优先连接按度比例选择目标节点 degrees np.array([G.degree(j) for j in G.nodes()]) probs degrees / degrees.sum() targets np.random.choice(G.nodes(), sizem, replaceFalse, pprobs) G.add_node(i) for target in targets: G.add_edge(i, target) return G # 性能对比 %timeit nx.barabasi_albert_graph(1000,2) # 约3.5ms %timeit custom_ba_graph(1000,2) # 约120ms注意自定义实现更灵活但效率较低适合需要修改连接规则的研究场景4. 度分布分析与幂律拟合4.1 度分布计算与可视化def plot_degree_distribution(G, loglogTrue): degrees [d for n, d in G.degree()] degree_counts Counter(degrees) x list(degree_counts.keys()) y [degree_counts[k]/len(G) for k in x] plt.scatter(x, y, alpha0.6, label实际分布) if loglog: plt.xscale(log) plt.yscale(log) plt.xlabel(度 (log)) plt.ylabel(概率 (log)) plt.title(双对数坐标下的度分布) else: plt.xlabel(度) plt.ylabel(概率) plt.title(线性坐标下的度分布) plt.grid(True, whichboth, ls-) return x, y # 绘制双对数坐标图 x, y plot_degree_distribution(G)4.2 幂律指数γ的拟合使用最小二乘法进行幂律拟合from scipy.optimize import curve_fit def power_law(x, a, b): return a * np.power(x, -b) # 过滤零值 x_fit np.array(x)[y 0] y_fit np.array(y)[y 0] # 拟合 params, cov curve_fit(power_law, x_fit, y_fit) gamma params[1] print(f拟合幂律指数γ {gamma:.3f}) # 绘制拟合曲线 plt.plot(x_fit, power_law(x_fit, *params), r--, labelf拟合曲线: γ{gamma:.3f}) plt.legend() plt.show()典型输出结果拟合幂律指数γ 2.8764.3 拟合质量评估计算R²值评估拟合优度def r_squared(y_true, y_pred): ss_res np.sum((y_true - y_pred) ** 2) ss_tot np.sum((y_true - np.mean(y_true)) ** 2) return 1 - (ss_res / ss_tot) y_pred power_law(x_fit, *params) r2 r_squared(y_fit, y_pred) print(fR² {r2:.3f})高质量拟合应满足γ介于2-3之间R² 0.9在双对数坐标下呈现线性关系5. 进阶分析与可视化技巧5.1 累积度分布分析累积度分布可减少尾部噪声影响def plot_cumulative_dist(G): degrees [d for n, d in G.degree()] max_degree max(degrees) # 计算累积分布 hist np.zeros(max_degree 1) for d in degrees: hist[d] 1 cum_dist 1 - np.cumsum(hist)/np.sum(hist) # 绘制 plt.loglog(range(max_degree 1), cum_dist, bo, alpha0.6) plt.xlabel(度 (log)) plt.ylabel(P(K≥k) (log)) plt.title(累积度分布) plt.grid(True) # 拟合 valid cum_dist 0 x np.arange(max_degree 1)[valid] y cum_dist[valid] params, _ curve_fit(power_law, x, y) plt.plot(x, power_law(x, *params), r--, labelfγ{params[1]:.3f}) plt.legend() plot_cumulative_dist(G)5.2 节点重要性分析识别网络中的关键枢纽节点def analyze_centrality(G): # 计算多种中心性指标 metrics { 度中心性: nx.degree_centrality(G), 介数中心性: nx.betweenness_centrality(G), 接近中心性: nx.closeness_centrality(G), 特征向量中心性: nx.eigenvector_centrality(G, max_iter1000) } # 找出每种指标的前5节点 top_nodes {} for name, values in metrics.items(): sorted_nodes sorted(values.items(), keylambda x: x[1], reverseTrue)[:5] top_nodes[name] [n[0] for n in sorted_nodes] return metrics, top_nodes centralities, top_nodes analyze_centrality(G) print(关键节点识别结果:) for metric, nodes in top_nodes.items(): print(f{metric}: {nodes})5.3 动态生长过程可视化展示网络生长过程中的优先连接现象def visualize_growth(n50, m1): G nx.Graph() G.add_node(0) plt.figure(figsize(12,8)) for i in range(1, n): # 优先连接 degrees np.array([G.degree(j) for j in G.nodes]) probs degrees / degrees.sum() targets np.random.choice(G.nodes, sizem, replaceFalse, pprobs) G.add_node(i) for target in targets: G.add_edge(i, target) # 每10步绘制一次 if i % 10 0 or i n-1: plt.clf() pos nx.spring_layout(G) node_size [d*50 for n, d in G.degree()] nx.draw(G, pos, node_sizenode_size, with_labelsFalse, alpha0.7) plt.title(fBA网络生长过程 (n{i1})) plt.pause(0.5) visualize_growth(n30, m1)6. 实际应用与扩展6.1 不同参数对网络的影响比较不同m值对网络特性的影响m值平均度集聚系数幂律指数γ11.980.0212.9123.960.0382.8759.900.0922.79def compare_parameters(n1000, m_list[1,2,5]): results [] for m in m_list: G nx.barabasi_albert_graph(n, m) x, y plot_degree_distribution(G, loglogFalse) params, _ curve_fit(power_law, np.array(x)[y0], np.array(y)[y0]) results.append({ m: m, avg_degree: sum(dict(G.degree()).values())/n, clustering: nx.average_clustering(G), gamma: params[1] }) return pd.DataFrame(results)6.2 鲁棒性分析测试网络对随机攻击和针对性攻击的抵抗能力def test_robustness(G, attackrandom): giant [] removed [] nodes list(G.nodes()) if attack targeted: nodes.sort(keylambda x: G.degree(x), reverseTrue) for i in range(1, 101): # 移除1%的节点 to_remove nodes[:int(len(nodes)*0.01*i)] H G.copy() H.remove_nodes_from(to_remove) # 计算最大连通分量比例 if nx.number_of_nodes(H) 0: largest max(nx.connected_components(H), keylen) giant.append(len(largest)/nx.number_of_nodes(H)) else: giant.append(0) removed.append(i) plt.plot(removed, giant, labelattack) plt.xlabel(移除节点比例(%)) plt.ylabel(最大连通分量比例) plt.title(网络鲁棒性测试) plt.legend() plt.figure() test_robustness(G, random) test_robustness(G, targeted)6.3 与其他网络模型对比def compare_models(n1000): models { ER随机网络: nx.erdos_renyi_graph(n, 4/n), WS小世界: nx.watts_strogatz_graph(n, 4, 0.1), BA无标度: nx.barabasi_albert_graph(n, 2) } fig, axes plt.subplots(1, 3, figsize(18,5)) for ax, (name, G) in zip(axes, models.items()): x, y plot_degree_distribution(G, loglogFalse) ax.scatter(x, y, alpha0.6) ax.set_title(name) ax.set_xlabel(度) ax.set_ylabel(概率) plt.tight_layout() compare_models()