Python-Simulation of the Epidemic Model (Kermack-McKendrick Model)

Epidemic

Quote: https://kotobank.jp/word/%E3%82%A8%E3%83%94%E3%83%87%E3%83%9F%E3%83%83%E3%82%AF-683127

> Epidemic In medical and public health, people with a certain disease make normal predictions in a certain area or population.
> Exceeding a large amount. An infectious disease such as influenza is prevalent in a specific area.
> The state in which this occurs simultaneously in various parts of the world is called a pandemic.

Kermack-McKendrick model

http://mathworld.wolfram.com/Kermack-McKendrickModel.html

A model that represents changes in the number of people infected with infectious diseases in a closed population. Hereinafter, it is represented by simultaneous differential equations.

\begin{eqnarray}
\frac{dx(x)}{dt}&=&-kx(t)y(t)\\
\frac{dy(t)}{dt}&=&kx(t)y(t)-ly(t)\\
\frac{dz(t)}{dt}&=&ly(t)
\end{eqnarray}

$ x (t) ≥0 $: number of healthy people, $ y (t) ≥0 $: number of sick people, $ z (t) ≥0 $: number of recovered people, $ k ≥0 $ : Infection rate, $ l ≥ 0 $: Recovery rate

As an interpretation ・ Set 1: The rate of change in the number of healthy people $ x $ is proportional to the number of healthy people x the number of sick people. The proportional coefficient is $ -k $. Since $ k, x, y ≥ 0 $, the number of healthy people will not increase. If the number of sick people becomes 0, the number of healthy people will be kept constant. ・ Type 2: The rate of change in the number of sick people $ y $ is determined by the rate of change in the number of healthy people and the contribution of the number of sick people. The greater the rate of change in the number of healthy people or the greater the number of sick people, the lower the rate of change in the number of sick people. If the sign of $ kx (t) -l $ is positive, the number of sick people will increase, and if it is negative, it will decrease. ・ Formula 3: The rate of change in the number of people who have recovered $ z $ is proportional to the number of sick people. The constant of proportionality is $ l $. The more sick people there are, the faster the number of people who recover will increase.

Fixed point

\begin{eqnarray}
\frac{dx(x)}{dt}&=&-kx(t)y(t)=0…①\\
\frac{dy(t)}{dt}&=&kx(t)y(t)-ly(t)=0…②\\
\frac{dz(t)}{dt}&=&ly(t)=0…③
\end{eqnarray}

The point that becomes.

From ② $ x $ = $ \ frac {l} {k} $ From ① and ③ $ y = 0 $

Conserved quantity

\begin{eqnarray}
\frac{dx(x)}{dy(t)}&=&\frac{-kx(t)y(t)}{kx(t)y(t)-ly(t)}\\
&=&\frac{-kx(t)}{kx(t)-l}\\
(\frac{l}{k}\frac{1}{x}-1)dx(t)&=&dy(t)\\
\int{(\frac{l}{k}\frac{1}{x}-1)dx(t)}&=&\int{dy(t)}\\
\frac{l}{k}logx(t)-x(t)&=&y(t)+E
\end{eqnarray}

$ \ Frac {l} {k} logx (t) -x (t) -y (t) $ is the conserved quantity (it takes a constant value even if the time changes).

Simulation by numerical calculation

Method of calculation

http://qiita.com/popondeli/items/391810fd727cefb190e7 The Runge-Kutta method described in is extended and used for simultaneous differential equations.

·Source code

import numpy as np
import matplotlib.pyplot as plt
import math

k = 1.0
l = 1.0

DELTA_T = 0.001
MAX_T = 100.0

def dx(x, y, z, t):
    return -k * x * y
    
def dy(x, y, z, t):
    return k * x * y - l * y
    
def dz(x, y, z, t):
    return l * y
    
def calc_conceved_quantity(x, y, z, t):
    return (l/k)*math.log(x) - x - y
    
