用Python制作在地图上模拟瘟疫扩散的Gif图


Posted in Python onMarch 31, 2015

受杰森的《Almost Looks Like Work》启发,我来展示一些病毒传播模型。需要注意的是这个模型并不反映现实情况,因此不要误以为是西非可怕的传染病。相反,它更应该被看做是某种虚构的僵尸爆发现象。那么,让我们进入主题。

用Python制作在地图上模拟瘟疫扩散的Gif图

这就是SIR模型,其中字母S、I和R反映的是在僵尸疫情中,个体可能处于的不同状态。

  •     S 代表易感群体,即健康个体中潜在的可能转变的数量。
  •     I 代表染病群体,即僵尸数量。
  •     R 代表移除量,即因死亡而退出游戏的僵尸数量,或者感染后又转回人类的数量。但对与僵尸不存在治愈者,所以我们就不要自我愚弄了(如果要把SIR模型应用到流感传染中,还是有治愈者的)。
  • 至于β(beta)和γ(gamma):
  •     β(beta)表示疾病的传染性程度,只要被咬就会感染。
  •     γ(gamma)表示从僵尸走向死亡的速率,取决于僵尸猎人的平均工作速率,当然,这不是一个完美的模型,请对我保持耐心。
  • S′=?βIS告诉我们健康者变成僵尸的速率,S′是对时间的导数。
  • I′=βIS?γI告诉我们感染者是如何增加的,以及行尸进入移除态速率(双关语)。
  • R′=γI只是加上(gamma I),这一项在前面的等式中是负的。

上面的模型没有考虑S/I/R的空间分布,下面来修正一下!

一种方法是把瑞典和北欧国家分割成网格,每个单元可以感染邻近单元,描述如下:

其中对于单元,和是它周围的四个单元。(不要因为对角单元而脑疲劳,我们需要我们的大脑不被吃掉)。

初始化一些东东。
 

import numpy as np
import math
import matplotlib.pyplot as plt  
%matplotlib inline
from matplotlib import rcParams
import matplotlib.image as mpimg
rcParams['font.family'] = 'serif'
rcParams['font.size'] = 16
rcParams['figure.figsize'] = 12, 8
from PIL import Image

适当的beta和gamma值就能够摧毁大半江山
 

beta = 0.010
gamma = 1

还记得导数的定义么?当导数已知,假设Δt很小的情况下,经过重新整理,它可以用来近似预测函数的下一个取值,我们已经声明过u′(t)。

用Python制作在地图上模拟瘟疫扩散的Gif图

初始化一些东东。
 

import numpy as np
import math
import matplotlib.pyplot as plt  
%matplotlib inline
from matplotlib import rcParams
import matplotlib.image as mpimg
rcParams['font.family'] = 'serif'
rcParams['font.size'] = 16
rcParams['figure.figsize'] = 12, 8
from PIL import Image

适当的beta和gamma值就能够摧毁大半江山
 

beta = 0.010
gamma = 1

还记得导数的定义么?当导数已知,假设Δt很小的情况下,经过重新整理,它可以用来近似预测函数的下一个取值,我们已经声明过u′(t)。

用Python制作在地图上模拟瘟疫扩散的Gif图

这种方法叫做欧拉法,代码如下:
 

def euler_step(u, f, dt):
  return u + dt * f(u)

我们需要函数f(u)。友好的numpy提供了简洁的数组操作。我可能会在另一篇文章中回顾它,因为它们太强大了,需要更多的解释,但现在这样就能达到效果:

def f(u):
  S = u[0]
  I = u[1]
  R = u[2]
 
  new = np.array([-beta*(S[1:-1, 1:-1]*I[1:-1, 1:-1] +
              S[0:-2, 1:-1]*I[0:-2, 1:-1] +
              S[2:, 1:-1]*I[2:, 1:-1] +
              S[1:-1, 0:-2]*I[1:-1, 0:-2] +
              S[1:-1, 2:]*I[1:-1, 2:]),
           beta*(S[1:-1, 1:-1]*I[1:-1, 1:-1] +
              S[0:-2, 1:-1]*I[0:-2, 1:-1] +
              S[2:, 1:-1]*I[2:, 1:-1] +
              S[1:-1, 0:-2]*I[1:-1, 0:-2] +
              S[1:-1, 2:]*I[1:-1, 2:]) - gamma*I[1:-1, 1:-1],
           gamma*I[1:-1, 1:-1]
          ])
 
  padding = np.zeros_like(u)
  padding[:,1:-1,1:-1] = new
  padding[0][padding[0] < 0] = 0
  padding[0][padding[0] > 255] = 255
  padding[1][padding[1] < 0] = 0
  padding[1][padding[1] > 255] = 255
  padding[2][padding[2] < 0] = 0
  padding[2][padding[2] > 255] = 255
 
  return padding

导入北欧国家的人口密度图并进行下采样,以便较快地得到结果
 

from PIL import Image
img = Image.open('popdens2.png')
img = img.resize((img.size[0]/2,img.size[1]/2))
img = 255 - np.asarray(img)
imgplot = plt.imshow(img)
imgplot.set_interpolation('nearest')

用Python制作在地图上模拟瘟疫扩散的Gif图

北欧国家的人口密度图(未包含丹麦)

S矩阵,也就是易感个体,应该近似于人口密度。感染者初始值是0,我们把斯德哥尔摩作为第一感染源。
 

S_0 = img[:,:,1]
I_0 = np.zeros_like(S_0)
I_0[309,170] = 1 # patient zero

因为还没人死亡,所以把矩阵也置为0.
 

R_0 = np.zeros_like(S_0)

