" R0 G+ O. Y- R Z+ S' k1 Y4 m3 z5 I. V2 G
S 类(Susceptible),易感者,指缺乏免疫能力的健康人,与感染者接触后容易受到感染;9 ~; a1 G$ I; n) S
1 z5 w+ d6 j2 b
& r% _# L2 e" ~3 d
E 类(Exposed),暴露者,指接触过感染者但暂无传染性的人,适用于存在潜伏期的传染病;) X7 [. B, F) h$ g! n5 v
* i0 d! [5 b* h+ X* Z, d
' A- |5 Z. c7 W' _" i
I 类(Infectious),患病者,指具有传染性的患病者,可以传播给 S 类成员将其变为 E 类或 I 类成员; % a& h1 t/ o6 x! F. P M; B* }2 K& i8 [! ?% j; P, `. j" v, L7 T6 ?, K
R 类(Recovered),康复者,指病愈后具有免疫力的人。如果免疫期有限,仍可以重新变为 S 类成员,进而被感染;如果是终身免疫,则不能再变为 S类、E类或 I 类成员。) ^! V6 O% u! `
?! m1 y" r2 p# A虽然 SI 模型的解析解并不复杂,而且解的精度当然是最好的,但我们仍然不鼓励用解析解的方法。原因在于,一是对于小白求解析解的过程相对复杂困难,而且可能出错,二是对于更复杂的模型是没有解析解的,即便大神也只能用数值方法求解。既然如此,不如从一开始就学习、掌握数值求解方法,熟悉数值解法的编程实现。# K% X) E. ?& R7 f
9 @, P" v/ f* l+ w & L9 m7 P( x2 a: G# Y3.2 SI 模型的数值解 - s' X E* {% R* oSI 模型是常微分方程初值问题,可以使用 Scipy 工具包的 scipy.integrate.odeint() 函数求数值解,具体方法可以参考前文《Python小白的数学建模课-09 微分方程模型》。2 L# J/ \; M b( n
3 F1 h2 S- `3 c8 t$ a* U1 N! W, ]/ D' z# b& M( T. z. U
scipy.integrate.odeint(func, y0, t, args=())4 N( y- `5 D: \+ ]7 E; n
1 # ]; V+ i; }3 e& R0 |: I**scipy.integrate.odeint()**是求解微分方程的具体方法,通过数值积分来求解常微分方程组。 , F6 J3 ?; ^, d& S# X- k( X2 a) t3 z6 E& J$ Z+ u0 P8 n* P
; t0 |# X, R% @0 M
odeint() 的主要参数: : Z: c( K* F& X5 p* G7 B2 X- s7 ]. q$ Q2 I7 K; Q; h' A$ d/ m
5 y0 E# G. V' o1 j4 R! Jfunc: callable(y, t, …) 导数函数 f ( y , t ) f(y,t)f(y,t) ,即 y 在 t 处的导数,以函数的形式表示 ~* N) A- \5 i8 Q8 z6 ^# _
y0: array: 初始条件 y 0 y_0y ; Z: I# l7 U7 q( J' m0 D0 J0$ Z, l+ x3 O0 {- m8 `& B
% {3 Q: w3 Z- [( ~0 P( v, Z' s+ c ,对于常微分方程组 y 0 y_0y + `/ W- {/ S: f, O3 p6 j01 }5 z3 Q7 f3 N4 J+ a
5 p9 v* o$ G0 R
则为数组向量 1 M6 f: o9 Z9 ]' d+ c+ ^9 rt: array: 求解函数值对应的时间点的序列。序列的第一个元素是与初始条件 y 0 y_0y - [. Q# V+ Z2 o5 J* b# q( p/ d& C
0+ o5 s1 o' V5 q, }9 g! ]
6 L' p( [$ o4 u' l9 s
对应的初始时间 t 0 t_0t ; M4 ]0 J4 m1 a; [4 z
0 8 r9 P3 W1 x# V+ L5 } ' M9 Z# }! n7 ?3 b/ `# H& _. i; ` ;时间序列必须是单调递增或单调递减的,允许重复值。' n6 }/ _) V' O; D* Q& 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。 4 Q3 |5 p! h$ k4 iodeint() 的返回值: A" a1 U. w4 S8 K" t, A) ]0 M2 o" Q+ a. }
# b9 R8 g R( i/ x" Z- `5 ~
/ Y- W) L% A0 y! f/ z) ~
y: array 数组,形状为 (len(t),len(y0),给出时间序列 t 中每个时刻的 y 值。 & F1 Q+ \2 \! ~; p8 b! T: q# M4 I2 Jodeint() 的编程步骤: 3 ]0 z* G: u$ n' j n& \ 3 ^0 P6 Q. R. m. u0 ~- @; P$ K4 |; ~3 u. U* D
导入 scipy、numpy、matplotlib 包;+ d! O# G6 _7 G; B
定义导数函数 f ( i , t ) = λ i ( 1 − i ) f(i,t)=\lambda i (1-i)f(i,t)=λi(1−i) ; , A3 ]% {0 c2 ~" Y, j定义初值 i 0 i_0i 4 m" g3 D0 G# X m* w& n
0; G! J; g) M' S7 B( U
: C$ w. Y0 h$ Q& s9 F 和 i ii 的定义区间 [ t 0 , t ] [t_0,\ t][t " J' g" u# y9 ]* ]* `0; j9 j8 c3 F1 m2 m. c3 |* E3 n
+ ~( y0 [6 E% ^
, t];8 x/ ^5 j$ Y- S1 B o4 y
调用 odeint() 求 i ii 在定义区间 [ t 0 , t ] [t_0,\ t][t : S3 H3 I1 f, e' W& E+ ?0 3 L2 H% _" `7 |( I# K2 a+ r9 w" I/ r & D0 b% V, l, ~$ f3 G. l/ S , t] 的数值解。 ; w$ ~; g/ U7 \3 c i3 P7 X, a& t) A' r4 N: X7 Z, c8 F
# V/ u6 N2 c. h2 i) L
3.3 Python例程:SI 模型的解析解与数值解 / E" Y$ T* B8 L3 ?+ v# 1. SI 模型,常微分非常,解析解与数值解的比较4 \: E2 t0 i$ q, z4 _" K; C
from scipy.integrate import odeint # 导入 scipy.integrate 模块 ! R, k: G* G( Z4 jimport numpy as np # 导入 numpy包2 ]7 \) L4 h. Q. ]
import matplotlib.pyplot as plt # 导入 matplotlib包0 |: O/ x/ `3 ~& L" ^
! H1 U% ]3 `: G. R# V( C6 l6 i% C% N# Y8 G: _* y2 m
图中 d i / d t di/dtdi/dt 具有最大值,最大值表示疫情增长的高潮,达到最大值后 d i / d t di/dtdi/dt 逐渐减小,但患病者比例很快增长到 100%,表明所有人都被感染成为患者。( L/ W8 e9 V h7 X) [