' b/ y {* Q n" `6 G. V8 M 8 h1 r( O4 k+ Z- O/ [% F( s$ e不同类型传染病的传播具有不同的特点,传染病的传播模型不是从医学角度分析传染病的传播过程,而是按照传播机理建立不同的数学模型。 v! c* L8 R6 S7 i: t$ e
^ ^' W m4 R3 A( H( N/ V8 N' r! H% F
5 R5 _) y% b3 p, B# J0 |1 f( ?
首先,把传染病流行范围内的人群分为 S、E、I、R 四类,具体含义如下: $ c1 v( J. {3 O4 s6 V% R1 I. s) I; C* Z7 S
; t" Y( M* K1 |4 e3 kS 类(Susceptible),易感者,指缺乏免疫能力的健康人,与感染者接触后容易受到感染;7 V, h# Y V' w) g. z; o" F
# x5 r1 Q" }" Q; Q2 l M; I 2 T3 y- i+ O# Y {) [7 rE 类(Exposed),暴露者,指接触过感染者但暂无传染性的人,适用于存在潜伏期的传染病;8 Q8 w6 K2 ?) C6 @
$ k9 W5 r/ N3 l 4 j, F' y! k" D. z1 i/ GI 类(Infectious),患病者,指具有传染性的患病者,可以传播给 S 类成员将其变为 E 类或 I 类成员; 9 a: m4 b) l$ O! j' m: g! L" K( } ]/ p5 p) b$ b+ H5 R2 f, R
- g. i ^) P% `- }R 类(Recovered),康复者,指病愈后具有免疫力的人。如果免疫期有限,仍可以重新变为 S 类成员,进而被感染;如果是终身免疫,则不能再变为 S类、E类或 I 类成员。. [( B3 c. u& t2 c' Y$ a/ t
4 B& @! ?4 d, o2 }7 T' w
* f& X) m% _; I( |常见的传染病模型按照传染病类型分为 SI、SIR、SIRS、SEIR 模型等,就是由以上四类人群根据不同传染病的特征进行组合而产生的不同模型。 # `, U1 c' y' k9 |1 U. s3 W3 {$ M # x3 N8 r0 B( q$ P % z' E q5 o5 L/ E# O% b/ p7 B- c1 ~0 ?6 g1 }7 U/ Y6 q
2 x4 n) x- I% p9 tfunc: callable(y, t, …) 导数函数 f ( y , t ) f(y,t)f(y,t) ,即 y 在 t 处的导数,以函数的形式表示 ' G9 }1 f0 G4 e5 |; W5 R7 Ty0: array: 初始条件 y 0 y_0y ; O& Z7 a4 h7 P3 l& {4 `7 i
05 _5 C) ` y, ?/ K# I6 q" `
9 J' E# v/ \4 o" D1 n
,对于常微分方程组 y 0 y_0y & s7 ^9 a* d4 F5 h0+ [" l0 x2 v+ U% g
- o( t ^7 ]2 A5 w0 D, {4 D 则为数组向量 ' _; {# H5 g+ m5 y! s3 [( qt: array: 求解函数值对应的时间点的序列。序列的第一个元素是与初始条件 y 0 y_0y " H3 l" Z% R7 q8 h$ |8 V0% M$ a6 ^ g! L6 W( O, R& q
( E" q, H9 y0 A u% Q+ |) w: d" Q0 x
对应的初始时间 t 0 t_0t " b1 t8 [$ _% U! s$ a% d& x1 }7 j
0; I6 H3 a- v9 d/ R" z: G7 }; r
# J; _9 f. C: q+ N8 B
;时间序列必须是单调递增或单调递减的,允许重复值。8 w8 ~2 N* o4 ~6 E# W8 O% z! m
args: 向导数函数 func 传递参数。当导数函数 f ( y , t , p 1 , p 2 , . . ) f(y,t,p1,p2,..)f(y,t,p1,p2,..) 包括可变参数 p1,p2… 时,通过 args =(p1,p2,…) 可以将参数p1,p2… 传递给导数函数 func。 - a2 H# j% H& ]" Oodeint() 的返回值: 8 ]! D* O4 y; A' J3 S# w) s' { - G! F- W f) t9 E: S6 l) q0 h: U' H' |4 `( d$ ~8 Q) N
y: array 数组,形状为 (len(t),len(y0),给出时间序列 t 中每个时刻的 y 值。3 J4 z/ ^+ f4 S" L9 z; `" G$ o
odeint() 的编程步骤:. ?5 }8 {3 L0 ~% O2 }8 Y
! Q: r8 F! A, _, w8 O' m4 U
, ?2 a# j- Y8 I4 Q2 U导入 scipy、numpy、matplotlib 包; - _; Q. |, g o! k# L3 _ j; ?定义导数函数 f ( i , t ) = λ i ( 1 − i ) f(i,t)=\lambda i (1-i)f(i,t)=λi(1−i) ;4 L* M. g$ G$ v( p; U0 ^
定义初值 i 0 i_0i # Q$ t! o* m! C( E: R6 o" U07 N( b0 y/ w+ i1 _- n
( a# k4 H' E" _) [9 i& o 和 i ii 的定义区间 [ t 0 , t ] [t_0,\ t][t ! j: D# d' K( |/ f4 r
0 % H1 X, T9 X% _7 L0 y( J) ]% } h + @1 ~) h0 }. ]* g S, ?% u , t];# ^9 a+ d% \( }' Z
调用 odeint() 求 i ii 在定义区间 [ t 0 , t ] [t_0,\ t][t ) q1 s* o% [8 e4 j9 m2 `
0 . L! p5 C( Y8 R, v 7 h, e$ G* Y; ~* Q- ^$ L
, t] 的数值解。 / s$ s* K( }# |% M6 M2 y+ X + r1 T% U% H1 g0 ~+ w3 y5 T8 }0 \6 E+ [6 s2 _9 E! }( ]- e8 R
3.3 Python例程:SI 模型的解析解与数值解8 ~, o: q3 Y4 v3 Q- G: P
# 1. SI 模型,常微分非常,解析解与数值解的比较5 A$ c9 w4 I) Y( b
from scipy.integrate import odeint # 导入 scipy.integrate 模块 , _( q% ?1 r' {+ D3 Q$ N5 timport numpy as np # 导入 numpy包 ) u, J4 Z( z+ o9 T: x! {( V, F h; Rimport matplotlib.pyplot as plt # 导入 matplotlib包: G' }7 E# @: g3 ~% j
7 Q9 E! T8 p+ M9 w; Y% w, l7 H4 ^) g
9 k! f; i8 `/ m3 I
def dy_dt(y, t, lamda, mu): # 定义导数函数 f(y,t) # |' L/ m h9 |/ ^' G# I" t dy_dt = lamda*y*(1-y) # di/dt = lamda*i*(1-i)$ V% d/ l3 b5 k; y; i! ~* U, w( h7 T
return dy_dt J* {0 j9 G$ d# V7 j( f# c$ E% M$ Q/ H) U i
, s6 g; \8 k9 I4 b
# 设置模型参数; Y$ r1 {! L/ ^3 H2 m, @9 C
number = 1e7 # 总人数& u4 l J- k" R# I8 w: ^+ _8 Z& z" i4 |
lamda = 1.0 # 日接触率, 患病者每天有效接触的易感者的平均人数3 f5 T; u# x7 V- R4 n" F+ F
mu1 = 0.5 # 日治愈率, 每天被治愈的患病者人数占患病者总数的比例0 S A$ U4 S, s- ]! I5 {) t2 a
y0 = i0 = 1e-6 # 患病者比例的初值: d W& [) m- }
tEnd = 50 # 预测日期长度7 g; C+ U3 A9 l& I" T9 M
t = np.arange(0.0,tEnd,1) # (start,stop,step) / `9 Q( B1 C/ d/ |, E4 N : x* s1 m- {1 I ; s/ u; v7 n+ V5 nyAnaly = 1/(1+(1/i0-1)*np.exp(-lamda*t)) # 微分方程的解析解 8 @! p6 W$ Y8 h& |' zyInteg = odeint(dy_dt, y0, t, args=(lamda,mu1)) # 求解微分方程初值问题 , B7 y4 _/ |2 q9 vyDeriv = lamda * yInteg *(1-yInteg) ; J( J# w0 Z0 Z, ~$ B% |! ~* ~# j* P& W+ o* A" f4 S) _
( A/ \( K/ B, i# l5 S8 @# 绘图1 M; Z! T/ f6 [' @
plt.plot(t, yAnaly, '-ob', label='analytic'). ^2 Z* J, d! i I
plt.plot(t, yInteg, ':.r', label='numerical')# I7 J1 T2 ]6 E- ^
plt.plot(t, yDeriv, '-g', label='dy_dt')5 Q& ?: h0 n. s
plt.title("Comparison between analytic and numerical solutions") + y& @: h# V' \8 ]plt.legend(loc='right') 7 c$ [+ v, h: q( `plt.axis([0, 50, -0.1, 1.1])/ y2 M t9 E" T" \
plt.show() 6 w: n+ `' U6 \. v, i( z19 [4 _, u, \: w) a' v1 c
2 3 u5 _2 J, Y1 N2 y3) U; O# @0 i) M& C2 S! Q
4 & ^) Z# w* @" T# _* X8 L5' Q N4 M/ |" a0 n% r( e7 J" }1 M
6! M, a. Z: j* h6 _) |
7 ' V- \3 B; G% F( T8; A* Y% [( q" }$ ?( {
9 6 R4 p/ z* f0 a- @108 E2 a Q: K [& E* z% o2 F
11 # B9 k _2 H% G# d) i5 C12 . J% H& ?4 @4 M# R13 ( |( E7 j* p; w14 $ N1 [# C# X: ?: D151 ?+ V. v5 L+ U. Y- J
16 6 p+ @! O7 P. K, @17 ) V% P! c, n) [4 U P8 k9 t18 # I1 K( C0 F4 l2 o9 q1 n19, T5 W! n, s# N' p
207 Y3 F. T2 H7 A1 ^+ V
21( {/ c. C6 ?3 q5 j( C9 D9 C
22 % [0 z3 L$ k {# K+ H7 |23 / a0 ]1 ~! ~' n j2 W24 , q3 W+ S% g4 `9 {8 ]. e/ ]8 c. K25 1 {! C: i/ S: h: `; S/ i- v, X26, z0 h5 x* O1 _( _
27 + l! H5 P# V( S' m0 [28 # f" L* r+ L% Z29' k @- J" S0 y! a
! T. f6 k% c4 [
. N" H: m% N ]: a! O
3.4 解析解与数值解的比较1 j! N, X( {4 s8 `
0 u7 b; A& {2 P- k
# Q' B& ^3 R( m& m% C/ G本图为例程 2.3 的运行结果,图中对解析解(蓝色)与使用 odeint() 得到的数值解(红色)进行比较。在该例中,无法观察到解析解与数值解的差异,表明数值解的误差很小。" k0 f9 _' ]* ]
l4 E, d# t: N. o' z) U; n
1 d' g. n" R/ j7 f7 |
图中 d i / d t di/dtdi/dt 具有最大值,最大值表示疫情增长的高潮,达到最大值后 d i / d t di/dtdi/dt 逐渐减小,但患病者比例很快增长到 100%,表明所有人都被感染成为患者。$ v3 {# [3 M6 q