Example07 / 10
Bianconi–Barabási 适应度模型——后来者居上
每个节点带适应度 η(均匀分布于 [0,1]),新节点连向 i 的概率 ∝ η_i k_i。 模拟 N=20000、m=2 的网络;在 t=1000 时人为插入一个 η=1 的“后来者”,追踪它与最早一批节点的度。 再按适应度分组,用 ln k_i 对 ln(t/t_i) 回归估计动态指数 β(η),与理论 β(η)=η/C(均匀分布 C≈1.255)比较。 输出:t=1000 才加入的高适应度节点,度数很快超过最早的节点;β(η) 随 η 近似线性增长, 数值比理论 η/1.255 低约 5–10%(有限时间与初始度的影响),但线性关系清楚。
Output输出图

Output文字输出
t= 4000: 节点0(η=0.09) k= 2, 节点1(η=0.24) k= 20, 后来者(η=1, t_i=1000) k= 21 t= 8000: 节点0(η=0.09) k= 2, 节点1(η=0.24) k= 23, 后来者(η=1, t_i=1000) k= 34 t=12000: 节点0(η=0.09) k= 2, 节点1(η=0.24) k= 29, 后来者(η=1, t_i=1000) k= 51 t=16000: 节点0(η=0.09) k= 2, 节点1(η=0.24) k= 30, 后来者(η=1, t_i=1000) k= 66 t=19999: 节点0(η=0.09) k= 2, 节点1(η=0.24) k= 32, 后来者(η=1, t_i=1000) k= 79 η∈[0.2,0.4): β 估计=0.220, 理论 η_mid/1.255=0.239 η∈[0.4,0.6): β 估计=0.362, 理论 η_mid/1.255=0.398 η∈[0.6,0.8): β 估计=0.509, 理论 η_mid/1.255=0.558 η∈[0.8,1.0): β 估计=0.674, 理论 η_mid/1.255=0.717
Code代码
# 每个节点带适应度 η(均匀分布于 [0,1]),新节点连向 i 的概率 ∝ η_i k_i。
# 模拟 N=20000、m=2 的网络;在 t=1000 时人为插入一个 η=1 的“后来者”,追踪它与最早一批节点的度。
# 再按适应度分组,用 ln k_i 对 ln(t/t_i) 回归估计动态指数 β(η),与理论 β(η)=η/C*(均匀分布 C*≈1.255)比较。
# 输出:t=1000 才加入的高适应度节点,度数很快超过最早的节点;β(η) 随 η 近似线性增长,
# 数值比理论 η/1.255 低约 5–10%(有限时间与初始度的影响),但线性关系清楚。
import numpy as np
rng = np.random.default_rng(3)
N, m, t_late = 20000, 2, 1000
eta = rng.random(N)
eta[t_late] = 1.0
deg = np.zeros(N)
deg[: m + 1] = m
track = {0: [], 1: [], t_late: []}
for t in range(m + 1, N):
w = eta[:t] * deg[:t]
targets = rng.choice(t, size=m, replace=False, p=w / w.sum())
deg[targets] += 1
deg[t] = m
if t % 200 == 0: # 记录轨迹用于作图
for i in track:
track[i].append((t, deg[i]))
if t % 4000 == 0 or t == N - 1:
print("t=%5d: 节点0(η=%.2f) k=%4d, 节点1(η=%.2f) k=%4d, 后来者(η=1, t_i=%d) k=%4d"
% (t, eta[0], deg[0], eta[1], deg[1], t_late, deg[t_late]))
# 估计 β(η):对每个适应度区间,回归 ln(k_i/m) ~ β ln(N/t_i),只用 t_i 足够早的节点
ti = np.arange(N)
ok = (ti > 10) & (ti < N // 5)
betas = []
for lo in np.arange(0.2, 1.0, 0.2):
sel = ok & (eta >= lo) & (eta < lo + 0.2)
x, y = np.log(N / ti[sel]), np.log(deg[sel] / m)
beta = (x * y).sum() / (x * x).sum() # 过原点回归
print("η∈[%.1f,%.1f): β 估计=%.3f, 理论 η_mid/1.255=%.3f" % (lo, lo + 0.2, beta, (lo + 0.1) / 1.255))
betas.append((lo + 0.1, beta))
# 作图:左为度随时间的增长轨迹(双对数);右为 β(η) 与理论直线
import matplotlib.pyplot as plt
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
for i, ls, lab in [(0, "-", "node 0 (eta = %.2f)" % eta[0]), (1, "--", "node 1 (eta = %.2f)" % eta[1]),
(t_late, "-", "latecomer t_i = %d (eta = 1)" % t_late)]:
tt, kk = zip(*[(t, k) for t, k in track[i] if t > i])
ax1.loglog(tt, kk, ls, lw=2, label=lab)
ax1.set_xlabel("time t"); ax1.set_ylabel("degree k_i(t)"); ax1.legend(fontsize=8)
ax1.set_title("The fittest latecomer overtakes early nodes", fontsize=10)
em, bt = zip(*betas)
ax2.plot(em, bt, "o", ms=8, label="estimated beta")
ax2.plot([0, 1], [0, 1 / 1.255], "--", color="0.4", label="theory eta / 1.255")
ax2.set_xlabel("fitness eta (bin centre)"); ax2.set_ylabel("dynamic exponent beta"); ax2.legend(fontsize=8)
ax2.set_title("beta grows linearly with fitness", fontsize=10)
plt.tight_layout(); plt.show()Run在浏览器中运行
首次加载 Python 环境约需 20–40 秒;可以修改参数后重新运行。