正确实现SI,SIS,SIR模型(python)

时间:2017-11-18 13:36:36

标签: python math modeling

我已经创建了上述模型的一些非常基本的实现。然而,虽然图表似乎看起来正确,但数字并不是常数。这是因为每个隔间中的易感/感染/恢复的人的总和应该加起来为N(这是总人数),但它不会,因为某种原因它会加起来一些奇怪的十进制数,并且现在看了3天后,我真的不知道如何解决它。

SI模型:

import matplotlib.pyplot as plt

N = 1000000
S = N - 1
I = 1
beta = 0.6

sus = [] # infected compartment
inf = [] # susceptible compartment
prob = [] # probability of infection at time t

def infection(S, I, N):
    t = 0
    while (t < 100):
        S = S - beta * ((S * I / N))
        I = I + beta * ((S * I) / N)
        p = beta * (I / N)

        sus.append(S)
        inf.append(I)
        prob.append(p)
        t = t + 1

infection(S, I, N)
figure = plt.figure()
figure.canvas.set_window_title('SI model')

figure.add_subplot(211)
inf_line, =plt.plot(inf, label='I(t)')

sus_line, = plt.plot(sus, label='S(t)')
plt.legend(handles=[inf_line, sus_line])

plt.ticklabel_format(style='sci', axis='y', scilimits=(0,0)) # use scientific notation

ax = figure.add_subplot(212)
prob_line = plt.plot(prob, label='p(t)')
plt.legend(handles=prob_line)

type(ax)  # matplotlib.axes._subplots.AxesSubplot

# manipulate
vals = ax.get_yticks()
ax.set_yticklabels(['{:3.2f}%'.format(x*100) for x in vals])

plt.xlabel('T')
plt.ylabel('p')

plt.show()

SIS模型:

import matplotlib.pylab as plt

N = 1000000
S = N - 1
I = 1
beta = 0.3
gamma = 0.1

sus = \[\]
inf = \[\]

def infection(S, I, N):
    for t in range (0, 1000):
        S = S - (beta*S*I/N) + gamma * I
        I = I + (beta*S*I/N) - gamma * I

        sus.append(S)
        inf.append(I)


infection(S, I, N)

figure = plt.figure()
figure.canvas.set_window_title('SIS model')

inf_line, =plt.plot(inf, label='I(t)')

sus_line, = plt.plot(sus, label='S(t)')
plt.legend(handles=\[inf_line, sus_line\])

plt.ticklabel_format(style='sci', axis='y', scilimits=(0,0))

plt.xlabel('T')
plt.ylabel('N')

plt.show()

SIR模型:

import matplotlib.pylab as plt

N = 1000000
S = N - 1
I = 1
R = 0
beta = 0.5
mu = 0.1

sus = []
inf = []
rec = []

def infection(S, I, R, N):
    for t in range (1, 100):
        S = S -(beta * S * I)/N
        I = I + ((beta * S * I)/N) - R
        R = mu * I

        sus.append(S)
        inf.append(I)
        rec.append(R)

infection(S, I, R, N)

figure = plt.figure()
figure.canvas.set_window_title('SIR model')

inf_line, =plt.plot(inf, label='I(t)')

sus_line, = plt.plot(sus, label='S(t)')

rec_line, = plt.plot(rec, label='R(t)')
plt.legend(handles=[inf_line, sus_line, rec_line])

plt.ticklabel_format(style='sci', axis='y', scilimits=(0,0))

plt.xlabel('T')
plt.ylabel('N')


plt.show()

2 个答案:

答案 0 :(得分:1)

我只会看SI模型。

您的两个关键变量是SI。 (你可能已经颠倒了这两个变量的含义,虽然这不会影响我在这里写的内容。)你初始化它们使它们的总和为N,这是常数1000000

您可以更新

行中的两个关键变量
S = S - beta * ((S * I / N))
I = I + beta * ((S * I) / N)

您显然打算添加到I并从S减去相同的值,因此SI的总和不变。但是,您实际上首先更改S然后使用该新值更改I,因此添加和减去的值实际上并不相同,并且变量的总和不会保持不变。

您可以使用Python在一行中更新多个变量的功能来解决此问题。用

替换这两行
S, I = S - beta * ((S * I / N)), I + beta * ((S * I) / N)

这会在更新变量之前计算两个新值,因此实际添加的值和从两个变量中减去的值相同。 (还有其他方法可以获得相同的效果,例如更新值的临时变量,或者一个临时变量来存储添加和减去的数量,但是因为你使用Python,你也可以使用它的功能。)

当我现在运行程序时,我得到了这些图表:

enter image description here

我认为这就是你想要的。

答案 1 :(得分:1)

因此上述解决方案也适用于SIS模型。

对于SIR模型,我必须使用odeint求解微分方程,这是SIR模型的简单解决方案:

import matplotlib.pylab as plt
from scipy.integrate import odeint
import numpy as np

N = 1000
S = N - 1
I = 1
R = 0
beta = 0.6 # infection rate
gamma = 0.2 # recovery rate

# differential equatinons
def diff(sir, t):
    # sir[0] - S, sir[1] - I, sir[2] - R
    dsdt = - (beta * sir[0] * sir[1])/N
    didt = (beta * sir[0] * sir[1])/N - gamma * sir[1]
    drdt = gamma * sir[1]
    print (dsdt + didt + drdt)
    dsirdt = [dsdt, didt, drdt]
    return dsirdt


# initial conditions
sir0 = (S, I, R)

# time points
t = np.linspace(0, 100)

# solve ODE
# the parameters are, the equations, initial conditions, 
# and time steps (between 0 and 100)
sir = odeint(diff, sir0, t)

plt.plot(t, sir[:, 0], label='S(t)')
plt.plot(t, sir[:, 1], label='I(t)')
plt.plot(t, sir[:, 2], label='R(t)')

plt.legend()

plt.xlabel('T')
plt.ylabel('N')

# use scientific notation
plt.ticklabel_format(style='sci', axis='y', scilimits=(0,0))

plt.show()