def runge_kutta(init_x, init_y, init_z, init_t):
    x, y, z, t = init_x, init_y, init_z, init_t
    history = [[x, y, z, t, calc_conceved_quantity(x, y, z, t)]]
    cnt = 0
    while t < MAX_T:
        cnt += 1
        k1_x = DELTA_T*dx(x, y, z, t)
        k1_y = DELTA_T*dy(x, y, z, t)
        k1_z = DELTA_T*dz(x, y, z, t)
        
        k2_x = DELTA_T*dx(x + k1_x/2, y + k1_y/2, z + k1_z/2, t + DELTA_T/2)
        k2_y = DELTA_T*dy(x + k1_x/2, y + k1_y/2, z + k1_z/2, t + DELTA_T/2)
        k2_z = DELTA_T*dz(x + k1_x/2, y + k1_y/2, z + k1_z/2, t + DELTA_T/2)
        
        k3_x = DELTA_T*dx(x + k2_x/2, y + k2_y/2, z + k2_z/2, t + DELTA_T/2)
        k3_y = DELTA_T*dy(x + k2_x/2, y + k2_y/2, z + k2_z/2, t + DELTA_T/2)
        k3_z = DELTA_T*dz(x + k2_x/2, y + k2_y/2, z + k2_z/2, t + DELTA_T/2)
        
        k4_x = DELTA_T*dx(x + k3_x, y + k3_y, z + k3_z, t + DELTA_T)
        k4_y = DELTA_T*dy(x + k3_x, y + k3_y, z + k3_z, t + DELTA_T)
        k4_z = DELTA_T*dz(x + k3_x, y + k3_y, z + k3_z, t + DELTA_T)
        
        x += (k1_x + 2*k2_x + 2*k3_x + k4_x)/6
        y += (k1_y + 2*k2_y + 2*k3_y + k4_y)/6
        z += (k1_z + 2*k2_z + 2*k3_z + k4_z)/6
        t += DELTA_T
        x = max(0, x)
        y = max(0, y)
        z = max(0, z)
        if cnt % 100 == 0:
            history.append([x, y, z, t, calc_conceved_quantity(x, y, z, t)])
    return history
    
if __name__ == '__main__':
    #Numerical calculation by Runge-Kutta method
    history = np.array(runge_kutta(init_x = 1, init_y = 0.1, init_z = 0, init_t = 0))
    
    x_min, x_max = min(history[:,0]), max(history[:,0])
    y_min, y_max = min(history[:,1]), max(history[:,1])
    z_min, z_max = min(history[:,2]), max(history[:,2])
    t_min, t_max = 0, MAX_T
    
    #Plot x vs y phase diagram
    plt.subplot(4, 1, 1)
    plt.title("x vs y")
    plt.xlim(x_min, x_max)
    plt.ylim(y_min, y_max)
    plt.scatter(history[:,0], history[:,1])
    
    # x(Number of healthy people)Plot the time change of
    plt.subplot(4, 1, 2)
    plt.title("t vs x")
    plt.xlim(t_min, t_max)
    plt.ylim(0, x_max)
    plt.scatter(history[:,3], history[:,0])
    
    # y(Number of sick people)Plot the time change of
    plt.subplot(4, 1, 3)
    plt.title("t vs y")
    plt.xlim(t_min, t_max)
    plt.ylim(0, y_max)
    plt.scatter(history[:,3], history[:,1])
    
    #Plot the time change of the conserved quantity
    plt.subplot(4, 1, 4)
    plt.title(u"t vs conserved quantity")
    plt.xlim(t_min, t_max)
    plt.scatter(history[:,3], history[:,4])
    plt.show()

$ k $ and $ l $ are 1.0.

figure_1-1.png

Results due to differences in x and y initial values

X vs y phase diagram when the simulation is repeated 100 times with the initial values of $ x and y $ given a random value from 0 to 1.

Source code

import numpy as np
import matplotlib.pyplot as plt
import math
import random

k = 1.0
l = 1.0

DELTA_T = 0.001
MAX_T = 100.0

def dx(x, y, z, t):
    return -k * x * y
    
def dy(x, y, z, t):
    return k * x * y - l * y
    
def dz(x, y, z, t):
    return l * y
    
def calc_conceved_quantity(x, y, z, t):
    return (l/k)*math.log(x) - x - y
    
