[PYTHON] J'ai essayé de prédire le nombre de personnes infectées au niveau national de la nouvelle corona avec un modèle mathématique

Aperçu

J'ai trouvé l'article de The Lancet [^ 1], qui prédit le nombre de personnes infectées avec un modèle mathématique, alors j'ai implémenté un modèle mathématique pour prédire le nombre de personnes infectées au Japon et je l'ai comparé à d'autres maladies infectieuses.

Résumé

table des matières

  1. [Objectif de cette fois](# 1-Objectif de cette fois)
  2. [Modèle mathématique des maladies infectieuses](# 2-Modèle mathématique des maladies infectieuses)
  3. [Estimation des paramètres](# 3-Estimation des paramètres)
  4. [Implémenté et illustré en python](# 4-Implémenté et illustré en python)
  5. [Supplément](# 5-Supplément)

1. Objet de cette période

  1. Prédire le nombre de futures infections domestiques du nouveau virus corona (COVID-19, ci-après dénommé le nouveau corona) à l'aide d'un modèle mathématique.

  2. Comparez les nombres de reproduction de base de la nouvelle couronne avec d'autres maladies infectieuses.

  3. Mise en œuvre de calculs scientifiques avec Scipy.

2. Modèle mathématique des maladies infectieuses

"Formulez le processus de propagation d'une maladie infectieuse, la durée pendant laquelle une personne infectée se développe et devient grave." [^ 2]

Dans le modèle actuariel des maladies infectieuses, la population est divisée selon le stade de l'infection, et l'augmentation ou la diminution de chaque groupe est exprimée par une équation différentielle. Je vais vous expliquer le modèle SEIR simple et la version étendue utilisée cette fois.

2.1. Modèle SEIR

Ensuite, les équations différentielles simultanées suivantes sont obtenues.

\begin{align}
\frac{dS(t)}{dt} &= -\beta \frac{I(t)}{N}S(t) \\

\frac{dE(t)}{dt} &= \beta \frac{I(t)}{N}S(t) - \sigma E(t) \\

\frac{dI(t)}{dt} &= \sigma E(t) - \gamma I(t) \\

\frac{dR(t)}{dt} &= \gamma I(t) \\

N &= S(t) + E(t) + I(t) + R(t)
\end{align}

Cependant, il ignore le taux de natalité et le taux de mortalité, et dit qu'il ne sera plus jamais infecté car il se rétablira et acquiert une immunité après le début.

Si vous donnez une valeur initiale appropriée et que vous la résolvez, vous pouvez prédire le nombre de personnes infectées à l'avenir. (Je mettrai le chiffre [^ 3] pour référence)

SEIR_InsetChart_default.png

Pour une explication et une implémentation détaillées, reportez-vous à l'article de qiita [^ 4].

Ici, $ R_0 = \ beta / \ gamma $ est appelé le nombre de reproduction de base, et "(tous les individus sont initialement sensibles. Cela signifie "le nombre de personnes infectées secondaires produites par personne infectée (en état d'avoir)". [^ 5] ** Le fait est que plus $ R_0 $ est élevé, plus l'infectivité est grande. ** **

Vous pouvez également utiliser $ R_0 $ pour calculer dans quelle mesure la vaccination généralisée peut prévenir une épidémie.

En plus du SEIR, divers modèles peuvent être créés en subdivisant la population entière par lieu de résidence et par âge, et en reflétant les caractéristiques des maladies infectieuses dans des équations différentielles. Par exemple, il y a SIR qui ne considère pas E, SEIS qui ne considère pas l'acquisition d'immunité et MSEIR qui considère l'immunité passive [^ 6].

2.2. Modèle SEIRD étendu

Le SEIR ci-dessus étant trop simple, nous l'étendrons cette fois à un modèle qui considère les entrées et sorties de population et le taux de mortalité avec les pays étrangers en se référant à l'article [^ 1].

Ensuite, les équations différentielles simultanées suivantes sont également obtenues.

\begin{align}
\frac{dS(t)}{dt} &= - \frac{R_0}{D_I} \frac{I(t)}{N(t)} S(t) - N_{J,I} + 
 \left(1 - \frac{E(t) + I(t)}{N(t)} \right)N_{I,J} \\

\frac{dE(t)}{dt} &= \frac{R_0}{D_I} \frac{I(t)}{N(t)} S(t) - \frac{E(t)}{T_E} + \frac{E(t) + I(t)}{N(t)} N_{I,J}\\

\frac{dI(t)}{dt} &= \frac{E(t)}{T_E} - \frac{I(t)}{T_I}\\

\frac{dR(t)}{dt} &= (1-f) \frac{I(t)}{T_I}\\

\frac{dD(t)}{dt} &= f \frac{I(t)}{T_I} \\

N(t) &= S(t) + E(t) + I(t) + R(t)
\end{align}

Cependant, en ce qui concerne $ N_ {J, I} $ et $ N_ {I, J} $, on suppose que tous ceux qui partent du Japon à l'étranger appartiennent à $ S $, et ceux qui viennent au Japon de l'étranger appartiennent à $ S, E $. Je vais.

Comme dans l'article [^ 1], les paramètres autres que $ R_0 $ sont remplacés par des valeurs appropriées. $ T_I et T_E $ sont mis à $ T_E = 6,0 et T_I = 2,4 $ en référence à SARS Corona. $ N_ {J, I}, N_ {I, J} $ est défini sur $ N_ {J, I} = 40000, N_ {I, J} = 70000 $ en référence au nombre de voyageurs en février 2019.

3. Estimation des paramètres

Le paramètre inconnu du modèle est $ R_0 $. Il existe diverses méthodes d'estimation telles que la méthode du carré minimum, l'estimation de probabilité maximale, l'estimation MAP, l'estimation bayésienne [^ 7], mais cette fois, la vraisemblance est calculée comme le processus de Poisson non stationnaire [^ 8] et $ R_0 $ est calculé par l'estimation de probabilité maximale. ..

3.1. Estimation la plus probable

Tout le monde aime l'estimation la plus probable. Tout d'abord, exprimez la probabilité (probabilité) des données observées en fonction de $ R_0 $, et trouvez $ R_0 $ qui la maximise. Lorsque le nombre de personnes infectées est modélisé comme un processus de Poisson non stationnaire en référence à l'article [^ 1] et que la probabilité est calculée,

L(R_0) = \prod_{d=D_s}^{D_e} \frac{e^{-\lambda_d}\lambda_d^{x_d}}{x_d!}

Cependant, $ D_s $: premier jour d'observation, $ D_s $: dernier jour d'observation, $ x_d $: nombre de personnes infectées à $ d $

\lambda (t, R_0) = E(t) + I(t) \\
\lambda _d (R_0) = \int_{d-1}^{d} \lambda (u, R_0) du

ça ira. $ \ lambda $ représente le nombre moyen de personnes infectées lorsqu'elles suivent la distribution de Poisson.

En excluant les termes non liés à $ R_0 $ de la vraisemblance logarithmique, $ R_0 $ peut être estimé ci-dessous.

\newcommand{\argmin}{\mathop{\rm arg~min}\limits}

\argmin_{R_0 > 0} - \log L(R_0) = \argmin_{R_0 > 0} \sum_{d=D_s}^{D_e} (\lambda_d(R_0) - x_d \log \lambda_d(R_0))

4. Implémenté et illustré en python

Implémentation de la classe SEIR
import scipy
from scipy.integrate import odeint
from scipy.optimize import minimize
from sklearn.metrics import mean_absolute_error, mean_squared_error


class SIR(object):

    def __init__(self, r_0, t_i, dt, init_S, init_I, init_R):
        self.r_0 = r_0
        self.t_i = t_i
        self.dt = dt
        self.init_state_list = [init_S, init_I, init_R]

    def _get_param(self, params, key, default, t=None):
        """Correspond à des paramètres variant dans le temps
        """
        if isinstance(params, dict):
            if key in list(params.keys()):
                param = params[key]
                if isinstance(param, list):
                    return param[np.clip(int(t / self.dt), 0, len(param)-1)]
                elif isinstance(param, np.ndarray):
                    return param
                else:
                    return default
            else:
                return default
        else:
            return default

    def _ode(self, state_list, t=None, params=None):
        """Définir des équations différentielles simultanées
        """
        r_0 = self._get_param(params, 'r_0', self.r_0, t=t)
        t_i = self._get_param(params, 't_i', self.t_i, t=t)
        S, I, R = state_list
        N = S + I + R
        dstate_dt = list()
        dstate_dt[0] = - (r_0 / t_i) * (I / N) * S
        dstate_dt[1] = (r_0 / t_i) * (I / N) * S - I / t_i
        dstate_dt[2] = I / t_i
        return dstate_dt

    def solve_ode(self, len_days=365, params=None):
        """Résoudre des équations différentielles
        """
        t = np.linspace(0, len_days, int(len_days / self.dt), endpoint=False)
        args = (params,) if params else ()
        return odeint(self._ode, self.init_state_list, t, args=args)


class CustomizedSEIRD(SIR):

    def __init__(self, r_0=None, t_e=6.0, t_i=2.4, n_i_j=70000, n_j_i=40000, f=0.0001, dt=1,
            init_S=126800000, init_E=0, init_I=1, init_R=0, init_D=0):
        self.r_0 = r_0
        self.t_e = t_e
        self.t_i = t_i
        self.n_i_j = n_i_j
        self.n_j_i = n_j_i
        self.f = f
        self.dt = dt
        self.init_state_list = [init_S, init_E, init_I, init_R, init_D]

    def _ode(self, state_list, t=None, params=None):
        """Définir des équations différentielles simultanées
        """
        r_0 = self._get_param(params, 'r_0', self.r_0, t=t)
        t_e = self._get_param(params, 't_e', self.t_e, t=t)
        t_i = self._get_param(params, 't_i', self.t_i, t=t)
        n_i_j = self._get_param(params, 'n_i_j', self.n_i_j, t=t)
        n_j_i = self._get_param(params, 'n_j_i', self.n_j_i, t=t)
        f = self._get_param(params, 'f', self.f)
        S, E, I, R, D = state_list
        N = S + E + I + R
        dstate_dt = list()
        dstate_dt.append(- (r_0 / t_i) * (I / N) * S - n_j_i + (1 - ((E + I) / N)) * n_i_j)
        dstate_dt.append((r_0 / t_i) * (I / N) * S - E / t_e + ((E + I) / N) * n_i_j)
        dstate_dt.append(E / t_e - I / t_i)
        dstate_dt.append((1 - f) * I / t_i)
        dstate_dt.append(f * I / t_i)
        return dstate_dt

    def _calc_neg_log_likelihood_r0(self, r_0, X):
        """Probabilité du journal(R_Seule la partie liée à 0)Calculer
        """
        solution = self.solve_ode(len_days=len(X), params=dict(r_0=r_0))
        lambda_arr = solution[int(1/self.dt)-1::int(1/self.dt), 2] # I
        return - np.sum(- lambda_arr + X * np.log(lambda_arr))
    
    def _calc_error(self, r_0, X, metric=mean_absolute_error):
        """Calculer l'erreur absolue moyenne et l'erreur quadratique moyenne
        """
        solution = self.solve_ode(len_days=len(X), params=dict(r_0=r_0))
        e_arr = solution[int(1/self.dt)-1::int(1/self.dt), 2]  # I
        return metric(X, e_arr)

    def exec_point_estimation(self, init_r_0, X, project='mle'):
        """Paramètres d'estimation ponctuelle
        """
        if project == 'mle':
            result = minimize(self._calc_neg_log_likelihood_r0, init_r_0, args=(X,), method='Nelder-Mead')
        elif project == 'lad':
            result = minimize(self._calc_error, init_r_0, args=(X, mean_absolute_error), method='Nelder-Mead')
        elif project == 'ls':
            result = minimize(self._calc_error, init_r_0, args=(X, mean_squared_error), method='Nelder-Mead')
        else:
            print(f'Invalid project: {project}')
            return None
        if self.r_0 is None:
            self.r_0 = result.x[0]
        return result

    def exec_map(self):
        """Estimation MAP
        """
        pass

    def exec_mcmc(self):
        """Méthode MCMC
        """
        pass

if __name__ == '__main__':
    # 1/16 à 3/Nombre de personnes infectées jusqu'à 8
    X = np.array([
        1, 1, 1, 1, 1, 1, 1, 1, 2, 3,  # 1/25
        4, 4, 7, 8, 14, 17, 20, 20, 20, 23,  # 2/4
        35, 45, 86, 90, 96, 161, 163, 203, 251, 259,  # 2/14
        338, 414, 520, 616, 705, 728, 743, 743, 838, 851, # 2/24
        862, 891, 919, 938, 947, 961, 980, 999, 1035, 1056, # 3/5
        1113, 1157, 1190 # 3/8
    ])
    model = CustomizedSEIRD()
    result = model.exec_point_estimation(init_r_0=1, X=X, project='mle')
    print(result.x[0])
2.8806152343750036

Le «nombre de personnes infectées» est difficile à gérer, et seuls ceux qui se rendent à l'hôpital sont effectivement comptés, et personne ne connaît le vrai $ x_d $ compte tenu des critères de diagnostic et de la spécificité de sensibilité du test. Hmm. Ici, il est estimé en fonction du nombre de personnes infectées [^ 9], y compris les navires de croisière.

Prédiction des futures infections domestiques par le modèle SEIR étendu (I est le nombre d'infections)

SEIRD2.png

C'est un graphique lorsque $ R_0 $ estimé par la ligne bleue ne change pas dans le futur. Si nous continuons comme il est, le nombre de personnes infectées atteindra son maximum juste lorsque la GW sera terminée. C'est un graphique lorsque la ligne rouge et la ligne bleue changent $ R_0 $ après 3/9. Puisque $ R_0 $ est "le nombre de personnes infectées secondaires produites par personne infectée", il sera plus petit en raison des contre-mesures contre les infections et des restrictions de mouvement. Si $ R_0 $ peut être rendu suffisamment petit, il peut être contenu comme une ligne verte.

Le chiffre ci-dessous est un chiffre publié par le ministère de la Santé et du Bien-être social [^ 9], mais la forme du graphique du nombre de personnes infectées correspond exactement.

厚生省コロナ感染者数.png

De plus, par exemple, si vous modifiez $ N_ {i, j} $, vous pouvez calculer si le nombre de personnes infectées changera en raison des restrictions d'immigration des étrangers. En calculant avec le même modèle, même si $ N_ {i, j} = 0 $ après 3/9, si $ R_0 $ est le même, le nombre de personnes infectées ne changera pas. Cela signifie que les restrictions à l'immigration n'ont aucun sens (si ce modèle est correct).

Ensuite, comparons le nombre de reproduction de base et la létalité avec d'autres maladies infectieuses [^ 10]. (Le taux de létalité de la nouvelle couronne est d'environ 0,1% à 5% du taux de létalité de chaque pays)

comparison.png

Il semble que le nombre de reproduction de base et le taux de létalité de la nouvelle couronne ne soient pas significativement plus élevés que ceux des autres maladies infectieuses. (Pour le risque de maladies infectieuses, il est nécessaire de prendre en compte la gravité des symptômes et la présence ou l'absence de vaccins, et je pense que de faibles taux de reproduction de base et de faibles taux de létalité ne signifient pas qu'ils sont sûrs, mais les détails sont Demandez à quelqu'un qui résiste aux maladies infectieuses)

5. Supplément

Ministère de la santé, du travail et de la protection sociale

Société japonaise pour les maladies infectieuses

WHO

CDC

Site sympa où vous pouvez vérifier le nombre de personnes infectées (Johns Hopkins CSSE)

** Je ne suis ni un spécialiste des maladies infectieuses, ni un service de santé publique, ni un statisticien. La maladie infectieuse réelle n'est pas aussi simple que ce modèle, donc cette prédiction est probablement fausse. Nous ne sommes pas responsables des dommages causés par le contenu de cet article. ** **

[^ 2]: Arrêtez les maladies infectieuses avec un modèle mathématique

[^ 4]: Début du modèle mathématique des maladies infectieuses: aperçu du modèle SEIR par Python et introduction à l'estimation des paramètres

[^ 5]: Prédiction des épidémies de maladies infectieuses: problèmes quantitatifs dans les modèles mathématiques de maladies infectieuses

[^ 7]: Estimation la plus probable, estimation MAP, estimation Bayes apprise dans Fujii 4ème Dan

[^ 8]: modèle SIR et processus de Poisson non stationnaire

[^ 9]: À propos de la nouvelle infection à coronavirus

Recommended Posts

J'ai essayé de prédire le nombre de personnes infectées au niveau national de la nouvelle corona avec un modèle mathématique
J'ai essayé de prédire le comportement du nouveau virus corona avec le modèle SEIR.
J'ai essayé de prédire le nombre de personnes infectées par le virus corona au Japon par la méthode du dernier article en Chine
J'ai essayé de prédire le nombre de personnes infectées par le virus corona en tenant compte de l'effet de s'abstenir de sortir
Prédire le nombre de personnes infectées par COVID-19 avec Prophet
Créez un BOT qui affiche le nombre de personnes infectées dans le nouveau Corona
J'ai essayé de créer un modèle avec l'exemple d'Amazon SageMaker Autopilot
J'ai essayé de visualiser les caractéristiques des nouvelles informations sur les personnes infectées par le virus corona avec wordcloud
J'ai essayé de prédire l'infection d'une nouvelle pneumonie en utilisant le modèle SIR: ☓ Wuhan edition ○ Hubei province edition
J'ai essayé de rationaliser le rôle standard des nouveaux employés avec Python
J'ai essayé d'obtenir et d'analyser les données statistiques de la nouvelle Corona avec Python: données de l'Université John's Hopkins
J'ai essayé d'envoyer automatiquement la littérature du nouveau virus corona à LINE avec Python
Je voulais connaître le nombre de lignes dans plusieurs fichiers et j'ai essayé de l'obtenir avec une commande
J'ai essayé de résumer les nouvelles personnes infectées par le virus corona dans la ville d'Ichikawa, préfecture de Chiba
J'ai essayé de trouver l'entropie de l'image avec python
J'ai essayé de trouver la moyenne de plusieurs colonnes avec TensorFlow
J'ai fait une fonction pour vérifier le modèle de DCGAN
Visualisons le nombre de personnes infectées par le virus corona avec matplotlib
J'ai essayé d'écrire dans un modèle de langage profondément appris
J'ai essayé de classer le nombre de décès par habitant de COVID-19 (nouveau virus corona) par pays
Application correspondante, j'ai essayé de prendre des statistiques de personnes fortes et j'ai essayé de créer un modèle d'apprentissage automatique
Jour 71, j'ai essayé de prédire combien de temps cette autolimitation se poursuivra avec le modèle SIR
J'ai écrit un doctest dans "J'ai essayé de simuler la probabilité d'un jeu de bingo avec Python"
J'ai essayé de prédire les ventes de logiciels de jeux avec VARISTA en me référant à l'article du Codexa
J'ai essayé d'automatiser l'arrosage du pot avec Raspberry Pi
[Introduction à StyleGAN] J'ai joué avec "The Life of a Man" ♬
J'ai essayé de créer une liste de nombres premiers avec python
J'ai essayé de créer un Discord Bot sur Docker qui signale le nombre de personnes infectées par corona à Tokyo à un moment spécifié
J'ai essayé d'agrandir la taille du volume logique avec LVM
J'ai essayé d'améliorer l'efficacité du travail quotidien avec Python
J'ai essayé de créer un mécanisme de contrôle exclusif avec Go
J'ai essayé de déverrouiller l'entrée 2 lock sésame d'une simple pression sur le bouton AWS IoT
Le cours de l'action a chuté avec "nouvelle Corona"? J'ai essayé d'obtenir le cours moyen de l'action Nikkei par grattage Web
J'ai essayé d'obtenir le code d'authentification de l'API Qiita avec Python.
(Python) J'ai essayé d'analyser 1 million de mains ~ J'ai essayé d'estimer le nombre d'AA ~
J'ai essayé d'analyser la négativité de Nono Morikubo. [Comparer avec Posipa]
J'ai essayé de visualiser le texte du roman "Weather Child" avec Word Cloud
J'ai essayé de visualiser le modèle avec la bibliothèque d'apprentissage automatique low-code "PyCaret"
J'ai essayé d'obtenir les informations sur le film de l'API TMDb avec Python
J'ai essayé d'afficher la valeur d'altitude du DTM dans un graphique
J'ai essayé l'histoire courante de l'utilisation du Deep Learning pour prédire la moyenne Nikkei
J'ai essayé de vérifier le résultat du test A / B avec le test du chi carré
Je souhaite résoudre le problème de fuite de mémoire lors de la sortie d'un grand nombre d'images avec Matplotlib
Créez un bot qui publie sur Slack le nombre de personnes positives pour le nouveau virus corona à Tokyo
J'ai essayé de prédire l'année prochaine avec l'IA
J'ai essayé de sauvegarder les données avec discorde
J'ai essayé de corriger la forme trapézoïdale de l'image
J'ai essayé de prédire la survie du Titanic avec PyCaret
J'ai essayé de vectoriser les paroles de Hinatazaka 46!
J'ai essayé de prédire la détérioration de la batterie lithium-ion en utilisant le SDK Qore
J'ai fait une application d'envoi de courrier simple avec tkinter de Python
Notez la solution car django n'a pas pu s'installer avec pip
J'ai essayé de visualiser facilement les tweets de JAWS DAYS 2017 avec Python + ELK
J'ai essayé de prédire la présence ou l'absence de neige par apprentissage automatique.
L'histoire de la fabrication de soracom_exporter (j'ai essayé de surveiller SORACOM Air avec Prometheus)