接着初始化模拟时长等。
 

T = 900             # final time
dt = 1             # time increment
N = int(T/dt) + 1        # number of time-steps
t = np.linspace(0.0, T, N)   # time discretization
 
# initialize the array containing the solution for each time-step
u = np.empty((N, 3, S_0.shape[0], S_0.shape[1]))
u[0][0] = S_0
u[0][1] = I_0
u[0][2] = R_0

我们需要自定义一个颜色表,这样才能将感染矩阵显示在地图上。
 

import matplotlib.cm as cm
theCM = cm.get_cmap("Reds")
theCM._init()
alphas = np.abs(np.linspace(0, 1, theCM.N))
theCM._lut[:-3,-1] = alphas

下面坐下来欣赏吧…

for n in range(N-1):
  u[n+1] = euler_step(u[n], f, dt)

让我们再做一下图像渲染,把它做成gif,每个人都喜欢gifs!
 

from images2gif import writeGif
 
keyFrames = []
frames = 60.0
 
for i in range(0, N-1, int(N/frames)):
  imgplot = plt.imshow(img, vmin=0, vmax=255)
  imgplot.set_interpolation("nearest")
  imgplot = plt.imshow(u[i][1], vmin=0, cmap=theCM)
  imgplot.set_interpolation("nearest")
  filename = "outbreak" + str(i) + ".png"
  plt.savefig(filename)
  keyFrames.append(filename)
 
images = [Image.open(fn) for fn in keyFrames]
gifFilename = "outbreak.gif"
writeGif(gifFilename, images, duration=0.3)
plt.clf()
Python 相关文章推荐
Python将xml和xsl转换为html的方法
Mar 10 Python
深入理解Javascript中的this关键字
Mar 27 Python
Python3.5编程实现修改IIS WEB.CONFIG的方法示例
Aug 18 Python
基于Python对象引用、可变性和垃圾回收详解
Aug 21 Python
python从子线程中获得返回值的方法
Jan 30 Python
django 控制页面跳转的例子
Aug 06 Python
python mqtt 客户端的实现代码实例
Sep 25 Python
Python实现字符串中某个字母的替代功能
Oct 21 Python
python基于plotly实现画饼状图代码实例
Dec 16 Python
简单了解Python读取大文件代码实例
Dec 18 Python
python使用openpyxl操作excel的方法步骤
May 28 Python
Python无损压缩图片的示例代码
Aug 06 Python
以一段代码为实例快速入门Python2.7
Mar 31 #Python
11个并不被常用但对开发非常有帮助的Python库
Mar 31 #Python
Python的Flask框架中@app.route的用法教程
Mar 31 #Python
使用Python的Flask框架实现视频的流媒体传输
Mar 31 #Python
在Python3中初学者应会的一些基本的提升效率的小技巧
Mar 31 #Python
使用IronPython把Python脚本集成到.NET程序中的教程
Mar 31 #Python
提升Python程序运行效率的6个方法
Mar 31 #Python
You might like
PHP中去掉字符串首尾空格的方法
2012/05/19 PHP
php object转数组示例
2014/01/15 PHP
PHP给源代码加密的几种方法汇总(推荐)
2018/02/06 PHP
PHP智能识别收货地址信息实例
2019/01/05 PHP
jquery中 $.expr使用实例介绍
2014/06/09 Javascript
JS实现仿google、百度搜索框输入信息智能提示的实现方法
2015/04/20 Javascript
JS实现生成会变大变小的圆环实例
2015/08/05 Javascript
js实现input框文字动态变换显示效果
2015/08/19 Javascript
深入理解关于javascript中apply()和call()方法的区别
2016/04/12 Javascript
浅谈jquery中next与siblings的区别
2016/10/27 Javascript
jQuery插件jqGrid动态获取列和列字段的方法
2017/03/03 Javascript
Node.js pipe实现源码解析
2017/08/12 Javascript
webpack使用 babel-loader 转换 ES6代码示例
2017/08/21 Javascript
javascript中函数的写法实例代码详解
2018/10/28 Javascript
vue+elementUI中表格高亮或字体颜色改变操作
2020/11/02 Javascript
关于Python中浮点数精度处理的技巧总结
2017/08/10 Python
Pandas读取csv时如何设置列名
2020/06/02 Python
Pycharm自动添加文件头注释和函数注释参数的方法
2020/10/23 Python
中国宠物用品商城:E宠商城
2016/08/27 全球购物
Merrell迈乐澳大利亚网站:购买户外登山鞋
2017/05/28 全球购物
Regatta官网:英国最受欢迎的户外服装和鞋类品牌
2019/05/01 全球购物
Linux开机引导的步骤是什么
2014/02/26 面试题
安全例会汇报材料
2014/08/23 职场文书
小学关爱留守儿童活动方案
2014/08/25 职场文书
防火标语大全
2014/10/06 职场文书
大学感恩节活动策划方案
2014/10/11 职场文书
党的群众路线教育实践活动心得体会范文
2014/11/05 职场文书
秦始皇兵马俑导游词
2015/02/02 职场文书
党员活动总结
2015/02/04 职场文书
成事在人观后感
2015/06/16 职场文书
高三语文教学反思
2016/02/16 职场文书
小学作文指导之如何写人?
2019/07/08 职场文书
Oracle笔记
2021/04/05 Oracle
【海涛dota】偶遇拉娜娅 质量局德鲁伊第一视角解说
2022/04/01 DOTA
SQL Server数据库查询出现阻塞之性能调优
2022/04/10 SQL Server
前端与RabbitMQ实时消息推送未读消息小红点实现示例
2022/07/23 Java/Android