$ X: z& ]+ L" q% e% S5 i, o) m $ B8 w* n4 i q! ]& k8 Y7 G; a* z F
7 G \; @/ F6 [) h& Y* K
1. 前言 ; a8 ^/ B. C0 q1 @新冠疫情不仅严重影响到全球的政治和经济,深刻和全面地影响着社会和生活的方方面面,也已经成为数学建模竞赛的背景帝。 ! h0 u1 R. L$ l9 S, a3 ?7 c% B) ]" D$ P6 v4 H1 ~ s
1 z6 V- C y% `7 n传染病的数学模型是数学建模中的典型问题,标准名称是流行病的数学模型(Mathematical models of epidemic diseases)。建立传染病的数学模型来描述传染病的传播过程,研究传染病的传播速度、空间范围、传播途径、动力学机理等问题,以指导对传染病的有效地预防和控制,具有重要的现实意义。9 W& k/ n1 R5 R! m
6 g5 Q# O q% Q j( K% i1 Z+ R" p8 U1 Y0 T
不同类型传染病的传播具有不同的特点,传染病的传播模型不是从医学角度分析传染病的传播过程,而是按照传播机理建立不同的数学模型。# R t# C) ]; _) z1 ^2 s
, L0 k, a( ^- l, T
: x7 m4 |2 T9 W; H; J$ O
首先,把传染病流行范围内的人群分为 S、E、I、R 四类,具体含义如下:3 X e. ^9 O" E0 t5 o, g- t: o
. z9 G) {( l+ b6 s2 \* [
0 `) U5 Q; k5 P9 C5 E5 K
S 类(Susceptible),易感者,指缺乏免疫能力的健康人,与感染者接触后容易受到感染;) U% s* u9 n t7 f2 ~9 E
Q" k3 b0 [* W# C0 v
2 b3 o/ ? ]2 Z, x
E 类(Exposed),暴露者,指接触过感染者但暂无传染性的人,适用于存在潜伏期的传染病; 2 B/ \5 w# L, t # g; J# O, Q) V) `$ ]( F " _1 f f/ d9 H8 j6 Z% |I 类(Infectious),患病者,指具有传染性的患病者,可以传播给 S 类成员将其变为 E 类或 I 类成员;$ ^: ]5 E2 L2 w3 }0 t
4 `: S' n" \" o. @! N4 X, l+ T2 k
3 B! u3 x. @4 \1 f& o, Y+ A
R 类(Recovered),康复者,指病愈后具有免疫力的人。如果免疫期有限,仍可以重新变为 S 类成员,进而被感染;如果是终身免疫,则不能再变为 S类、E类或 I 类成员。 . `# X7 G% Y4 M y( h% x& \ 1 Q" s1 M: q( a1 R% ^/ V7 u1 j + `& \% c! B: Y r' y% O4 h常见的传染病模型按照传染病类型分为 SI、SIR、SIRS、SEIR 模型等,就是由以上四类人群根据不同传染病的特征进行组合而产生的不同模型。, y0 \) ^% ~, K% F' F- g; w
6 u) G% Y# d7 X" P m/ o1 B( ]6 e. c! M8 {: d1 c- E! o+ W
$ E" D4 D: @4 E0 `
8 Z# L4 z' r2 n( _& X' N
Python小白的数学建模课-A3.12个新冠疫情数模竞赛赛题及短评 " j) Z2 H& c" }1 Q3 p( T/ {1 k1 R- YPython小白的数学建模课-B2. 新冠疫情 SI模型4 p. ?- }( o: P# ]: s; y
Python小白的数学建模课-B3. 新冠疫情 SIS模型( \- V! Y2 K# t
Python小白的数学建模课-B4. 新冠疫情 SIR模型3 d3 I0 _% N) [" Z. f
Python小白的数学建模课-B5. 新冠疫情 SEIR模型 / M" T$ V. G( @Python小白的数学建模课-B6. 新冠疫情 SEIR改进模型- e* j; Q: Q3 v5 w0 c4 b) [3 a
Python数模笔记-PuLP库 ; W5 T6 m J) T; a1 P' S8 ~8 m- R1 Z1 D9 y$ r0 ^
1 S* R9 g4 }; b5 \$ [1 d. R6 {; B6 C
" ~, ]' @! o1 [5 d5 ]& G5 r* k 7 V! r6 s: n+ @" `2. 疫情传播 SI 模型0 j# R A. f3 [ K
2.1 SI 模型的适用范围 & T( Y( P+ v) rSI 模型适用于只有易感者和患病者两类人群,且无法治愈的疾病,例如 T型病、僵尸。 & J7 N0 K8 |4 k+ j1 z & h! C2 C- Y: o 7 I; @& r6 \; M) d% C0 |% L8 r2 T/ m. @$ V- M' K7 z5 E3 r
: O; Q; }7 J6 N7 h5 h$ k2.2 SI 模型的假设' m3 o# X. j% C7 p7 c" |
考察地区的总人数 N 不变,即不考虑生死或迁移;% E0 s1 \8 m. Q' ` |
人群分为易感者(S类)和患病者(I类)两类; * {- `. ~; _$ m* r% g# n2 Z" ?! N易感者(S类)与患病者(I类)有效接触即被感染,变为患病者,无潜伏期、无治愈情况、无免疫力; . Z' a* ?! i+ {6 J, b& z每个患病者每天有效接触的易感者的平均人数(日接触数)是 λ \lambdaλ,称为日接触率;! v0 R) |2 j; f$ C7 g1 ^& \
将第 t 天时 S类、I 类人群的占比记为 s ( t ) s(t)s(t)、i ( t ) i(t)i(t),数量为 S ( t ) S(t)S(t)、I ( t ) I(t)I(t);初始日期 t = 0 t=0t=0 时, S类、I 类人群占比的初值为 s 0 s_0s : f1 l9 ?& Z1 y; ~1 l+ \' s4 p0 4 h+ _; y3 R$ N8 @ : i; T. M3 _4 j' d
、i 0 i_0i ! ]* o3 k- P' F6 d' }' P
0 $ q5 H$ q5 s! X. c* u8 J. q+ G. F " g/ \! U5 j, S1 u
。 1 w5 z2 k& |& N' c6 U2.3 SI 模型的微分方程8 j6 s2 f( @4 A
由 ' Z9 b7 G" \0 [) jN d i d t = N λ s i N\frac{di}{dt} = N\lambda s i 8 s: J: Q4 W" X( cN 2 X' S, M- e3 R( |/ U' s; T) u
dt, H) r8 Z: x! N( u# o0 D# W P
di 2 y$ Q. i2 N/ E " u( C. a: w' F8 |& z3 h
=Nλsi $ j1 W. Y9 y$ ?1 R! d ; P3 ~9 Y4 y% D% f5 W ( \7 Q- j8 R- D得:2 d$ ^3 `3 N& t. f7 L
d i d t = λ i ( 1 − i ) , i ( 0 ) = i 0 \frac{di}{dt} = \lambda i (1-i),\ i(0) = i_0 . { P" a$ h! J% J8 ]dt V+ m% B9 ^* l) b, T- B
di # A, l! ?% ?0 ]1 Y: a : S m0 t. P! p2 b2 m" g, d! L
=λi(1−i), i(0)=i $ \) H4 D3 G6 g8 ^ m0$ ^0 }/ F6 c; {, W; ^ R/ S2 b4 A& j
* `6 _* D/ g; T+ s, w& v8 K% G * J4 b3 y0 a* X" `6 P4 _1 S/ x O. d
9 N. P0 Z/ A; a) [5 O ) m! W9 ~1 `7 S$ }; F* F8 s这是 Logistic 模型,用分离变量法可以求出其解析解为:0 X, m7 K+ |- ?
i ( t ) = 1 1 + ( 1 / i 0 − 1 ) e − λ t I ( t ) = N i ( t ) i(t)=\frac{1}{1+(1/i_0 - 1)\ e^{-\lambda t}}\\ I(t)= N\ i(t)5 V' Q; Z4 |3 F0 Y5 ?
i(t)= 6 K" J3 g3 c' z) r" l! s2 h1+(1/i ( W& [9 G7 q" Z" y4 Z( [0 * D2 X6 [; E4 B5 D $ P8 L$ o3 g. S# C4 ~& \, O- J- C k −1) e ) m+ d+ b$ i9 c/ ]% z8 Y−λt: Y, \& R3 e7 J" V: H7 V6 {
! p+ {. |$ k- S, d
1/ `6 l) W& T8 z/ g& K% s
# ]; `) S! @ R; n. S 7 F0 t2 U; m8 R) r$ |/ a% BI(t)=N i(t) 9 a* z9 t6 Y/ k+ j: y l; C! R: ?, i9 t! A, `8 O
% g7 _2 \6 t8 G' _, K; U$ o# E8 [& g. }1 Y" e/ Y% n8 b; i
" q. @. f m4 @; k! }3. SI 模型的 Python 编程 4 N' U/ z8 u3 Z( z7 _6 k3.1 SI 模型的解析解# `% b b3 W" ?, _$ F- X
上文已经得到 SI 模型的解析解,对此很容易通过 Python 编程实现,详见本文例程。 ! S% x- _% b" G. \" {, y7 q2 l* D ) J5 q3 r, l# X4 C. N+ b- s - i. V- p* U. I: n: c1 y# {虽然 SI 模型的解析解并不复杂,而且解的精度当然是最好的,但我们仍然不鼓励用解析解的方法。原因在于,一是对于小白求解析解的过程相对复杂困难,而且可能出错,二是对于更复杂的模型是没有解析解的,即便大神也只能用数值方法求解。既然如此,不如从一开始就学习、掌握数值求解方法,熟悉数值解法的编程实现。 ! c7 ?9 T/ `% m: y' Y- P" d( K3 \8 z3 @+ m4 C' }
% a5 |8 j8 ^0 u$ J2 n+ ]3.2 SI 模型的数值解3 K! T3 ~% |' {8 r, y$ k
SI 模型是常微分方程初值问题,可以使用 Scipy 工具包的 scipy.integrate.odeint() 函数求数值解,具体方法可以参考前文《Python小白的数学建模课-09 微分方程模型》。6 s- A7 h' A$ ^0 u0 d- F* E
" C$ x7 K+ x1 j% `- p8 c" X; N3 u " ?+ g2 s+ |" E% N. L# r5 b0 ascipy.integrate.odeint(func, y0, t, args=())0 m1 x1 f/ d8 l' `4 f; n0 ^. f
10 H0 j% A" d# A' y9 I
**scipy.integrate.odeint()**是求解微分方程的具体方法,通过数值积分来求解常微分方程组。 ' t; N- U5 r5 I7 n$ T3 C8 n# C' \3 d! B
* J$ _9 M) X3 M( W r: N
odeint() 的主要参数: " G" j6 W; ?2 X8 j* ?& u. d4 a, @' I- L: R
6 q" e) M: r1 r, P$ V% U1 Ofunc: callable(y, t, …) 导数函数 f ( y , t ) f(y,t)f(y,t) ,即 y 在 t 处的导数,以函数的形式表示7 u: p% S2 X, { t
y0: array: 初始条件 y 0 y_0y & F q) j8 h8 U! |1 j2 m, Z
0 : b. w n W- `3 \4 I T4 h! g+ p) X# U8 X7 `. m ,对于常微分方程组 y 0 y_0y $ R/ y5 @6 Q' V, ~- l1 l02 v6 i) z9 _+ ]4 ]- a5 y
, D1 [) a6 Q3 ]3 p- A 则为数组向量 " k# F; _0 E8 p) j& It: array: 求解函数值对应的时间点的序列。序列的第一个元素是与初始条件 y 0 y_0y . N9 I, T1 l& ]0 X5 |
0 & D: ~# j9 P/ |- ^; c " b' t+ y" \/ N a" X- }5 R5 i+ A( y 对应的初始时间 t 0 t_0t 7 b" B7 `6 ^5 \# [
0( `9 h/ @9 ]+ F1 _
* Y( H% ~ s8 Q7 z% B" S# H ;时间序列必须是单调递增或单调递减的,允许重复值。: H8 W/ L, L* h
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。 ; T- z- ^( p# v2 l- @- |; I+ modeint() 的返回值:& ], \' `9 N& B! y
: q2 Z; u$ l9 E0 w
5 ~2 M. x2 E+ O0 f5 z' b6 Fy: array 数组,形状为 (len(t),len(y0),给出时间序列 t 中每个时刻的 y 值。 4 @3 |3 h1 w; ~7 K: X% Yodeint() 的编程步骤:6 O+ l9 M+ ^8 x) {3 r6 M* L" ~: Z2 j- N
( F, X! @' }7 b" s F Q$ V ; E" [" X2 y% p) ?1 {! _) N c导入 scipy、numpy、matplotlib 包;9 t3 A6 B/ @( y& f3 T6 ^. b1 M( W
定义导数函数 f ( i , t ) = λ i ( 1 − i ) f(i,t)=\lambda i (1-i)f(i,t)=λi(1−i) ; & C. i/ j2 |' v$ [+ R' g# o定义初值 i 0 i_0i & S8 o8 x& L! C& D
0 % g3 f4 W1 o+ C, w( Z 5 j% Y3 w$ G: l+ k9 ? 和 i ii 的定义区间 [ t 0 , t ] [t_0,\ t][t 3 n) R# G6 ?4 M( d$ y( C0 H" U0, N3 S. S' e$ m
3 K0 Y. f# G% z8 Z" c! ~
, t];# r4 E% ] q1 \3 E
调用 odeint() 求 i ii 在定义区间 [ t 0 , t ] [t_0,\ t][t , W- ]1 r- U" Y5 m; _" D. D
0 3 Z& G+ J+ |( ~6 [4 u& I / x1 ]0 E: Z. q , t] 的数值解。 - M3 Z, `0 U# x3 j& b 1 ^9 n! E- y: N4 G& e" t 9 e( z% F9 I: M3.3 Python例程:SI 模型的解析解与数值解! T+ g( x3 m! j/ {( a# k0 w n
# 1. SI 模型,常微分非常,解析解与数值解的比较; _: v) E( Y2 u; {/ \
from scipy.integrate import odeint # 导入 scipy.integrate 模块$ ], P2 u; }, A0 F% V5 A+ b% V& _8 }
import numpy as np # 导入 numpy包 . E# Q _; X0 T. y$ n7 qimport matplotlib.pyplot as plt # 导入 matplotlib包 2 p- n8 M6 ~4 U# m- G/ r0 C" { " Z$ v/ r, j& g* R" U5 Y* R) M* E2 }1 L1 v2 V0 N y' n
def dy_dt(y, t, lamda, mu): # 定义导数函数 f(y,t) : S7 b7 ^/ D* y0 `. H' C8 M5 L6 \ dy_dt = lamda*y*(1-y) # di/dt = lamda*i*(1-i) 5 `( E" N! R: }6 B/ M3 ^ return dy_dt , o0 T& N8 K' W' W [: F L( |1 Q 9 J F/ F" w) p% X1 p' ?" w* X0 V, A; X7 S1 _3 g% H9 P7 e
# 设置模型参数/ c# O1 P8 k: s8 N
number = 1e7 # 总人数4 |0 _9 V0 l% c' T# y* W
lamda = 1.0 # 日接触率, 患病者每天有效接触的易感者的平均人数6 i( r/ |7 g0 f# ~
mu1 = 0.5 # 日治愈率, 每天被治愈的患病者人数占患病者总数的比例 ' ]# r6 {$ e. B \5 H2 x Ly0 = i0 = 1e-6 # 患病者比例的初值 : Z- M3 ^# J( S3 D+ qtEnd = 50 # 预测日期长度 1 p( Y: n+ U+ zt = np.arange(0.0,tEnd,1) # (start,stop,step) , I. e9 z6 y( P; [* v( w5 {. c3 C+ u
& r7 ~1 W ?& _& n
yAnaly = 1/(1+(1/i0-1)*np.exp(-lamda*t)) # 微分方程的解析解8 p8 X* B3 W4 y, s
yInteg = odeint(dy_dt, y0, t, args=(lamda,mu1)) # 求解微分方程初值问题 " X% E) f- P+ r( `: i# t- yyDeriv = lamda * yInteg *(1-yInteg)2 w9 ^7 `2 Q# n# b7 I1 V% Q
8 @' S& i! a& ]; V/ y" k$ c5 Y& V F& K' G7 U
# 绘图3 q# u9 [5 r( ?' k7 M4 W% m2 _
plt.plot(t, yAnaly, '-ob', label='analytic')8 {/ K8 W: ^, z
plt.plot(t, yInteg, ':.r', label='numerical')2 Z; p' L# k+ c/ N
plt.plot(t, yDeriv, '-g', label='dy_dt') & m8 r( L) n$ iplt.title("Comparison between analytic and numerical solutions")% f7 ~/ g8 M ]+ @" s
plt.legend(loc='right')9 J6 {; i8 z( o+ C; c" Q& ~+ m4 k' S
plt.axis([0, 50, -0.1, 1.1])2 K' b" K+ g9 L5 o8 x& ~6 ~
plt.show() $ G. {3 A3 a5 C# k+ `1 }9 j9 {- I' m9 p# P9 c3 _
2 O0 G4 M9 A; t3 , G, I0 T3 Y8 y9 i2 z3 v3 H4 ( R; b# J* G8 Y7 C0 H [ v5 + g* Y& i, |% B: \* ]$ o D5 M6 - i, f3 Q7 j, m: w* R3 S7- D# p! u5 a# A1 C
8 u( j, b r2 S3 N0 N. w4 R
9 : j" A* `) `4 S9 s2 F3 K10# {7 u! v0 E0 {4 |. T2 X5 t3 ~+ Y b* h
11 - s/ `6 p d$ u9 o2 Z12 ' u9 x- v5 ^# _; X7 Z4 H4 q13 - }" s3 k# G: O9 ]1 W# j14: a) W7 j) E% z2 h8 d
15 8 f/ i* I& x( r3 |& L$ A- o16 + a5 ]) t' D3 _17% k* @/ b) g3 }3 u, Y; i- ^
18 7 H# J: Z( n: `4 A- V. O1 i1 j# k19/ d% i9 p: y8 b6 R& K6 ^
20/ r9 o( r) x; `- F S. y! p+ X, h, F
21+ D$ p; t4 c, ?7 g5 n! X0 ?6 C. ~
22 5 ?) Z* \5 c! _- K% F0 K( G23; z8 M7 o: ^7 D* t* N2 X
24 ' j p7 [2 b0 G* Q E1 _/ G s" U25# f& t/ G' C8 L3 X- Q( s' s
269 d" ]+ l5 Z x, U2 t1 S
27 7 p6 c# l9 E8 z0 M- l! F280 A& l/ T: z8 C' G* X
29- D7 k5 ~6 T+ v9 H. ^
4 b+ @( }0 s4 g/ r$ l& l& N7 k: M) N7 X" H- g
3.4 解析解与数值解的比较 6 F; k* ^' O @# M- @% n7 p, O3 m7 N 5 |5 n' ]. D' i: S( h% m l) T: J& s" i& ?( m6 X
本图为例程 2.3 的运行结果,图中对解析解(蓝色)与使用 odeint() 得到的数值解(红色)进行比较。在该例中,无法观察到解析解与数值解的差异,表明数值解的误差很小。 + K, M$ y7 C- t. e 3 F7 {5 [- r6 M" c , \8 M/ S' O; J" Z0 T图中 d i / d t di/dtdi/dt 具有最大值,最大值表示疫情增长的高潮,达到最大值后 d i / d t di/dtdi/dt 逐渐减小,但患病者比例很快增长到 100%,表明所有人都被感染成为患者。0 z+ u6 G2 E( Q6 w" m
_6 N: Q$ x) e' w! W, i
9 x1 `" o; v1 F2 \% P! n i这是特定参数的结果,还是模型的必然趋势,需要对参数的影响进行更详细的研究。; i* U- X2 x1 u2 r1 s% _& J; d
0 {5 ~ B' g/ Q9 p0 {9 f! J- O( Q
8 x! { n" U7 }# H: [: ^6 B% b; [7 v8 y( Z
4. SI 模型参数的影响9 V* S$ f3 a- _) `" `8 d0 x
对于 SI 模型,只有日接触率 λ \lambdaλ 和患病者比例的初值 i 0 i_0i 7 [" n# o! i' o7 {- g6 M0 & X/ W% a8 J+ D |: r: Z8 S N + R8 u/ c1 S( N/ [' {, C; U
会影响模型的结果,其它参数如总人数 N 并没有影响。2 I/ Z1 Y" ^/ x' F' r
G b& O6 k' J" ?: G1 R! w h3 n
4.1 日接触率对 SI 模型的影响5 H' A! n j; M' \8 ]# j
& k& `# y: P) H! u' J