3 P& j7 X- j( a% H5 ], m ]3. SI 模型的 Python 编程4 h# j# T( h3 ^$ u
3.1 SI 模型的解析解 # b1 p+ a! ~! e' K. m上文已经得到 SI 模型的解析解,对此很容易通过 Python 编程实现,详见本文例程。 " J( n+ L- Z& j2 Q8 ^ I4 f A/ R ?$ s: k- Y
" k# s6 s3 M8 e' E+ p
虽然 SI 模型的解析解并不复杂,而且解的精度当然是最好的,但我们仍然不鼓励用解析解的方法。原因在于,一是对于小白求解析解的过程相对复杂困难,而且可能出错,二是对于更复杂的模型是没有解析解的,即便大神也只能用数值方法求解。既然如此,不如从一开始就学习、掌握数值求解方法,熟悉数值解法的编程实现。* O6 [. z! g, l3 [
5 W! S2 s% z0 T+ v1 W. q- y+ p9 i* Z, G5 s" Z7 [
3.2 SI 模型的数值解 0 {: X/ o9 i- E' O6 ZSI 模型是常微分方程初值问题,可以使用 Scipy 工具包的 scipy.integrate.odeint() 函数求数值解,具体方法可以参考前文《Python小白的数学建模课-09 微分方程模型》。 9 I- H( k! y. f+ S/ ] 0 k5 l. Z9 u: @4 ^0 p# _+ O. f" ~ v; ?( {! s; [4 W4 W4 O
scipy.integrate.odeint(func, y0, t, args=())) D9 s! n; H5 W, U5 J
1 " [ w3 L! S3 o0 m! P G% b n**scipy.integrate.odeint()**是求解微分方程的具体方法,通过数值积分来求解常微分方程组。 : I/ {* X" V; {; {; ? L" F2 M+ B) E% x+ X8 m8 _; [
5 t. a) p) }% x1 t
odeint() 的主要参数:( E7 J! U/ W" X7 V1 t3 @& J, Q
u5 D; B- d4 Q* _ e$ ~# N% N* E* T( a: e3 T
func: callable(y, t, …) 导数函数 f ( y , t ) f(y,t)f(y,t) ,即 y 在 t 处的导数,以函数的形式表示 M) |$ `2 P$ Q3 M- Gy0: array: 初始条件 y 0 y_0y , T. K `0 m2 J- {0 F2 l0/ T$ u A( r! p- r; o4 P% B" |
! T( i& p4 v0 l ,对于常微分方程组 y 0 y_0y 7 J( z8 b0 m- }4 H4 R+ w9 d0: P1 w* W* f1 J; t
0 N% i. E8 i* L* ?# }4 _3 a0 D$ L% J 则为数组向量7 B4 \ U. o R; D8 b( X: p
t: array: 求解函数值对应的时间点的序列。序列的第一个元素是与初始条件 y 0 y_0y : _* P8 x0 l3 j! z, ?4 v0 0 F9 g& a1 }6 j" t ! a R$ J1 m1 {" u, X) M0 z
对应的初始时间 t 0 t_0t ; r, z! U ^1 ]
06 k5 A9 M& q! F1 D
4 J/ W: z$ Z( Z" I( ` ;时间序列必须是单调递增或单调递减的,允许重复值。 & m# ` L# I$ f3 [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。 7 f0 R* `8 `7 Todeint() 的返回值:. p* L, b, @& ~8 v/ v0 L
5 C: ^& B0 ^3 v$ K
# }9 L: q! ^) }2 m4 z4 d5 |+ wy: array 数组,形状为 (len(t),len(y0),给出时间序列 t 中每个时刻的 y 值。 . E* V! f6 j6 H; _: c+ N! E9 q) [odeint() 的编程步骤:/ o, O1 a) N; f4 M% p! V; C
; A# ^& V9 S, C3 \$ }& f " x7 L; o4 U/ }5 {7 t/ {9 L* T导入 scipy、numpy、matplotlib 包; $ J# d( F" T6 }2 e, d定义导数函数 f ( i , t ) = λ i ( 1 − i ) f(i,t)=\lambda i (1-i)f(i,t)=λi(1−i) ;7 j$ G7 `) s& \: y) ` [, L, f
定义初值 i 0 i_0i : B2 l. ?' H+ `* O
0 2 S2 I; e' ]0 l* h 9 A( j, C" J2 Q& Y 和 i ii 的定义区间 [ t 0 , t ] [t_0,\ t][t $ t) |- X7 P/ W$ r/ p4 Q/ @% k0% H) P1 u9 j b2 G/ w
1 ~- D- J! a, b: Q , t];) ?+ e" }2 r2 b/ r% B$ o
调用 odeint() 求 i ii 在定义区间 [ t 0 , t ] [t_0,\ t][t 1 p' [, {; }- P; b4 S' h
09 h$ G4 |3 k% j. D; O- b. `' p
+ ^7 g" ]0 z) H! \0 J8 x , t] 的数值解。 ! s H0 _& R* K! F 6 ]0 n: F( R2 m n8 K$ Z( b4 G% C' g0 l' F- t5 n
3.3 Python例程:SI 模型的解析解与数值解" H& ]+ |5 p, y, V/ z- s/ r
# 1. SI 模型,常微分非常,解析解与数值解的比较* G9 y0 K+ N _
from scipy.integrate import odeint # 导入 scipy.integrate 模块, z- W. q$ W% h0 w3 v/ d
import numpy as np # 导入 numpy包 " G1 z/ |. X" C, @% h: i5 T$ C( Z5 Aimport matplotlib.pyplot as plt # 导入 matplotlib包 2 `& q+ U% `0 T+ }7 |: g% @1 j) q; b5 X4 e
, B) e0 t, w$ q8 Z8 }' N
def dy_dt(y, t, lamda, mu): # 定义导数函数 f(y,t)' e& E( l8 g2 b; d+ ~4 _2 ?0 F
dy_dt = lamda*y*(1-y) # di/dt = lamda*i*(1-i)3 l9 e' X. K6 G7 R( {, f
return dy_dt - n! j, K' Z% W) H& W/ ~ 5 J* B1 r- E# t( _/ w & L" |7 J# p* E/ ^& Z; n/ y8 z# 设置模型参数 / c' h a6 U- `9 h( t- mnumber = 1e7 # 总人数 , M- I9 u! j: o( C! ?" i* qlamda = 1.0 # 日接触率, 患病者每天有效接触的易感者的平均人数 4 i% B$ g6 F: v7 ]2 d: u- c3 qmu1 = 0.5 # 日治愈率, 每天被治愈的患病者人数占患病者总数的比例 4 o' v2 R% _. p8 |9 q/ ?y0 = i0 = 1e-6 # 患病者比例的初值 2 e3 A, f/ U/ |3 dtEnd = 50 # 预测日期长度) x! e1 ?8 a7 S4 U4 `. T( K
t = np.arange(0.0,tEnd,1) # (start,stop,step)- ^8 p+ X1 q- X* q* ]: F) J$ a5 v
m, E k) l$ o# W; ^# x& ?" A 7 `# ~* f* I! [6 Q4 YyAnaly = 1/(1+(1/i0-1)*np.exp(-lamda*t)) # 微分方程的解析解- z/ \. e. ?- J+ V5 N
yInteg = odeint(dy_dt, y0, t, args=(lamda,mu1)) # 求解微分方程初值问题5 ~# g" I1 ^% |! T' `( r
yDeriv = lamda * yInteg *(1-yInteg) 6 H; \* H9 n; Z7 F3 v. l, T5 A0 Y: c
( \! {3 V; G' |% p" w% ^# 绘图 & w" o( g$ _* C! e" Zplt.plot(t, yAnaly, '-ob', label='analytic')/ u3 r6 d: `8 T6 y! T( h; J
plt.plot(t, yInteg, ':.r', label='numerical')9 Y r T% N* o+ B3 Q7 J
plt.plot(t, yDeriv, '-g', label='dy_dt')$ K, g/ h+ }7 C) E- d9 O
plt.title("Comparison between analytic and numerical solutions"); f8 x J, M& `/ n3 C
plt.legend(loc='right')* y2 K+ K8 l( G* @4 I- n
plt.axis([0, 50, -0.1, 1.1])' i8 ] @' x' w! q9 B3 i. N/ I! c) ]
plt.show() 1 l$ U" b5 r4 `+ Y3 R* `' f' k% P1 x1- G6 Q: Z8 b4 I7 ]1 \9 I' A
29 P7 j' \* j; b5 v: i8 r5 ^
3 - L/ k% M6 c- Q! R# _5 j4 5 ]) D$ y, n: i5 X, a. N4 ~% J53 x6 ~- _1 x& A+ ^6 ~+ _; N9 O
6 , j; H5 R7 h( r* a# e. A6 ^7) v% u3 |6 w |' M
8! Y+ t" K; u' r
9, p3 C# z: N$ u" N- N
10 4 h0 t4 b8 h# v3 m11 4 C$ W1 v l- [12: D; M3 K' Q, Z% A8 r) h5 |
13 7 o% ?7 m1 B7 Y/ T( Y; H14$ ]0 W' b+ }+ G4 K3 U7 }
150 e, }3 S; m& m0 x" K6 U
16 ' a, ^. J7 E, y: p17 % ~) r3 |( b! U$ I, B [6 `0 i18 " b E! {1 O8 z19 + L M4 g0 L) E4 K8 n% u' C/ m L" O20 2 c! c p2 C. l1 P8 [0 F21% f" R* U% T2 x! n7 V7 T F% h
220 [: H y$ C( }6 T& k
23 $ y; v- L" {( s. `" c. ~; x( o& r246 L+ n \$ f6 `9 b6 [- m4 p' d r
25. P3 |; w. F! ?* n
266 s+ [8 m4 s: h9 \- U
27 5 o- V* o/ ?( x6 a( _6 K3 y) u28% T) P' l7 f/ f! y5 |9 Z
29 ' ?8 f& J( s3 n: j 6 T4 Y* \% f% V; R" T. w. V+ | + l7 f1 T; b4 N& D( X, S3.4 解析解与数值解的比较2 l7 A8 |3 P, U( O4 i# ?* r! W/ C
$ J* U% H. l5 ]+ }+ _7 E# P% A8 Z" L5 f
本图为例程 2.3 的运行结果,图中对解析解(蓝色)与使用 odeint() 得到的数值解(红色)进行比较。在该例中,无法观察到解析解与数值解的差异,表明数值解的误差很小。0 W# ~0 k6 l! d4 u
' i8 i$ T4 o' C% D7 K$ X: h8 i- c y& A% Y! b
图中 d i / d t di/dtdi/dt 具有最大值,最大值表示疫情增长的高潮,达到最大值后 d i / d t di/dtdi/dt 逐渐减小,但患病者比例很快增长到 100%,表明所有人都被感染成为患者。9 d! k. |3 M4 k, V! f$ ^
! g6 S" R- L+ g% m 5 Z( M" X }0 T这是特定参数的结果,还是模型的必然趋势,需要对参数的影响进行更详细的研究。 : w3 k6 \8 p$ a$ k* [ : }* s0 t6 i: |6 V& y2 m# u, F8 }6 Z2 c7 h) l: r
' U/ c8 d" w0 ], A' [7 J . \- O4 _ v$ G3 Q4 r q w4. SI 模型参数的影响 5 _9 h/ ^3 f# M" J; W4 W对于 SI 模型,只有日接触率 λ \lambdaλ 和患病者比例的初值 i 0 i_0i / }* N0 [; K' [; r+ D B* Z0 ' X, X7 z2 N" ] `6 B+ [4 h+ d 9 X1 u7 \" w+ c6 y, j6 W5 s7 \8 H 会影响模型的结果,其它参数如总人数 N 并没有影响。9 w/ u- |, I7 t* c+ x5 B, P$ H
9 U5 u; N6 O/ ?' H
* j! ~7 Q; h3 v2 |4 c4 u4 Y
4.1 日接触率对 SI 模型的影响) Y, O' z" O1 `+ Z) J/ i& S' C
* A; G3 W2 |4 G
9 Y- C, R# Z9 |' S
对不同日接触率的比较表明:) g% r- u* M5 y3 p- m3 z4 [
- k+ d, w4 Y* U' ~
0 N8 U. ~ o. G" [ V. ?日接触率越大,疫情从发生到爆发的时间越短,爆发过程的增长速度也越快。 / n* N& R7 C& V- z不论日接触率多大,患病者的比例最终都会增长到 1,表明所有人都被感染成为患者。 8 p" \0 p# H+ A O) |不论日接触率多大,都具有缓慢发展、爆发、增长放缓 3 个阶段,进入爆发阶段后患病者的比例急剧增长,疫情就很难控制了。 e8 G3 {$ a1 O+ `( j2 @5 A8 w% Y8 c& |
, f8 I q) ~: v: Q" ~4.2 患病者比例的初值对 SI 模型的影响9 R9 N( E; F3 M) s) b
' {0 k Z4 j ?% ]
: ]1 l9 a2 @4 A- S对患病者比例初值的比较表明,患病者初值的人数或比例只影响疫情爆发期到来的快慢,对疫情传播的过程和结果几乎没有影响。 ) O: Y! j9 Q- Y2 Y$ v# Y1 X# H" Y: G( \3 N! _! J
' o* F4 |, W) B
这与我们直观的经验不太一致,一个原因是 SI 模型本身存在不足,另一方面也说明如果对传染病不加控制,即使开始患病人数很少,经过一段时间的传播后也终将会引起爆发。* E& E' M" a5 V8 w n+ w
/ b$ f* t) A4 I" p! h
; l6 g( B3 _: M& v3 n+ K
4.3 SI 模型结果讨论- ?3 I z' } R% U
在 i ( t ) = 0.5 , I ( t ) = N / 2 i(t)=0.5,\ I(t) = N/2i(t)=0.5, I(t)=N/2 时 $ di/dt$ 达到最大值,病人数目 I ( t ) I(t)I(t) 增加最快。由此可以预报传染病高潮的到来,即为医院的门诊量最大的一天,卫生部门要重点关注。; ^0 q7 H1 q: ]- ]
t m t_mt ! r& W, Q+ W! W! O% y) ]& O: C om ( Y" M9 J. {# q0 B: | ; S, i! [6 o W* r- N
与 λ \lambdaλ 成反比。日接触率 λ \lambdaλ 反映卫生水平、防控手段,提高卫生水平、强化防控手段,降低病人的日接触率,可以推迟传染病高潮的到来。8 }8 @' U; X1 i5 |6 n6 Q: p
当 t → ∞ t \to \inftyt→∞ 时 i → 1 i \to 1i→1 ,表明所有人最终都会被传染而变成病人。这完全不符合实际情况,表明该模型太不讲 politics 了,只能适用于美帝国家建模。4 D# K# C- s5 n# p& v0 F
SI 模型非常明显而严重的缺陷,是该模型没有考虑患病者可以治愈,因此只能是健康人患病,而患病者不能恢复健康(甚至也不会死亡,而是不断传播疫情),所以终将全部被传染。1 {/ B+ K( F) |+ i# o; i
————————————————& J: c" [6 L. t2 P5 t' N9 K
版权声明:本文为CSDN博主「youcans」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 9 x+ H! M; H3 Q' `2 O6 L原文链接:https://blog.csdn.net/youcans/article/details/117740466; g6 y+ T" l# q" t
! j1 v4 M' B* [/ z8 d
# a0 K7 Q2 \& q$ q; i