目录
- 0 简介
- 1 效果展示——树状网络
- 2 效果展示——小世界网络
- 3 代码
- 3.1 创建网络:树状网络
- 3.2 创建网络:小世界网络
- 3.3 创建网络:随机网络
- 3.4 创建网络:补充说明
- 3.5 在随机位置生成初始感染节点
- 3.6 传染
- 3.7 可视化
- 4 执行
- 4.1 创建小世界网络
- 4.2 创建树状网络
- 4.3 传播模拟可视化
- 5 后记
0 简介
本博文代码的思路是:
1、假设某个(某些)在网络中的节点有某种传染病
2、传染病会根据一定的传播概率传播给与被感染的节点直接相邻(连接)的其他节点
然后,要把这个传播的过程用图片的形式呈现出来,并且记录下每次迭代的感染数据。
顺便一提,本文基于SI模型,如果需要SIR模型还是SIS还是SIER模型的可以自己改进。
1 效果展示——树状网络
照例,先来一波效果展示。
在可视化中红色是已被感染的节点,绿色是健康节点。
这里我先展示一下3个分支5层的树状网络的效果,为了快点模拟完成,设置传染率0.5,初始感染节点为3个。
初始状态(第0次迭代):
第1次迭代:
第2次迭代:
……
第12次迭代:
……
第16次迭代:
……
第22次迭代(最后一个节点还蛮顽强的):
在出图片的同时,终端还输出了每次的感染情况:
2 效果展示——小世界网络
可能一个类型的网络看得还不太清楚,所以我再展示一下小世界网络的传播情况。
这是一个有80个节点的小世界网络,初始邻居数是4,断线重连概率是0.2。设置传染率0.5,初始感染节点为3个。
初始状态(第0次迭代):
第1次迭代:
第2次迭代:
……
第5次迭代:
第6次迭代:
第7次迭代:
第8次迭代:
第9次迭代:
终端输出的每次迭代的感染情况:
3 代码
好的,现在步入正题。
首先调用需要的包。
import numpy as np
import random
import copy
import matplotlib.pyplot as plt
import networkx as nx
然后再写几个生成不同形态的网络的函数。本博文提供了树状网络,小世界网络和随机网络。
3.1 创建网络:树状网络
def tree(Branch,Grade): #树状网络 #Branch为节点向下分支,Grade为层数 #树状网络无需预先创建网络模型(网络关系矩阵)
####创建树状网络初始网络模型(网络关系矩阵)(创捷节点)####
Nodes = 0
for power in range(Grade):
Add_Nodes = Branch**power
Nodes = Nodes + Add_Nodes
Zero = []
a = np.zeros(Nodes,int)
for i in range(Nodes):
Zero.append(a)
Zero = np.array(Zero)
###########构建树状网络关系(连结各节点)##############
C = copy.deepcopy(Zero)
Nodes = len(C)
Search = 0
Start = 0
End = 1
for g in range(1,Grade): #因为一层树无意义
LastCount = Branch**(g-1) #上一层树有LastCount个节点一这层连结
Count = Branch**g #这层树有Count个节点与上一层连结
LastNode = range(Start,End) #上一层树在网络关系矩阵的位置
Start = End #这层树的起始与终止位置
End = Start + Count
ThisNode = range(Start,End) #这层数在网络关系矩阵的位置
Cursor = Start
for n in LastNode:
for t in range(Cursor,(Cursor+Branch)): #该层树与上一层树创建双向连结关系,游标Cursor指向该层树
C[t][n] = 1
C[n][t] = 1
Cursor = Cursor + Branch #游标Cursor切换
return C
3.2 创建网络:小世界网络
def small_world(Nodes,Neighour,Alpha): #小世界网络 #Nodes为节点数,neighour为初始邻居数,Alhpa为按照watts-strogatz法断线重连概率
####创建树状网络初始网络模型(网络关系矩阵)(创捷节点)####
Zero = []
a = np.zeros(Nodes,int)
for i in range(Nodes):
Zero.append(a)
Zero = np.array(Zero)
###########构建网络关系(连结各节点)##############
C = copy.deepcopy(Zero)
Nodes = len(C) #节点数
for a in range(Nodes): #先按正常连接
Add_time = 0
while Add_time < (Neighour/2):
C[a][a-(Add_time+1)] = 1
C[a-(Add_time+1)][a] = 1
Add_time += 1
##################断线重连部分###################
for r in range(Nodes): #读取各节点
Add_time = 0
while Add_time < (Neighour/2):
if C[r][r-(Add_time+1)] == 1: #若存在连线,根据所填概率询问是否重连
if random.random() < Alpha: #若生成的随机数小于Alpha则重连
C[r][r-(Add_time+1)] = 0 #清除现有连线
C[r-(Add_time+1)][r] = 0
Ob = random.randint(0,(Nodes-1))#新建连结对象
while C[r][Ob] == 1 or Ob == r: #两点之间不能存在多个连结,并且新建的连结对象不能是自身
Ob = random.randint(0,(Nodes-1))
C[r][Ob] = 1 #连结
C[Ob][r] = 1
Add_time += 1
return C #返回一个连结属性矩阵,1为连结,0为无连结
3.3 创建网络:随机网络
def random_network(Nodes,Linker): #随机网络
####创建树状网络初始网络模型(网络关系矩阵)(创捷节点)####
Zero = []
a = np.zeros(Nodes,int)
for i in range(Nodes):
Zero.append(a)
Zero = np.array(Zero)
###########构建网络关系(连结各节点)##############
C = copy.deepcopy(Zero)
Nodes = len(C) #节点数
for a in range(Linker):
target1 = random.randint(0,Nodes-1) #随机抓取两个节点
target2 = random.randint(0,Nodes-1)
while C[target1][target2] == 1 or target1 == target2:
target1 = random.randint(0,Nodes-1)
target2 = random.randint(0,Nodes-1)
C[target1][target2] = 1
C[target2][target1] = 1
return C #返回一个连结属性矩阵,1为连结,0为无连结
3.4 创建网络:补充说明
补充一下,本博文的网络构建采用矩阵的方式构建,我随手print一个10节点邻居为2重连率为0.2的小世界网络:
接下来还有3个关于传播和可视化的函数。
3.5 在随机位置生成初始感染节点
def catastrophe(Nodes,Amount): #设置初始感染者数量,在随机位置生成
a = range(Nodes)
Infecters = random.sample(a,Amount)
InfectStatus = np.zeros(Nodes,int) #感染状态表
for i in Infecters:
InfectStatus[i] = 1 #感染者登记为1
return InfectStatus #返回一个感染者编号列表
3.6 传染
def infect(Connections,InfectStatus,Beta): #传染模型 Connections为节点连结关系属性矩阵,Infecters为初始感染者,Beta为感染率
Status1 = copy.deepcopy(InfectStatus) #前一状态感染者列表
Status2 = copy.deepcopy(InfectStatus) #当前状态待更新感染者列表
C = copy.deepcopy(Connections)
Nodes = len(C)
if sum(InfectStatus) < Nodes/2: #当感染节点数小于总数的一半时
for i in range(len(Status1)): #遍历所有节点,发现感染者
if Status1[i] == 1: #若状态为1,即为感染
for j in range(len(C[i])):
if Status1[j] == 0 and C[i][j] == 1: #若连结关系为1,即为连结
if random.random() <= Beta: #若生成的随机数小于Beta则登记为感染
Status2[j] = 1 #i感染j
else:
for a in range(len(Status1)):
if Status1[a] == 0:
for b in range(len(C[a])):
if Status1[b] == 1 and C[a][b] == 1:
if random.random() <= Beta:
Status2[a] = 1
return Status2 #返回新的感染者列表
3.7 可视化
def show_iteration(Connections,Amount,Beta): #传染病迭代输出模型 #Connections为网络关系矩阵,Amount为初始(0时期)感染者数量
C = copy.deepcopy(Connections)
Nodes = len(C)
InfecterStatus = catastrophe(Nodes,Amount) #根据设定的初始感染数,在随机位置生成感染者
g = nx.Graph() #新建画布
for n in range(Nodes): #在画布上设置节点
g.add_node(n)
for ed in range(Nodes): #在画布上设置边(连结关系)
for lin in range(ed+1,Nodes):
if C[ed][lin] == 1:
g.add_edge(ed,lin)
pos =nx.kamada_kawai_layout(g) #kamada-kawai路径长度成本函数计算
Status = {}
times = 0
while sum(InfecterStatus) <= Nodes: #当感染数大于等于节点数时停止迭代
# plt.imshow(InfecterStatus)
# plt.pause(3)#帧数
for s in range(len(InfecterStatus)): #把感染状态写入字典
SI = InfecterStatus[s]
Status[s] = SI
colors = []
for c in g: #分配各节点颜色表示感染状态
sta = Status[c]
if sta == 1:
clr = 'r'
if sta == 0 :
clr = 'g'
colors.append(clr)
nodesize = []
for ns in g:
de = ((sum(C[ns])*10)+50) #节点大小(节点度数越大,节点越大)
nodesize.append(de)
plt.figure(figsize=(12, 8))
nx.draw_networkx_nodes(g , pos=pos , with_labels=True , node_color=colors , node_size=nodesize , alpha=0.6)
nx.draw_networkx_edges(g , pos=pos , with_labels=True , width=0.3 , alpha=0.3)
print(f'迭代第 {times} 次 ---- 感染者数量:{sum(InfecterStatus)} ---- 占比:{(sum(InfecterStatus)/Nodes)}')
plt.show()
if sum(InfecterStatus) == Nodes:
Nodes = Nodes - 1
InfecterStatus = infect(C,InfecterStatus,Beta) #传染模型
times += 1
print('---------- 迭代完成 ----------')
4 执行
怕有的小伙伴光看上面了不会执行,所以在这边特地说明一下执行部分。
随缘说明,我想到啥说啥,其实也不是很难,根据我以下的说明举一反三很容易。
4.1 创建小世界网络
生成节点数为20,初始邻居数为4,重连率为0.2的小世界网络并打印出来
代码如下:
C = small_world(20,4,0.2)
print(C)
结果如下:
4.2 创建树状网络
生成4个分支,3层的树状网络并打印出来
代码如下:
C = tree(4,3)
print(C)
结果如下:
4.3 传播模拟可视化
以节点数100邻居数4重连率0.2的小世界网络为例进行传染病传播模拟。设置初始感染节点10,传染率0.5。
代码如下:
C = small_world(100,4,0.2) #生成网络矩阵
show_iteration(C,10,0.5) #传播模拟
开始运行会跳出一幅图,这是初始状态(第0次迭代)网络的展示。
把上面这幅图关掉,会出现第二幅图,这是第1次迭代网络的展示。同时在终端还会打印出当前以前的传染情况。
依次类推。当全部节点感染的时候,就停止运行。
后话:如果需要连贯地显示可以用imshow动态显示(无需手动关闭上一张图片),具体的调用方法可以自行百度。