(しばらく工事中)
とりあえず、以前書いたメモ 「Pythonでode」 にリンクを張っておく。
scipy のodeint() は、定評のある ODEPACK を利用しているそうである。
| testsir2.py |
# testsir2.py
#
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
# x=(S,I,R)
def sir(x, t, R0):
return [-R0*x[0]*x[1], R0*x[0]*x[1]-x[1], x[1]]
R0=2.5
I0=0.001
x0=[1.0-I0,I0,0.0]
n=1000
t=np.linspace(0.0, 20.0, n+1)
x=odeint(sir, x0, t, args=(R0,))
plt.plot(t,x[:,0],'b', label='S')
plt.plot(t,x[:,1],'g', label='I')
plt.plot(t,x[:,2],'r', label='R')
plt.legend(loc='best')
plt.xlabel('t')
plt.grid()
plt.show()
|
簡単に書けるのは嬉しい。ついでにSI平面上で解の軌道を描いてみる。
| testsir3.py |
# testsir3.py --- SIR model
# coding: utf-8
#
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
# x=(S,I,R)
def sir(x, t, R0):
return [-R0*x[0]*x[1], R0*x[0]*x[1]-x[1], x[1]]
R0=2.5
I0=0.001
x0=[1.0-I0,I0,0.0]
n=1000
t=np.linspace(0.0, 20.0, n+1)
x=odeint(sir, x0, t, args=(R0,))
plt.figure(figsize=(10,5))
plt.subplot(121)
plt.plot(t,x[:,0],'b', label='S')
plt.plot(t,x[:,1],'g', label='I')
plt.plot(t,x[:,2],'r', label='R')
plt.legend(loc='best')
plt.xlabel('t')
plt.grid()
plt.subplot(122)
plt.xlim(0.0,1.0)
plt.plot(x[:,0],x[:,1],'k',label='S&I')
plt.legend(loc='best')
plt.xlabel('S')
plt.ylabel('I')
plt.show()
|
新しく用意した、 という scipy.integrate.solve_ivp を利用するプログラムは、 以下のようになる。
| testsir4.py |
# testsir4.py --- SIR model
# coding: utf-8
#
import numpy as np
from scipy.integrate import solve_ivp
import matplotlib.pyplot as plt
# x=(S,I,R)
def sir(t, x, R0):
return [-R0*x[0]*x[1], R0*x[0]*x[1]-x[1], x[1]]
R0=2.5
I0=0.001
x0=[1.0-I0,I0,0.0]
T=20.0
sol=solve_ivp(sir, [0.0, T], x0, args=(R0,),
dense_output=True, rtol=1e-10,atol=1e-10)
n=1000
t=np.linspace(0.0, T, n+1)
x = sol.sol(t)
plt.figure(figsize=(10,5))
plt.subplot(121)
plt.plot(t,x.T)
plt.xlabel('t')
plt.legend(['S', 'I', 'R'], shadow=True)
plt.title('SIR model (t-S,I,R)')
plt.subplot(122)
plt.xlim(0.0,1.0)
plt.plot(x[0], x[1], "-")
plt.xlabel("S")
plt.ylabel("I")
plt.title("SIR")
plt.show()
|
sir() の引数の順番は odeint() のときとは変える必要がある。 dense_output=True, rtol=1e-10,atol=1e-10 のあたりは、実は見様見真似で、 どうするべきか、まだよく理解していない。
そうだ、流行曲線というのも描いてみよう。
これは新規感染者数の時間経過を表すものである。
, つまり
を描けば良い。
| testsir5.py |
# testsir5.py --- SIR model
# coding: utf-8
#
import numpy as np
from scipy.integrate import solve_ivp
import matplotlib.pyplot as plt
# x=(S,I,R)
def sir(t, x, R0):
return [-R0*x[0]*x[1], R0*x[0]*x[1]-x[1], x[1]]
R0=2.5
I0=0.001
x0=[1.0-I0,I0,0.0]
T=20.0
sol=solve_ivp(sir, [0.0, T], x0, args=(R0,),
dense_output=True, rtol=1e-10,atol=1e-10)
n=1000
t=np.linspace(0.0, T, n+1)
x = sol.sol(t)
plt.figure(figsize=(15,5))
plt.subplot(131)
plt.plot(t,x.T)
plt.xlabel('t')
plt.legend(['S', 'I', 'R'], shadow=True)
plt.title('SIR model (t-S,I,R)')
plt.subplot(132)
plt.xlim(0.0,1.0)
plt.plot(x[0], x[1], "-")
plt.xlabel("S")
plt.ylabel("I")
plt.title("orbit in SI-plane")
plt.subplot(133)
plt.plot(t,R0*x[0]*x[1],"-")
plt.xlabel('t')
plt.ylabel('-DS/Dt')
plt.title("Epidemic curve")
plt.show()
|
古い Python 環境しかインストールしていなくて、 solve_ivp() が使えない人が、結構大勢いることに気づいた (何か勧めるときは、アップデートの仕方を教えてあげるべきだ)。 ともあれ、odeint() で上と同じことをするには、 次のようなプログラムを使えば良い。
| testsir5b.py |
# testsir5b.py --- SIR model
# coding: utf-8
#
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
# x=(S,I,R)
def sir(x, t, R0):
return [-R0*x[0]*x[1], R0*x[0]*x[1]-x[1], x[1]]
R0=2.5
I0=0.001
x0=[1.0-I0,I0,0.0]
n=1000
t=np.linspace(0.0, 20.0, n+1)
x=odeint(sir, x0, t, args=(R0,))
plt.figure(figsize=(15,5))
plt.subplot(131)
plt.plot(t,x[:,0],'b', label='S')
plt.plot(t,x[:,1],'g', label='I')
plt.plot(t,x[:,2],'r', label='R')
plt.legend(loc='best')
plt.xlabel('t')
plt.title('SIR model (t-S,I,R)')
plt.grid()
plt.subplot(132)
plt.xlim(0.0,1.0)
plt.plot(x[:,0],x[:,1],'k',label='S&I')
plt.legend(loc='best')
plt.xlabel('S')
plt.ylabel('I')
plt.title("orbit in SI-plane")
plt.subplot(133)
plt.plot(t,R0*x[:,0]*x[:,1],'b', label='S')
plt.xlabel('t')
plt.ylabel('-DS/Dt')
plt.title("Epidemic curve")
plt.show()
|
ついでに3次元相空間での軌道も描いてみる。
| testsir6.py |
# testsir6.py --- SIR model
# coding: utf-8
#
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
# x=(S,I,R)
def sir(x, t, R0):
return [-R0*x[0]*x[1], R0*x[0]*x[1]-x[1], x[1]]
#
R0=2.5
I0=0.001
x0=[1.0-I0,I0,0.0]
n=1000
t=np.linspace(0.0, 20.0, n+1)
x=odeint(sir, x0, t, args=(R0,))
fig=plt.figure(figsize=(20,5))
# S,I,Rの時間変化
plt.subplot(141)
plt.plot(t,x[:,0],'b', label='S')
plt.plot(t,x[:,1],'g', label='I')
plt.plot(t,x[:,2],'r', label='R')
plt.legend(loc='best')
plt.xlabel('t')
plt.title('SIR model (t-S,I,R)')
plt.grid()
# SI平面での軌道
plt.subplot(142)
plt.xlim(0.0,1.0)
plt.plot(x[:,0],x[:,1],'k',label='S&I')
plt.legend(loc='best')
plt.xlabel('S')
plt.ylabel('I')
plt.title("orbit in SI-plane")
# 流行曲線
plt.subplot(143)
plt.plot(t,R0*x[:,0]*x[:,1],'b', label='S')
plt.xlabel('t')
plt.ylabel('-DS/Dt')
plt.title("Epidemic curve")
# SIR空間での軌道
# 3DAxesを追加
ax = fig.add_subplot(144, projection='3d')
# 軸ラベルを設定
ax.set_xlabel("$S$")
ax.set_ylabel("$I$")
ax.set_zlabel("$R$")
#曲線を描画
ax.plot(x[:, 0], x[:, 1], x[:, 2])
plt.title("orbit in SIR-space")
plt.show()
|