def runge_kutta(init_x, init_y, init_z, init_t):
    x, y, z, t = init_x, init_y, init_z, init_t
    history = [[x, y, z, t, calc_conceved_quantity(x, y, z, t)]]
    cnt = 0
    while t < MAX_T:
        cnt += 1
        k1_x = DELTA_T*dx(x, y, z, t)
        k1_y = DELTA_T*dy(x, y, z, t)
        k1_z = DELTA_T*dz(x, y, z, t)
        
        k2_x = DELTA_T*dx(x + k1_x/2, y + k1_y/2, z + k1_z/2, t + DELTA_T/2)
        k2_y = DELTA_T*dy(x + k1_x/2, y + k1_y/2, z + k1_z/2, t + DELTA_T/2)
        k2_z = DELTA_T*dz(x + k1_x/2, y + k1_y/2, z + k1_z/2, t + DELTA_T/2)
        
        k3_x = DELTA_T*dx(x + k2_x/2, y + k2_y/2, z + k2_z/2, t + DELTA_T/2)
        k3_y = DELTA_T*dy(x + k2_x/2, y + k2_y/2, z + k2_z/2, t + DELTA_T/2)
        k3_z = DELTA_T*dz(x + k2_x/2, y + k2_y/2, z + k2_z/2, t + DELTA_T/2)
        
        k4_x = DELTA_T*dx(x + k3_x, y + k3_y, z + k3_z, t + DELTA_T)
        k4_y = DELTA_T*dy(x + k3_x, y + k3_y, z + k3_z, t + DELTA_T)
        k4_z = DELTA_T*dz(x + k3_x, y + k3_y, z + k3_z, t + DELTA_T)
        
        x += (k1_x + 2*k2_x + 2*k3_x + k4_x)/6
        y += (k1_y + 2*k2_y + 2*k3_y + k4_y)/6
        z += (k1_z + 2*k2_z + 2*k3_z + k4_z)/6
        t += DELTA_T
        x = max(0, x)
        y = max(0, y)
        z = max(0, z)
        if cnt % 100 == 0:
            history.append([x, y, z, t, calc_conceved_quantity(x, y, z, t)])
    return history
    
if __name__ == '__main__':

    for i in range(0, 100):
        init_x = random.random()
        init_y = random.random()
    
        #Numerical calculation by Runge-Kutta method
        history = np.array(runge_kutta(init_x, init_y, init_z = 0, init_t = 0))
        
        x_min, x_max = min(history[:,0]), max(history[:,0])
        y_min, y_max = min(history[:,1]), max(history[:,1])
        z_min, z_max = min(history[:,2]), max(history[:,2])
        t_min, t_max = 0, MAX_T
        
        #Plot x vs y phase diagram
        plt.title("x vs y")
        plt.xlim(0, 1)
        plt.ylim(0, 1)
        plt.scatter(history[:,0], history[:,1])
    plt.show()

figure_1-2.png

While drawing a curve, it falls to $ y = 0 $ (= number of infected people 0).

Results due to differences in parameters k and l (infection rate, recovery rate)

Higher recovery rate

l = 3.0k = 1.0

figure_1-3_l-3.png

The fall to $ y = 0 $ becomes steep

Increased infection rate

l = 1.0k = 5.0

figure_1-4_k-5.png

Once infected, the number of infected people increases and decreases to 0.

Recommended Posts

Python-Simulation of the Epidemic Model (Kermack-McKendrick Model)
Reading comprehension of "The Go Memory Model"
GUI simulation of the new coronavirus (SEIR model)
Specify the lighting Model of SCN Material in Pythonista
The meaning of self
Count the number of parameters in the deep learning model
the zen of Python
The story of sys.path.append ()
Revenge of the Types: Revenge of types
Try to evaluate the performance of machine learning / regression model
I tried refactoring the CNN model of TensorFlow using TF-Slim
Implement the mathematical model "SIR model" of infectious diseases with OpenModelica
The story of a Django model field disappearing from a class
I made a function to check the model of DCGAN
Analyze the topic model of becoming a novelist with GensimPy3
Align the version of chromedriver_binary
Scraping the result of "Schedule-kun"
10. Counting the number of lines
Towards the retirement of Python2
Benefits of refining Django's Model
Get the number of digits
Explain the code of Tensorflow_in_ROS
Reuse the results of clustering
GoPiGo3 of the old man
Calculate the number of changes
Change the theme of Jupyter
The popularity of programming languages
Change the style of matplotlib
Calibrate the model with PyCaret
Visualize the orbit of Hayabusa2
About the components of Luigi
Connected components of the graph
Filter the output of tracemalloc
About the features of Python
Simulation of the contents of the wallet
The Power of Pandas: Python
I want to manually assign the training parameters of the [Pytorch] model
Translated the explanation of the upper model of kaggle's brain wave detection competition
[Django] Correct the plural form of the model name on the management screen
Try to model the cumulative return of rollovers in futures trading
[Translation] scikit-learn 0.18 User Guide 3.3. Model evaluation: Quantify the quality of prediction
Evaluate the performance of a simple regression model using LeaveOneOut cross-validation
[Introduction to SIR model] Consider the fitting result of Diamond Princess ♬
Evaluate the accuracy of the learning model by cross-validation from scikit learn