赞
踩
本博文代码的思路是:
1、假设某个(某些)在网络中的节点有某种传染病
2、传染病会根据一定的传播概率传播给与被感染的节点直接相邻(连接)的其他节点
然后,要把这个传播的过程用图片的形式呈现出来,并且记录下每次迭代的感染数据。
顺便一提,本文基于SI模型,如果需要SIR模型还是SIS还是SIER模型的可以自己改进。
照例,先来一波效果展示。
在可视化中红色是已被感染的节点,绿色是健康节点。
这里我先展示一下3个分支5层的树状网络的效果,为了快点模拟完成,设置传染率0.5,初始感染节点为3个。
初始状态(第0次迭代):
第1次迭代:
第2次迭代:
……
第12次迭代:
……
第16次迭代:
……
第22次迭代(最后一个节点还蛮顽强的):
在出图片的同时,终端还输出了每次的感染情况:
可能一个类型的网络看得还不太清楚,所以我再展示一下小世界网络的传播情况。
这是一个有80个节点的小世界网络,初始邻居数是4,断线重连概率是0.2。设置传染率0.5,初始感染节点为3个。
初始状态(第0次迭代):
第1次迭代:
第2次迭代:
……
第5次迭代:
第6次迭代:
第7次迭代:
第8次迭代:
第9次迭代:
终端输出的每次迭代的感染情况:
好的,现在步入正题。
首先调用需要的包。
import numpy as np
import random
import copy
import matplotlib.pyplot as plt
import networkx as nx
然后再写几个生成不同形态的网络的函数。本博文提供了树状网络,小世界网络和随机网络。
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
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为无连结
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为无连结
补充一下,本博文的网络构建采用矩阵的方式构建,我随手print一个10节点邻居为2重连率为0.2的小世界网络:
接下来还有3个关于传播和可视化的函数。
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 #返回一个感染者编号列表
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 #返回新的感染者列表
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('---------- 迭代完成 ----------')
怕有的小伙伴光看上面了不会执行,所以在这边特地说明一下执行部分。
随缘说明,我想到啥说啥,其实也不是很难,根据我以下的说明举一反三很容易。
生成节点数为20,初始邻居数为4,重连率为0.2的小世界网络并打印出来
代码如下:
C = small_world(20,4,0.2)
print(C)
结果如下:
生成4个分支,3层的树状网络并打印出来
代码如下:
C = tree(4,3)
print(C)
结果如下:
以节点数100邻居数4重连率0.2的小世界网络为例进行传染病传播模拟。设置初始感染节点10,传染率0.5。
代码如下:
C = small_world(100,4,0.2) #生成网络矩阵
show_iteration(C,10,0.5) #传播模拟
开始运行会跳出一幅图,这是初始状态(第0次迭代)网络的展示。
把上面这幅图关掉,会出现第二幅图,这是第1次迭代网络的展示。同时在终端还会打印出当前以前的传染情况。
依次类推。当全部节点感染的时候,就停止运行。
后话:如果需要连贯地显示可以用imshow动态显示(无需手动关闭上一张图片),具体的调用方法可以自行百度。
动态视频可以参考这篇文献中的附录A(建议用网页打开):
Looking into mobility in the Covid-19 ‘eye of the storm’: Simulating virus spread and urban resilience in the Wuhan city region travel flow network
如果可以,也希望大家多多引用。
-----------------------分割线(以下是乞讨内容)-----------------------
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。