{ "cells": [ { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "RVU1Q900Dl2r" }, "source": [ "##### Copyright 2020 The TensorFlow Authors.\n", "##### Copyright 2020 Sen Pei (Columbia University).\n", "\n", "Licensed under the Apache License, Version 2.0 (the \"License\");" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "QKUGkj9ZDmfg" }, "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\"); { display-mode: \"form\" }\n", "# you may not use this file except in compliance with the License.\n", "# You may obtain a copy of the License at\n", "#\n", "# https://www.apache.org/licenses/LICENSE-2.0\n", "#\n", "# Unless required by applicable law or agreed to in writing, software\n", "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", "# See the License for the specific language governing permissions and\n", "# limitations under the License." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "KCZNiAlqEAr1" }, "source": [ "# Substantial Undocumented Infection Facilitates the Rapid Dissemination of Novel Coronavirus (SARS-CoV2)\n", "\n", "\n", " \n", " \n", " \n", " \n", "
\n", " View on TensorFlow.org\n", " \n", " Run in Google Colab\n", " \n", " View source on GitHub\n", " \n", " Download notebook\n", "
" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "iBdidAV1Rw-G" }, "source": [ "This is a TensorFlow Probability port of the eponymous 16 March 2020 paper by Li et al. We faithfully reproduce the original authors' methods and results on the TensorFlow Probability platform, showcasing some of TFP's capabilities in the setting of modern epidemiology modeling. Porting to TensorFlow gives us a ~10x speedup relative to the original Matlab code, and, since TensorFlow Probability pervasively supports vectorized batch computation, also favorably scales to hundreds of independent replications.\n", "\n", "### Original paper\n", "\n", "Ruiyun Li, Sen Pei, Bin Chen, Yimeng Song, Tao Zhang, Wan Yang, and Jeffrey Shaman. Substantial undocumented infection facilitates the rapid dissemination of novel coronavirus (SARS-CoV2). (2020), doi:\n", "https://doi.org/10.1126/science.abb3221 .\n", "\n", "*Abstract:* \"Estimation of the prevalence and contagiousness of undocumented novel coronavirus (SARS-CoV2) infections is critical for understanding the overall prevalence and pandemic potential of this disease. Here we use observations of reported infection within China, in conjunction with mobility data, a networked dynamic metapopulation model and Bayesian inference, to infer critical epidemiological characteristics associated with SARS-CoV2, including the fraction of undocumented infections and their contagiousness. We estimate 86% of all infections were undocumented (95% CI: [82%–90%]) prior to 23 January 2020 travel restrictions. Per person, the transmission rate of undocumented infections was 55% of documented infections ([46%–62%]), yet, due to their greater numbers, undocumented infections were the infection source for 79% of documented cases. These findings explain the rapid geographic spread of SARS-CoV2 and indicate containment of this virus will be particularly challenging.\"\n", "\n", "[Github link](https://github.com/SenPei-CU/COVID-19) to the code and data." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "0yETSzjhoVBN" }, "source": [ "## Overview" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "HtZGdFItx4Z3" }, "source": [ "The model is a [compartmental disease model](https://en.wikipedia.org/wiki/Compartmental_models_in_epidemiology), with compartments for \"susceptible\", \"exposed\" (infected but not yet infectious), \"never-documented infectious\", and \"eventually-documented infectious\". There are two noteworthy features: separate compartments for each of 375 Chinese cities, with an assumption about how people travel from one city to another; and delays in reporting infection, so that a case that becomes \"eventually-documented infectious\" on day $t$ doesn't show up in the observed case counts until a stochastic later day.\n", "\n", "The model assumes that the never-documented cases end up undocumented by being milder, and thus infect others at a lower rate. The main parameter of interest in the original paper is the proportion of cases that go undocumented, to estimate both the extent of existing infection, and the impact of undocumented transmission on the spread of the disease.\n", "\n", "This colab is structured as a code walkthrough in bottom-up style. In order, we will\n", "- Ingest and briefly examine the data,\n", "- Define the state space and dynamics of the model,\n", "- Build up a suite of functions for doing inference in the model following Li et al, and\n", "- Invoke them and examine the results. Spoiler: They come out the same as the paper.\n" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Brvp_GH-ItsG" }, "source": [ "## Installation and Python Imports" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "iUEZ07T3yuBj" }, "outputs": [], "source": [ "!pip3 install -q tf-nightly tfp-nightly" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "-Za3hnj2y5M9" }, "outputs": [], "source": [ "import collections\n", "import io\n", "import requests\n", "import time\n", "import zipfile\n", "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", "\n", "import tensorflow.compat.v2 as tf\n", "import tensorflow_probability as tfp\n", "from tensorflow_probability.python.internal import samplers\n", "\n", "tfd = tfp.distributions\n", "tfes = tfp.experimental.sequential" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "KYfPl6uqzIs1" }, "source": [ "## Data Import\n", "\n", "Let's import the data from github and inspect some of it." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "1q22N4rPzXIg" }, "outputs": [], "source": [ "r = requests.get('https://raw.githubusercontent.com/SenPei-CU/COVID-19/master/Data.zip')\n", "z = zipfile.ZipFile(io.BytesIO(r.content))\n", "z.extractall('/tmp/')\n", "raw_incidence = pd.read_csv('/tmp/data/Incidence.csv')\n", "raw_mobility = pd.read_csv('/tmp/data/Mobility.csv')\n", "raw_population = pd.read_csv('/tmp/data/pop.csv')" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "IC3Nt8lJSllh" }, "source": [ "Below we can see the raw incidence count per day. We are most interested in the first 14 days (January 10th to January 23rd), as the travel restrictions were put in place on the 23rd. The paper deals with this by modeling Jan 10-23 and Jan 23+ separately, with different parameters; we will just restrict our reproduction to the earlier period." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": { "height": 1000 }, "colab_type": "code", "id": "yFP-Tah4zfne", "outputId": "f02e7cf1-e4ae-4a56-ad1c-8bbfd61fde4a" }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
BeijingTianjinShijiazhuangTangshanQinhuangdaoHandanXintaiBaodingZhangjiakouChengdeCangzhouLangfangHengshuiTaiyuanDatongYangquanChangzhiJinchengShuozhouJinzhongYunchengXinzhouLinfenLvliangHuhehaoteBaotouWuhaiChifengTongliaoEerduosiHulunbeierBayannaoerWulanchabuXing'anmengXimengAlashanmengShenyangDalianAnshanFushunBenxiDandongJinzhou (Liaoning)YinkouFuxinLiaoyangPanjinTielingZhaoyangHuludaoChangchunJilinSipingLiaoyuanTonghuaBaishanSongyuanBaichengYanbianHa'erbinQiqiha'erJixiHegangShuangyashanDaqingYichun (Heilongjiang)JiamusiQitaiheMudanjiangHeiheSuihuaDaxing'anlingShanghaiNanjingWuxiXuzhouChangzhouSuzhou (Jiangsu)NantongLianyungangHuai'anYanchengYangzhouZhenjiangTaizhou (Jiangsu)SuqianHangzhouNingboWenzhouJiaxing...KunmingQujingYuxiBaoshanShaotongLijiangPu'erLincangChuxiongHongheWenshanXishuangbannaDaliDehonhNujiangDiqingLasaChangduShannanRikazeNaquAliLinzhiXi'anTongchuanBaojiXianyangWeinanYan'anHanzhouYulin (Shanxi)AnkangShangluoLanzhouJiayuguanJinchangBaiyinTianshuiWuweiZhangyePingliangJiuquanQingyangDongxiLongnanLinxiaGannanXiningHaidongHaibeiHuangnanHainanGuoluoYushuHaixiYinchuanShizuishanWuzhou (Ningxia)GuyuanZhongweiUrumuqiKelamayiTulufanHamiChangjiBozhou (Xinjiang)Bazhou (Xinjiang)AkesuKezhouKashiHetian (Xinjiang)YiliTachengAletaiShiheziAla'erTumushukeWujiaqu (Xinjiang)BeitunWujiaqushi (Xinjiang)TiemenguanShuangheKekedalaTaiwanHongkongMacaoHetianxian (Xinjiang)MoyuYutianGejiu
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
10500000000000000000000000000000000000000000000000000000000000000000000000100000000000000000...000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
11520000000000000000000000000000000000000000000000000000000000000000000000800000000000001020...100000000000000000000000000000000000000000000000000000000000000000000000000000000001000000
12421000000000010000000200000000000000110100000000001000000000000000001000700001000000000320...100000000000000000000000000000000000000000000000000000010000000000000000000000000000000000
131210000000010000000000000000000000000100000000000100100001001000010000010431001110010005220...000000000000000000000002001000000100100000000000000000000001200000000000000000000000000000
147230000101100110100021000000000000001100100000021201000000050000000000001310051000100016141...100001000001000000000000000010010100000000000100000000000010100000000000000000000000000000
1515210020200000001000200000001120000002200000000000000000000021000200000107310041210001015784...111001000100100000000002302000021200000000010001000000020000000000000001000000000000300000
16174200010000200000020001102000000010010001100002000001000100000000010000013023112010321000140...300210000000020000000004200001000400000100001103000000000000100000000000000000000000000000
17128210210003421000300110201010000000021000400010000010000000210000001005013325242000102254283...010103000100100000000004001112040301010000000004000000050200101000000001000000000001000000
181111200131033102000041700230212200100000000400000110000100001110000400000144300800153041193543...834111100005100000000003030201011300000110000000000000000100100000000002000000000001000000
1920310022151401010201031010000010100001000000000001140000000120010000000212151724334000101821582...601120200204100000000003011012020000010000010000000000020200100000000000000000000000000000
202130401240060000000000400000000000000120010000010100000000005010020311021276253813320033165550...3100001000022000000000014001245030000000000000002000000000000100000010001000000000000000000
212401113302012001002022300000002010000211000301041113000000007020110324010253131224255051139142...601020010000000000000000000000000000000000000001000000040100000000000000000000000000000000
22231213010210000220030201001110010000000200000010000040020000090002000111102476714501201001211241...104000000100100000000008022002010300000000010010000000010100000000000000000000000000000000
233973010400001000000000000000000000000110000001110004130000001212033000102016540062150104189260...111021002001010000000008111002020000000000000000000000030000200000000001000000000000000000
241612500320011010000104030000000010000000000000000000113300000181315000000601542348334012211427494...120000000000000000000008110100010200020000000000020000011001200010000001000000000000000000
252500110041101030000121300111102010000010000002000001001000000101430400011020143165333400334918244...020010001001000000000005022001003200000000000000000000000000000010000002000000000000000000
2621113504303111300000000200020000200000100000000000001012000009690420101050215203522810220106313...3010000000011000000000010004303021000000000000001000000050100300000000000000000000000000000
272300224011121020101010310200110000000002000000030003010100011218016001110100165342922302111510255...300100000000300000000004000001020200200000000010000000020100300000000000000000000000000000
28180042420115501100003030001001000000022000010010000000100010600000000005012833232331021065172...110000000000000000000008001010000000000010030000000000000002100000000000000000000000000000
29117040103000213102023120000000002000012000020000000502010000140312000200006644031540110035101...000020000000000000000008010400000100020020000030000000000000100000000001000000000000000000
\n", "

30 rows × 375 columns

\n", "
" ], "text/plain": [ " Beijing Tianjin Shijiazhuang Tangshan Qinhuangdao Handan Xintai Baoding ... Kekedala Taiwan Hongkong Macao Hetianxian (Xinjiang) Moyu Yutian Gejiu\n", "0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0\n", "1 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0\n", "2 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0\n", "3 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0\n", "4 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0\n", "5 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0\n", "6 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0\n", "7 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0\n", "8 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0\n", "9 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0\n", "10 5 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0\n", "11 5 2 0 0 0 0 0 0 ... 0 1 0 0 0 0 0 0\n", "12 4 2 1 0 0 0 0 0 ... 0 0 0 0 0 0 0 0\n", "13 12 1 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0\n", "14 7 2 3 0 0 0 0 1 ... 0 0 0 0 0 0 0 0\n", "15 15 2 1 0 0 2 0 2 ... 0 0 3 0 0 0 0 0\n", "16 17 4 2 0 0 0 1 0 ... 0 0 0 0 0 0 0 0\n", "17 12 8 2 1 0 2 1 0 ... 0 1 0 0 0 0 0 0\n", "18 11 1 1 2 0 0 1 3 ... 0 1 0 0 0 0 0 0\n", "19 20 3 1 0 0 2 2 1 ... 0 0 0 0 0 0 0 0\n", "20 21 3 0 4 0 1 2 4 ... 0 0 0 0 0 0 0 0\n", "21 24 0 1 1 1 3 3 0 ... 0 0 0 0 0 0 0 0\n", "22 23 12 1 3 0 1 0 2 ... 0 0 0 0 0 0 0 0\n", "23 39 7 3 0 1 0 4 0 ... 0 0 0 0 0 0 0 0\n", "24 16 12 5 0 0 3 2 0 ... 0 0 0 0 0 0 0 0\n", "25 25 0 0 1 1 0 0 4 ... 0 0 0 0 0 0 0 0\n", "26 21 11 3 5 0 4 3 0 ... 0 0 0 0 0 0 0 0\n", "27 23 0 0 2 2 4 0 1 ... 0 0 0 0 0 0 0 0\n", "28 18 0 0 4 2 4 2 0 ... 0 0 0 0 0 0 0 0\n", "29 11 7 0 4 0 1 0 3 ... 0 0 0 0 0 0 0 0\n", "\n", "[30 rows x 375 columns]" ] }, "execution_count": 0, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "raw_incidence.drop('Date', axis=1) # The 'Date' column is all 1/18/21\n", "# Luckily the days are in order, starting on January 10th, 2020." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "EOQn3GZ2DcKE" }, "source": [ "Let's sanity-check the Wuhan incidence counts." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": { "height": 281 }, "colab_type": "code", "id": "S6iXSZK7Df5h", "outputId": "66820caf-ed42-4ed1-c5ba-b853aaf51aab" }, "outputs": [ { "data": { "image/png": "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\n/4Qe9HSAXAWqAAAAAElFTkSuQmCC\n", "text/plain": [ "
" ] }, "metadata": { "tags": [] }, "output_type": "display_data" } ], "source": [ "plt.plot(raw_incidence.Wuhan, '.-')\n", "plt.title('Wuhan incidence counts over 1/10/20 - 02/08/20')\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "4rzCbKNkMKdk" }, "source": [ "So far, so good. Now the initial population counts." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": { "height": 1000 }, "colab_type": "code", "id": "P2Spczra1A7y", "outputId": "3ebde5b5-e0de-4d44-ae75-716c62536f93" }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
CityPopulation
0Beijing21540000.0
1Tianjin11760000.0
2Shijiazhuang10151200.0
3Tangshan7843600.0
4Qinhuangdao3094600.0
5Handan9492800.0
6Xintai7319900.0
7Baoding10425300.0
8Zhangjiakou4425100.0
9Chengde3531800.0
10Cangzhou7505500.0
11Langfang4615000.0
12Hengshui4453100.0
13Taiyuan4421400.0
14Datong3456000.0
15Yangquan1414400.0
16Changzhi3468200.0
17Jincheng2343100.0
18Shuozhou1781200.0
19Jinzhong3381600.0
20Yuncheng5359600.0
21Xinzhou3171200.0
22Linfen4500300.0
23Lvliang3885600.0
24Huhehaote2437900.0
25Baotou2297400.0
26Wuhai434900.0
27Chifeng4518000.0
28Tongliao3083500.0
29Eerduosi2078400.0
.........
345Urumuqi2330000.0
346Kelamayi270000.0
347Tulufan590000.0
348Hami550000.0
349Changji1590000.0
350Bozhou (Xinjiang)470000.0
351Bazhou (Xinjiang)1170000.0
352Akesu2260000.0
353Kezhou470000.0
354Kashi3650000.0
355Hetian (Xinjiang)1800000.0
356Yili2600000.0
357Tacheng990000.0
358Aletai640000.0
359Shihezi660000.0
360Ala'er326800.0
361Tumushuke255600.0
362Wujiaqu (Xinjiang)125600.0
363Beitun80000.0
364Wujiaqushi (Xinjiang)125600.0
365Tiemenguan50000.0
366Shuanghe53800.0
367Kekedala75000.0
368Taiwan23580000.0
369Hongkong7450000.0
370Macao630000.0
371Hetianxian (Xinjiang)360000.0
372Moyu646200.0
373Yutian289500.0
374Gejiu472000.0
\n", "

375 rows × 2 columns

\n", "
" ], "text/plain": [ " City Population\n", "0 Beijing 21540000.0\n", "1 Tianjin 11760000.0\n", "2 Shijiazhuang 10151200.0\n", "3 Tangshan 7843600.0\n", "4 Qinhuangdao 3094600.0\n", "5 Handan 9492800.0\n", "6 Xintai 7319900.0\n", "7 Baoding 10425300.0\n", "8 Zhangjiakou 4425100.0\n", "9 Chengde 3531800.0\n", "10 Cangzhou 7505500.0\n", "11 Langfang 4615000.0\n", "12 Hengshui 4453100.0\n", "13 Taiyuan 4421400.0\n", "14 Datong 3456000.0\n", "15 Yangquan 1414400.0\n", "16 Changzhi 3468200.0\n", "17 Jincheng 2343100.0\n", "18 Shuozhou 1781200.0\n", "19 Jinzhong 3381600.0\n", "20 Yuncheng 5359600.0\n", "21 Xinzhou 3171200.0\n", "22 Linfen 4500300.0\n", "23 Lvliang 3885600.0\n", "24 Huhehaote 2437900.0\n", "25 Baotou 2297400.0\n", "26 Wuhai 434900.0\n", "27 Chifeng 4518000.0\n", "28 Tongliao 3083500.0\n", "29 Eerduosi 2078400.0\n", ".. ... ...\n", "345 Urumuqi 2330000.0\n", "346 Kelamayi 270000.0\n", "347 Tulufan 590000.0\n", "348 Hami 550000.0\n", "349 Changji 1590000.0\n", "350 Bozhou (Xinjiang) 470000.0\n", "351 Bazhou (Xinjiang) 1170000.0\n", "352 Akesu 2260000.0\n", "353 Kezhou 470000.0\n", "354 Kashi 3650000.0\n", "355 Hetian (Xinjiang) 1800000.0\n", "356 Yili 2600000.0\n", "357 Tacheng 990000.0\n", "358 Aletai 640000.0\n", "359 Shihezi 660000.0\n", "360 Ala'er 326800.0\n", "361 Tumushuke 255600.0\n", "362 Wujiaqu (Xinjiang) 125600.0\n", "363 Beitun 80000.0\n", "364 Wujiaqushi (Xinjiang) 125600.0\n", "365 Tiemenguan 50000.0\n", "366 Shuanghe 53800.0\n", "367 Kekedala 75000.0\n", "368 Taiwan 23580000.0\n", "369 Hongkong 7450000.0\n", "370 Macao 630000.0\n", "371 Hetianxian (Xinjiang) 360000.0\n", "372 Moyu 646200.0\n", "373 Yutian 289500.0\n", "374 Gejiu 472000.0\n", "\n", "[375 rows x 2 columns]" ] }, "execution_count": 0, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "raw_population" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Xf6xLARfsBwe" }, "source": [ "Let's also check and record which entry is Wuhan." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": { "height": 35 }, "colab_type": "code", "id": "phQQFI401Pr8", "outputId": "b0d8334e-c714-4a8e-813f-de31aa6947e0" }, "outputs": [ { "data": { "text/plain": [ "'Wuhan'" ] }, "execution_count": 0, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "raw_population['City'][169]" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "uS5vWXkBsQLG" }, "outputs": [], "source": [ "WUHAN_IDX = 169" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "3RWGcEfL65sS" }, "source": [ "And here we see the mobility matrix between different cities. This is a proxy for the number of people moving between different cities on the first 14 days. It's dervied from GPS records provided by Tencent for the 2018 Lunar New Year season. Li et al model mobility during the 2020 season as some unknown (subject to inference) constant factor $\\theta$ times this." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": { "height": 1000 }, "colab_type": "code", "id": "BvPonRBJ1AIQ", "outputId": "95eec3c7-cf53-4f30-f4b9-fe6742fbb5fe" }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
DayOriginDestinationMobility Index
01BeijingTianjin17585
11BeijingShijiazhuang21289
21BeijingHandan27676
31BeijingBaoding19007
41BeijingZhangjiakou20327
51BeijingLangfang31180
61BeijingHa'erbin24390
71BeijingShanghai66799
81BeijingNanjing17719
91BeijingHangzhou28536
101BeijingWenzhou16767
111BeijingXinyang17522
121BeijingWuhan32517
131BeijingChangsha35671
141BeijingChongqing66639
151BeijingXi'an17088
161TianjinBeijing13942
171TianjinTangshan6631
181TianjinHandan5140
191TianjinBaoding6398
201TianjinCangzhou7030
211TianjinLangfang7363
221TianjinChangchun4258
231TianjinHa'erbin12675
241TianjinShanghai8698
251TianjinHangzhou4364
261TianjinFuzhou (Fujian)14632
271TianjinDezhou6857
281TianjinWuhan4669
291TianjinChangsha6579
...............
9221814GejiuChangsha52
9221914GejiuHengyang42
9222014GejiuChangde53
9222114GejiuChenzhou36
9222214GejiuYongzhou42
9222314GejiuGuangzhou48
9222414GejiuShenzhen77
9222514GejiuHuizhou43
9222614GejiuNannig30
9222714GejiuBeihai30
9222814GejiuBaise37
9222914GejiuChongqing132
9223014GejiuNeijiang47
9223114GejiuLiupanshui41
9223214GejiuBijie32
9223314GejiuKunming452
9223414GejiuQujing359
9223514GejiuYuxi170
9223614GejiuShaotong94
9223714GejiuPu'er50
9223814GejiuChuxiong62
9223914GejiuWenshan138
9224014GejiuDali50
9224114GejiuXi'an55
9224214GejiuXianyang38
9224314GejiuLanzhou60
9224414GejiuPingliang73
9224514GejiuDongxi126
9224614GejiuXining31
9224714GejiuGuyuan33
\n", "

92248 rows × 4 columns

\n", "
" ], "text/plain": [ " Day Origin Destination Mobility Index\n", "0 1 Beijing Tianjin 17585\n", "1 1 Beijing Shijiazhuang 21289\n", "2 1 Beijing Handan 27676\n", "3 1 Beijing Baoding 19007\n", "4 1 Beijing Zhangjiakou 20327\n", "5 1 Beijing Langfang 31180\n", "6 1 Beijing Ha'erbin 24390\n", "7 1 Beijing Shanghai 66799\n", "8 1 Beijing Nanjing 17719\n", "9 1 Beijing Hangzhou 28536\n", "10 1 Beijing Wenzhou 16767\n", "11 1 Beijing Xinyang 17522\n", "12 1 Beijing Wuhan 32517\n", "13 1 Beijing Changsha 35671\n", "14 1 Beijing Chongqing 66639\n", "15 1 Beijing Xi'an 17088\n", "16 1 Tianjin Beijing 13942\n", "17 1 Tianjin Tangshan 6631\n", "18 1 Tianjin Handan 5140\n", "19 1 Tianjin Baoding 6398\n", "20 1 Tianjin Cangzhou 7030\n", "21 1 Tianjin Langfang 7363\n", "22 1 Tianjin Changchun 4258\n", "23 1 Tianjin Ha'erbin 12675\n", "24 1 Tianjin Shanghai 8698\n", "25 1 Tianjin Hangzhou 4364\n", "26 1 Tianjin Fuzhou (Fujian) 14632\n", "27 1 Tianjin Dezhou 6857\n", "28 1 Tianjin Wuhan 4669\n", "29 1 Tianjin Changsha 6579\n", "... ... ... ... ...\n", "92218 14 Gejiu Changsha 52\n", "92219 14 Gejiu Hengyang 42\n", "92220 14 Gejiu Changde 53\n", "92221 14 Gejiu Chenzhou 36\n", "92222 14 Gejiu Yongzhou 42\n", "92223 14 Gejiu Guangzhou 48\n", "92224 14 Gejiu Shenzhen 77\n", "92225 14 Gejiu Huizhou 43\n", "92226 14 Gejiu Nannig 30\n", "92227 14 Gejiu Beihai 30\n", "92228 14 Gejiu Baise 37\n", "92229 14 Gejiu Chongqing 132\n", "92230 14 Gejiu Neijiang 47\n", "92231 14 Gejiu Liupanshui 41\n", "92232 14 Gejiu Bijie 32\n", "92233 14 Gejiu Kunming 452\n", "92234 14 Gejiu Qujing 359\n", "92235 14 Gejiu Yuxi 170\n", "92236 14 Gejiu Shaotong 94\n", "92237 14 Gejiu Pu'er 50\n", "92238 14 Gejiu Chuxiong 62\n", "92239 14 Gejiu Wenshan 138\n", "92240 14 Gejiu Dali 50\n", "92241 14 Gejiu Xi'an 55\n", "92242 14 Gejiu Xianyang 38\n", "92243 14 Gejiu Lanzhou 60\n", "92244 14 Gejiu Pingliang 73\n", "92245 14 Gejiu Dongxi 126\n", "92246 14 Gejiu Xining 31\n", "92247 14 Gejiu Guyuan 33\n", "\n", "[92248 rows x 4 columns]" ] }, "execution_count": 0, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "raw_mobility" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "vSY98S14Oaqs" }, "source": [ "Finally, let's preprocess all this into numpy arrays that we can consume." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "9txbadTC14YP" }, "outputs": [], "source": [ "# The given populations are only \"initial\" because of intercity mobility during\n", "# the holiday season.\n", "initial_population = raw_population['Population'].to_numpy().astype(np.float32)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "w-pKDK461zFX" }, "source": [ "Convert the mobility data into an [L, L, T]-shaped Tensor, where L is the number of locations, and T is the number of timesteps." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "f-2zASNxw_wi" }, "outputs": [], "source": [ "daily_mobility_matrices = []\n", "for i in range(1, 15):\n", " day_mobility = raw_mobility[raw_mobility['Day'] == i]\n", " \n", " # Make a matrix of daily mobilities.\n", " z = pd.crosstab(\n", " day_mobility.Origin, \n", " day_mobility.Destination, \n", " values=day_mobility['Mobility Index'], aggfunc='sum', dropna=False)\n", " \n", " # Include every city, even if there are no rows for some in the raw data on\n", " # some day. This uses the sort order of `raw_population`.\n", " z = z.reindex(index=raw_population['City'], columns=raw_population['City'], \n", " fill_value=0)\n", " # Finally, fill any missing entries with 0. This means no mobility.\n", " z = z.fillna(0)\n", " daily_mobility_matrices.append(z.to_numpy())\n", "\n", "mobility_matrix_over_time = np.stack(daily_mobility_matrices, axis=-1).astype(\n", " np.float32)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "GaJYQFT91-15" }, "source": [ "Finally take the observed infections and make an [L, T] table." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "qs4TKTnv176D" }, "outputs": [], "source": [ "# Remove the date parameter and take the first 14 days.\n", "observed_daily_infectious_count = raw_incidence.to_numpy()[:14, 1:]\n", "observed_daily_infectious_count = np.transpose(\n", " observed_daily_infectious_count).astype(np.float32)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "B9WeGRug2HLQ" }, "source": [ "And double-check that we got the shapes the way we wanted. As a reminder, we're working with 375 cities and 14 days." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": { "height": 69 }, "colab_type": "code", "id": "dymKgF8p1hgi", "outputId": "040b68e0-2d29-462a-a208-dd82c75c02b9" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Mobility Matrix over time should have shape (375, 375, 14): (375, 375, 14)\n", "Observed Infectious should have shape (375, 14): (375, 14)\n", "Initial population should have shape (375): (375,)\n" ] } ], "source": [ "print('Mobility Matrix over time should have shape (375, 375, 14): {}'.format(\n", " mobility_matrix_over_time.shape))\n", "print('Observed Infectious should have shape (375, 14): {}'.format(\n", " observed_daily_infectious_count.shape))\n", "print('Initial population should have shape (375): {}'.format(\n", " initial_population.shape))" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "LGTcVy2K2mxv" }, "source": [ "## Defining State and Parameters\n", "\n", "\n", "Let's start defining our model. The model we are reproducing is a variant of an [SEIR model](https://en.wikipedia.org/wiki/Compartmental_models_in_epidemiology#The_SEIR_model). In this case we have the following time-varying states:\n", "* $S$: Number of people susceptible to the disease in each city.\n", "* $E$: Number of people in each city exposed to the disease but not infectious yet. Biologically, this corresponds to contracting the disease, in that all exposed people eventually become infectious.\n", "* $I^u$: Number of people in each city who are infectious but undocumented. In the model, this actually means \"will never be documented\".\n", "* $I^r$: Number of people in each city who are infectious and documented as such. Li et al model reporting delays, so $I^r$ actually corresponds to something like \"case is severe enough to be documented at some point in the future\".\n", "\n", "As we will see below, we will be inferring these states by running an Ensemble-adjusted Kalman Filter (EAKF) forward in time. The state vector of the EAKF is one city-indexed vector for each of these quantities.\n", "\n", "The model has the following inferrable global, time-invariant parameters:\n", "\n", "* $\\beta$: The transmission rate due to documented-infectious individuals.\n", "* $\\mu$: The relative transmission rate due to undocumented-infectious\n", " individuals. This will act through the product $\\mu \\beta$.\n", "* $\\theta$: The intercity mobility factor. This is a factor greater than\n", " 1 correcting for underreporting of mobility data (and for population growth\n", " from 2018 to 2020).\n", "* $Z$: The average incubation period (i.e., time in the \"exposed\" state).\n", "* $\\alpha$: This is the fraction of infections severe enough to be (eventually) documented.\n", "* $D$: The average duration of infections (i.e., time in either \"infectious\" state).\n", "\n", "We will be inferring point estimates for these parameters with an Iterative-Filtering loop around the EAKF for the states.\n", "\n", "The model also depends on un-inferred constants:\n", "* $M$: The intercity mobility matrix. This is time-varying and presumed given. Recall that it's scaled by the inferred parameter $\\theta$ to give the actual population movements between cities.\n", "* $N$: The total number of people in each city. The initial populations are taken as given, and the time-variation of population is computed from the mobility numbers $\\theta M$.\n" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "--4jYF-Q9maG" }, "source": [ "First, we give ourselves some data structures for holding our states and parameters.\n" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "VacihFdC25l4" }, "outputs": [], "source": [ "SEIRComponents = collections.namedtuple(\n", " typename='SEIRComponents',\n", " field_names=[\n", " 'susceptible', # S\n", " 'exposed', # E\n", " 'documented_infectious', # I^r\n", " 'undocumented_infectious', # I^u\n", " # This is the count of new cases in the \"documented infectious\" compartment.\n", " # We need this because we will introduce a reporting delay, between a person\n", " # entering I^r and showing up in the observable case count data.\n", " # This can't be computed from the cumulative `documented_infectious` count,\n", " # because some portion of that population will move to the 'recovered'\n", " # state, which we aren't tracking explicitly.\n", " 'daily_new_documented_infectious'])\n", "\n", "ModelParams = collections.namedtuple(\n", " typename='ModelParams',\n", " field_names=[\n", " 'documented_infectious_tx_rate', # Beta\n", " 'undocumented_infectious_tx_relative_rate', # Mu\n", " 'intercity_underreporting_factor', # Theta\n", " 'average_latency_period', # Z\n", " 'fraction_of_documented_infections', # Alpha\n", " 'average_infection_duration' # D\n", " ]\n", ")" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "kBgUMzTL_2gc" }, "source": [ "We also code Li et al's bounds for the values of the parameters." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "H_HWdcXZ_1Cw" }, "outputs": [], "source": [ "PARAMETER_LOWER_BOUNDS = ModelParams(\n", " documented_infectious_tx_rate=0.8,\n", " undocumented_infectious_tx_relative_rate=0.2,\n", " intercity_underreporting_factor=1.,\n", " average_latency_period=2.,\n", " fraction_of_documented_infections=0.02,\n", " average_infection_duration=2.\n", ")\n", "\n", "PARAMETER_UPPER_BOUNDS = ModelParams(\n", " documented_infectious_tx_rate=1.5,\n", " undocumented_infectious_tx_relative_rate=1.,\n", " intercity_underreporting_factor=1.75,\n", " average_latency_period=5.,\n", " fraction_of_documented_infections=1.,\n", " average_infection_duration=5.\n", ")" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "-yizvLfw-CiT" }, "source": [ "## SEIR Dynamics\n", "\n", "Here we define the relationship between the parameters and state.\n", "\n", "The time-dynamics equations from Li et al (supplemental material, eqns 1-5) are as follows:\n", "\n", "$\\frac{dS_i}{dt} = -\\beta \\frac{S_i I_i^r}{N_i} - \\mu \\beta \\frac{S_i I_i^u}{N_i} + \\theta \\sum_k \\frac{M_{ij} S_j}{N_j - I_j^r} - + \\theta \\sum_k \\frac{M_{ji} S_j}{N_i - I_i^r}$\n", "\n", "$\\frac{dE_i}{dt} = \\beta \\frac{S_i I_i^r}{N_i} + \\mu \\beta \\frac{S_i I_i^u}{N_i} -\\frac{E_i}{Z} + \\theta \\sum_k \\frac{M_{ij} E_j}{N_j - I_j^r} - + \\theta \\sum_k \\frac{M_{ji} E_j}{N_i - I_i^r}$\n", "\n", "$\\frac{dI^r_i}{dt} = \\alpha \\frac{E_i}{Z} - \\frac{I_i^r}{D}$\n", "\n", "$\\frac{dI^u_i}{dt} = (1 - \\alpha) \\frac{E_i}{Z} - \\frac{I_i^u}{D} + \\theta \\sum_k \\frac{M_{ij} I_j^u}{N_j - I_j^r} - + \\theta \\sum_k \\frac{M_{ji} I^u_j}{N_i - I_i^r}$\n", "\n", "$N_i = N_i + \\theta \\sum_j M_{ij} - \\theta \\sum_j M_{ji}$\n", "\n", "As a reminder, the $i$ and $j$ subscripts index cities. These equations model the time-evolution of the disease through\n", "- Contact with infectious individuals leading to more infection;\n", "- Disease progression from \"exposed\" to one of the \"infectious\" states;\n", "- Disease progression from \"infectious\" states to recovery, which we model by removal from the modeled population;\n", "- Inter-city mobility, including exposed or undocumented-infectious persons; and\n", "- Time-variation of daily city populations through inter-city mobility.\n", "\n", "Following Li et al, we assume that people with cases severe enough to eventually be reported do not travel between cities.\n", "\n", "Also following Li et al, we treat these dynamics as subject to term-wise Poisson noise, i.e., each term is actually the rate of a Poisson, a sample from which gives the true change. The Poisson noise is term-wise because subtracting (as opposed to adding) Poisson samples does not yield a Poisson-distributed result.\n", "\n", "We will evolve these dynamics forward in time with the classic fourth-order Runge-Kutta integrator, but first let's define the function that computes them (including sampling the Poisson noise)." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "_Cpj5Lyo-AGw" }, "outputs": [], "source": [ "def sample_state_deltas(\n", " state, population, mobility_matrix, params, seed, is_deterministic=False):\n", " \"\"\"Computes one-step change in state, including Poisson sampling.\n", " \n", " Note that this is coded to support vectorized evaluation on arbitrary-shape\n", " batches of states. This is useful, for example, for running multiple\n", " independent replicas of this model to compute credible intervals for the\n", " parameters. We refer to the arbitrary batch shape with the conventional\n", " `B` in the parameter documentation below. This function also, of course,\n", " supports broadcasting over the batch shape.\n", "\n", " Args:\n", " state: A `SEIRComponents` tuple with fields Tensors of shape\n", " B + [num_locations] giving the current disease state.\n", " population: A Tensor of shape B + [num_locations] giving the current city\n", " populations.\n", " mobility_matrix: A Tensor of shape B + [num_locations, num_locations] giving\n", " the current baseline inter-city mobility.\n", " params: A `ModelParams` tuple with fields Tensors of shape B giving the\n", " global parameters for the current EAKF run.\n", " seed: Initial entropy for pseudo-random number generation. The Poisson\n", " sampling is repeatable by supplying the same seed.\n", " is_deterministic: A `bool` flag to turn off Poisson sampling if desired.\n", "\n", " Returns:\n", " delta: A `SEIRComponents` tuple with fields Tensors of shape\n", " B + [num_locations] giving the one-day changes in the state, according\n", " to equations 1-4 above (including Poisson noise per Li et al).\n", " \"\"\"\n", " undocumented_infectious_fraction = state.undocumented_infectious / population\n", " documented_infectious_fraction = state.documented_infectious / population\n", "\n", " # Anyone not documented as infectious is considered mobile\n", " mobile_population = (population - state.documented_infectious)\n", " def compute_outflow(compartment_population):\n", " raw_mobility = tf.linalg.matvec(\n", " mobility_matrix, compartment_population / mobile_population)\n", " return params.intercity_underreporting_factor * raw_mobility\n", " def compute_inflow(compartment_population):\n", " raw_mobility = tf.linalg.matmul(\n", " mobility_matrix,\n", " (compartment_population / mobile_population)[..., tf.newaxis],\n", " transpose_a=True)\n", " return params.intercity_underreporting_factor * tf.squeeze(\n", " raw_mobility, axis=-1)\n", "\n", " # Helper for sampling the Poisson-variate terms.\n", " seeds = samplers.split_seed(seed, n=11)\n", " if is_deterministic:\n", " def sample_poisson(rate):\n", " return rate\n", " else:\n", " def sample_poisson(rate):\n", " return tfd.Poisson(rate=rate).sample(seed=seeds.pop())\n", "\n", " # Below are the various terms called U1-U12 in the paper. We combined the\n", " # first two, which should be fine; both are poisson so their sum is too, and\n", " # there's no risk (as there could be in other terms) of going negative.\n", " susceptible_becoming_exposed = sample_poisson(\n", " state.susceptible *\n", " (params.documented_infectious_tx_rate *\n", " documented_infectious_fraction +\n", " (params.undocumented_infectious_tx_relative_rate *\n", " params.documented_infectious_tx_rate) *\n", " undocumented_infectious_fraction)) # U1 + U2\n", "\n", " susceptible_population_inflow = sample_poisson(\n", " compute_inflow(state.susceptible)) # U3\n", " susceptible_population_outflow = sample_poisson(\n", " compute_outflow(state.susceptible)) # U4\n", "\n", " exposed_becoming_documented_infectious = sample_poisson(\n", " params.fraction_of_documented_infections *\n", " state.exposed / params.average_latency_period) # U5\n", " exposed_becoming_undocumented_infectious = sample_poisson(\n", " (1 - params.fraction_of_documented_infections) *\n", " state.exposed / params.average_latency_period) # U6\n", "\n", " exposed_population_inflow = sample_poisson(\n", " compute_inflow(state.exposed)) # U7\n", " exposed_population_outflow = sample_poisson(\n", " compute_outflow(state.exposed)) # U8\n", "\n", " documented_infectious_becoming_recovered = sample_poisson(\n", " state.documented_infectious /\n", " params.average_infection_duration) # U9\n", " undocumented_infectious_becoming_recovered = sample_poisson(\n", " state.undocumented_infectious /\n", " params.average_infection_duration) # U10\n", "\n", " undocumented_infectious_population_inflow = sample_poisson(\n", " compute_inflow(state.undocumented_infectious)) # U11\n", " undocumented_infectious_population_outflow = sample_poisson(\n", " compute_outflow(state.undocumented_infectious)) # U12\n", "\n", " # The final state_deltas\n", " return SEIRComponents(\n", " # Equation [1]\n", " susceptible=(-susceptible_becoming_exposed +\n", " susceptible_population_inflow +\n", " -susceptible_population_outflow),\n", " # Equation [2]\n", " exposed=(susceptible_becoming_exposed +\n", " -exposed_becoming_documented_infectious +\n", " -exposed_becoming_undocumented_infectious +\n", " exposed_population_inflow +\n", " -exposed_population_outflow),\n", " # Equation [3]\n", " documented_infectious=(\n", " exposed_becoming_documented_infectious +\n", " -documented_infectious_becoming_recovered),\n", " # Equation [4]\n", " undocumented_infectious=(\n", " exposed_becoming_undocumented_infectious +\n", " -undocumented_infectious_becoming_recovered +\n", " undocumented_infectious_population_inflow +\n", " -undocumented_infectious_population_outflow),\n", " # New to-be-documented infectious cases, subject to the delayed\n", " # observation model.\n", " daily_new_documented_infectious=exposed_becoming_documented_infectious)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "K7T_QQTRKqOE" }, "source": [ "Here's the integrator. This is completely standard, except for passing the PRNG seed through to the `sample_state_deltas` function to get independent Poisson noise at each of the partial steps that the Runge-Kutta method calls for." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "2qx4tX8sCAZv" }, "outputs": [], "source": [ "@tf.function(autograph=False)\n", "def rk4_one_step(state, population, mobility_matrix, params, seed):\n", " \"\"\"Implement one step of RK4, wrapped around a call to sample_state_deltas.\"\"\"\n", " # One seed for each RK sub-step\n", " seeds = samplers.split_seed(seed, n=4)\n", "\n", " deltas = tf.nest.map_structure(tf.zeros_like, state)\n", " combined_deltas = tf.nest.map_structure(tf.zeros_like, state)\n", "\n", " for a, b in zip([1., 2, 2, 1.], [6., 3., 3., 6.]):\n", " next_input = tf.nest.map_structure(\n", " lambda x, delta, a=a: x + delta / a, state, deltas)\n", " deltas = sample_state_deltas(\n", " next_input,\n", " population,\n", " mobility_matrix,\n", " params,\n", " seed=seeds.pop(), is_deterministic=False)\n", " combined_deltas = tf.nest.map_structure(\n", " lambda x, delta, b=b: x + delta / b, combined_deltas, deltas)\n", "\n", " return tf.nest.map_structure(\n", " lambda s, delta: s + tf.round(delta),\n", " state, combined_deltas)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "3gVKuTqi32Bn" }, "source": [ "## Initialization\n", " \n", "Here we implement the initialization scheme from the paper.\n", "\n", "Following Li et al, our inference scheme will be an ensemble adjustment Kalman filter inner loop, surrounded by an iterated filtering outer loop (IF-EAKF). Computationally, that means we need three kinds of initialization:\n", "- Initial state for the inner EAKF\n", "- Initial parameters for the outer IF, which are also the initial\n", " parameters for the first EAKF\n", "- Updating parameters from one IF iteration to the next, which serve\n", " as the initial parameters for each EAKF other than the first.\n", "\n" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "rdRf_UmdvPLo" }, "outputs": [], "source": [ "def initialize_state(num_particles, num_batches, seed):\n", " \"\"\"Initialize the state for a batch of EAKF runs.\n", " \n", " Args:\n", " num_particles: `int` giving the number of particles for the EAKF.\n", " num_batches: `int` giving the number of independent EAKF runs to\n", " initialize in a vectorized batch.\n", " seed: PRNG entropy.\n", " \n", " Returns:\n", " state: A `SEIRComponents` tuple with Tensors of shape [num_particles,\n", " num_batches, num_cities] giving the initial conditions in each\n", " city, in each filter particle, in each batch member.\n", " \"\"\"\n", " num_cities = mobility_matrix_over_time.shape[-2]\n", " state_shape = [num_particles, num_batches, num_cities]\n", " susceptible = initial_population * np.ones(state_shape, dtype=np.float32)\n", " documented_infectious = np.zeros(state_shape, dtype=np.float32)\n", " daily_new_documented_infectious = np.zeros(state_shape, dtype=np.float32)\n", "\n", " # Following Li et al, initialize Wuhan with up to 2000 people exposed\n", " # and another up to 2000 undocumented infectious.\n", " rng = np.random.RandomState(seed[0] % (2**31 - 1))\n", " wuhan_exposed = rng.randint(\n", " 0, 2001, [num_particles, num_batches]).astype(np.float32)\n", " wuhan_undocumented_infectious = rng.randint(\n", " 0, 2001, [num_particles, num_batches]).astype(np.float32)\n", " \n", " # Also following Li et al, initialize cities adjacent to Wuhan with three\n", " # days' worth of additional exposed and undocumented-infectious cases,\n", " # as they may have traveled there before the beginning of the modeling\n", " # period.\n", " exposed = 3 * mobility_matrix_over_time[\n", " WUHAN_IDX, :, 0] * wuhan_exposed[\n", " ..., np.newaxis] / initial_population[WUHAN_IDX]\n", " undocumented_infectious = 3 * mobility_matrix_over_time[\n", " WUHAN_IDX, :, 0] * wuhan_undocumented_infectious[\n", " ..., np.newaxis] / initial_population[WUHAN_IDX]\n", "\n", " exposed[..., WUHAN_IDX] = wuhan_exposed\n", " undocumented_infectious[..., WUHAN_IDX] = wuhan_undocumented_infectious\n", "\n", " # Following Li et al, we do not remove the initial exposed and infectious\n", " # persons from the susceptible population.\n", " return SEIRComponents(\n", " susceptible=tf.constant(susceptible),\n", " exposed=tf.constant(exposed),\n", " documented_infectious=tf.constant(documented_infectious),\n", " undocumented_infectious=tf.constant(undocumented_infectious),\n", " daily_new_documented_infectious=tf.constant(daily_new_documented_infectious))\n", " \n", "def initialize_params(num_particles, num_batches, seed):\n", " \"\"\"Initialize the global parameters for the entire inference run.\n", "\n", " Args:\n", " num_particles: `int` giving the number of particles for the EAKF.\n", " num_batches: `int` giving the number of independent EAKF runs to\n", " initialize in a vectorized batch.\n", " seed: PRNG entropy.\n", " \n", " Returns:\n", " params: A `ModelParams` tuple with fields Tensors of shape\n", " [num_particles, num_batches] giving the global parameters\n", " to use for the first batch of EAKF runs.\n", " \"\"\"\n", " # We have 6 parameters. We'll initialize with a Sobol sequence,\n", " # covering the hyper-rectangle defined by our parameter limits.\n", " halton_sequence = tfp.mcmc.sample_halton_sequence(\n", " dim=6, num_results=num_particles * num_batches, seed=seed)\n", " halton_sequence = tf.reshape(\n", " halton_sequence, [num_particles, num_batches, 6])\n", " halton_sequences = tf.nest.pack_sequence_as(\n", " PARAMETER_LOWER_BOUNDS, tf.split(\n", " halton_sequence, num_or_size_splits=6, axis=-1))\n", " def interpolate(minval, maxval, h):\n", " return (maxval - minval) * h + minval\n", " return tf.nest.map_structure(\n", " interpolate,\n", " PARAMETER_LOWER_BOUNDS, PARAMETER_UPPER_BOUNDS, halton_sequences)\n", "\n", "def update_params(num_particles, num_batches,\n", " prev_params, parameter_variance, seed):\n", " \"\"\"Update the global parameters between EAKF runs.\n", "\n", " Args:\n", " num_particles: `int` giving the number of particles for the EAKF.\n", " num_batches: `int` giving the number of independent EAKF runs to\n", " initialize in a vectorized batch.\n", " prev_params: A `ModelParams` tuple of the parameters used for the previous\n", " EAKF run.\n", " parameter_variance: A `ModelParams` tuple specifying how much to drift\n", " each parameter.\n", " seed: PRNG entropy.\n", " \n", " Returns:\n", " params: A `ModelParams` tuple with fields Tensors of shape\n", " [num_particles, num_batches] giving the global parameters\n", " to use for the next batch of EAKF runs.\n", " \"\"\"\n", " # Initialize near the previous set of parameters. This is the first step\n", " # in Iterated Filtering.\n", " seeds = tf.nest.pack_sequence_as(\n", " prev_params, samplers.split_seed(seed, n=len(prev_params)))\n", " return tf.nest.map_structure(\n", " lambda x, v, seed: x + tf.math.sqrt(v) * tf.random.stateless_normal([\n", " num_particles, num_batches, 1], seed=seed),\n", " prev_params, parameter_variance, seeds)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "jKWm64gF0JkZ" }, "source": [ "## Delays\n", "\n", "One of the important features of this model is taking explicit account of the fact that infections are reported later than they begin. That is, we expect that a person who moves from the $E$ compartment to the $I^r$ compartment on day $t$ may not show up in the observable reported case counts until some later day.\n", "\n", "We assume the delay is gamma-distributed. Following Li et al, we use 1.85 for the shape, and parameterize the rate to produce an average reporting delay of 9 days." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "rFNy6L491BFD" }, "outputs": [], "source": [ "def raw_reporting_delay_distribution(gamma_shape=1.85, reporting_delay=9.):\n", " return tfp.distributions.Gamma(\n", " concentration=gamma_shape, rate=gamma_shape / reporting_delay)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "yQTwUeKr8dVP" }, "source": [ "Our observations are discrete, so we will round the raw (continuous) delays up to the nearest day. We also have a finite data horizon, so the delay distribution for a single person is a categorical over the remaining days. We can therefore compute the per-city predicted observations more efficiently than sampling $O(I^r)$ gammas, by pre-computing multinomial delay probabilities instead." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "0YRv0FjX9DfB" }, "outputs": [], "source": [ "def reporting_delay_probs(num_timesteps, gamma_shape=1.85, reporting_delay=9.):\n", " gamma_dist = raw_reporting_delay_distribution(gamma_shape, reporting_delay)\n", " multinomial_probs = [gamma_dist.cdf(1.)]\n", " for k in range(2, num_timesteps + 1):\n", " multinomial_probs.append(gamma_dist.cdf(k) - gamma_dist.cdf(k - 1))\n", " # For samples that are larger than T.\n", " multinomial_probs.append(gamma_dist.survival_function(num_timesteps))\n", " multinomial_probs = tf.stack(multinomial_probs)\n", " return multinomial_probs" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "7WAHi68lBFqz" }, "source": [ "Here's the code for actually applying these delays to the new daily documented infectious counts:" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "vrPHDvUEBPsS" }, "outputs": [], "source": [ "def delay_reporting(\n", " daily_new_documented_infectious, num_timesteps, t, multinomial_probs, seed):\n", " # This is the distribution of observed infectious counts from the current\n", " # timestep.\n", "\n", " raw_delays = tfd.Multinomial(\n", " total_count=daily_new_documented_infectious,\n", " probs=multinomial_probs).sample(seed=seed)\n", "\n", " # The last bucket is used for samples that are out of range of T + 1. Thus\n", " # they are not going to be observable in this model.\n", " clipped_delays = raw_delays[..., :-1]\n", "\n", " # We can also remove counts that are such that t + i >= T.\n", " clipped_delays = clipped_delays[..., :num_timesteps - t]\n", " # We finally shift everything by t. That means prepending with zeros.\n", " return tf.concat([\n", " tf.zeros(\n", " tf.concat([\n", " tf.shape(clipped_delays)[:-1], [t]], axis=0),\n", " dtype=clipped_delays.dtype),\n", " clipped_delays], axis=-1)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "DRsd3wsW9WYQ" }, "source": [ "## Inference" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "2lO5MVT6M2lc" }, "source": [ "First we'll define some data structures for inference.\n", "\n", "In particular, we'll be wanting to do Iterated Filtering, which packages the\n", "state and parameters together while doing inference. So we'll define\n", "a `ParameterStatePair` object.\n", "\n", "We also want to package any side information to the model." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "6JrCjAhXM6TL" }, "outputs": [], "source": [ "ParameterStatePair = collections.namedtuple(\n", " 'ParameterStatePair', ['state', 'params'])\n", "\n", "# Info that is tracked and mutated but should not have inference performed over.\n", "SideInfo = collections.namedtuple(\n", " 'SideInfo', [\n", " # Observations at every time step.\n", " 'observations_over_time',\n", " 'initial_population',\n", " 'mobility_matrix_over_time',\n", " 'population',\n", " # Used for variance of measured observations.\n", " 'actual_reported_cases',\n", " # Pre-computed buckets for the multinomial distribution.\n", " 'multinomial_probs',\n", " 'seed',\n", " ])\n", "\n", "# Cities can not fall below this fraction of people\n", "MINIMUM_CITY_FRACTION = 0.6\n", "\n", "# How much to inflate the covariance by.\n", "INFLATION_FACTOR = 1.1\n", "\n", "INFLATE_FN = tfes.inflate_by_scaled_identity_fn(INFLATION_FACTOR)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "eoZPQ9YDM9mj" }, "source": [ "Here is the complete observation model, packaged for the Ensemble Kalman Filter.\n", "\n", "The interesting feature is the reporting delays (computed as previously). The upstream model emits the `daily_new_documented_infectious` for each city at each time step." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "lBrt1BkO9Xje" }, "outputs": [], "source": [ "# We observe the observed infections.\n", "def observation_fn(t, state_params, extra):\n", " \"\"\"Generate reported cases.\n", " \n", " Args:\n", " state_params: A `ParameterStatePair` giving the current parameters\n", " and state.\n", " t: Integer giving the current time.\n", " extra: A `SideInfo` carrying auxiliary information.\n", "\n", " Returns:\n", " observations: A Tensor of predicted observables, namely new cases\n", " per city at time `t`.\n", " extra: Update `SideInfo`.\n", " \"\"\"\n", " # Undo padding introduced in `inference`.\n", " daily_new_documented_infectious = state_params.state.daily_new_documented_infectious[..., 0]\n", " # Number of people that we have already committed to become\n", " # observed infectious over time.\n", " # shape: batch + [num_particles, num_cities, time]\n", " observations_over_time = extra.observations_over_time\n", " num_timesteps = observations_over_time.shape[-1]\n", "\n", " seed, new_seed = samplers.split_seed(extra.seed, salt='reporting delay')\n", " \n", " daily_delayed_counts = delay_reporting(\n", " daily_new_documented_infectious, num_timesteps, t,\n", " extra.multinomial_probs, seed)\n", " observations_over_time = observations_over_time + daily_delayed_counts\n", "\n", " extra = extra._replace(\n", " observations_over_time=observations_over_time,\n", " seed=new_seed)\n", "\n", " # Actual predicted new cases, re-padded.\n", " adjusted_observations = observations_over_time[..., t][..., tf.newaxis]\n", " # Finally observations have variance that is a function of the true observations:\n", " return tfd.MultivariateNormalDiag(\n", " loc=adjusted_observations,\n", " scale_diag=tf.math.maximum(\n", " 2., extra.actual_reported_cases[..., t][..., tf.newaxis] / 2.)), extra" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "ugNrSlDAyUc6" }, "source": [ "Here we define the transition dynamics. We've done the semantic work already; here we just package it for the EAKF framework, and, following Li et al, clip city populations to prevent them from getting too small." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "95S7LAj4NB_5" }, "outputs": [], "source": [ "def transition_fn(t, state_params, extra):\n", " \"\"\"SEIR dynamics.\n", "\n", " Args:\n", " state_params: A `ParameterStatePair` giving the current parameters\n", " and state.\n", " t: Integer giving the current time.\n", " extra: A `SideInfo` carrying auxiliary information.\n", "\n", " Returns:\n", " state_params: A `ParameterStatePair` predicted for the next time step.\n", " extra: Updated `SideInfo`.\n", " \"\"\"\n", " mobility_t = extra.mobility_matrix_over_time[..., t]\n", " new_seed, rk4_seed = samplers.split_seed(extra.seed, salt='Transition')\n", " new_state = rk4_one_step(\n", " state_params.state,\n", " extra.population,\n", " mobility_t,\n", " state_params.params,\n", " seed=rk4_seed)\n", "\n", " # Make sure population doesn't go below MINIMUM_CITY_FRACTION.\n", " new_population = (\n", " extra.population + state_params.params.intercity_underreporting_factor * (\n", " # Inflow\n", " tf.reduce_sum(mobility_t, axis=-2) - \n", " # Outflow\n", " tf.reduce_sum(mobility_t, axis=-1)))\n", " new_population = tf.where(\n", " new_population < MINIMUM_CITY_FRACTION * extra.initial_population,\n", " extra.initial_population * MINIMUM_CITY_FRACTION,\n", " new_population)\n", "\n", " extra = extra._replace(population=new_population, seed=new_seed)\n", "\n", " # The Ensemble Kalman Filter code expects the transition function to return a distribution.\n", " # As the dynamics and noise are encapsulated above, we construct a `JointDistribution` that when\n", " # sampled, returns the values above.\n", "\n", " new_state = tfd.JointDistributionNamed(\n", " model=tf.nest.map_structure(lambda x: tfd.VectorDeterministic(x), new_state))\n", " params = tfd.JointDistributionNamed(\n", " model=tf.nest.map_structure(lambda x: tfd.VectorDeterministic(x), state_params.params))\n", " \n", " state_params = tfd.JointDistributionNamed(\n", " model=ParameterStatePair(state=new_state, params=params))\n", "\n", " return state_params, extra" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "nsdNsvzuyaN-" }, "source": [ "Finally we define the inference method. This is two loops, the outer loop\n", "being Iterated Filtering while the inner loop is Ensemble Adjustment Kalman Filtering." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "EUWinMkUNFGJ" }, "outputs": [], "source": [ "# Use tf.function to speed up EAKF prediction and updates.\n", "ensemble_kalman_filter_predict = tf.function(\n", " tfes.ensemble_kalman_filter_predict, autograph=False)\n", "ensemble_adjustment_kalman_filter_update = tf.function(\n", " tfes.ensemble_adjustment_kalman_filter_update, autograph=False)\n", "\n", "def inference(\n", " num_ensembles,\n", " num_batches,\n", " num_iterations,\n", " actual_reported_cases,\n", " mobility_matrix_over_time,\n", " seed=None,\n", " # This is how much to reduce the variance by in every iterative\n", " # filtering step.\n", " variance_shrinkage_factor=0.9,\n", " # Days before infection is reported.\n", " reporting_delay=9.,\n", " # Shape parameter of Gamma distribution.\n", " gamma_shape_parameter=1.85):\n", " \"\"\"Inference for the Shaman, et al. model.\n", "\n", " Args:\n", " num_ensembles: Number of particles to use for EAKF.\n", " num_batches: Number of batches of IF-EAKF to run.\n", " num_iterations: Number of iterations to run iterative filtering.\n", " actual_reported_cases: `Tensor` of shape `[L, T]` where `L` is the number\n", " of cities, and `T` is the timesteps.\n", " mobility_matrix_over_time: `Tensor` of shape `[L, L, T]` which specifies the\n", " mobility between locations over time.\n", " variance_shrinkage_factor: Python `float`. How much to reduce the\n", " variance each iteration of iterated filtering.\n", " reporting_delay: Python `float`. How many days before the infection\n", " is reported.\n", " gamma_shape_parameter: Python `float`. Shape parameter of Gamma distribution\n", " of reporting delays.\n", "\n", " Returns:\n", " result: A `ModelParams` with fields Tensors of shape [num_batches],\n", " containing the inferred parameters at the final iteration.\n", " \"\"\"\n", " print('Starting inference.')\n", " num_timesteps = actual_reported_cases.shape[-1]\n", " params_per_iter = []\n", "\n", " multinomial_probs = reporting_delay_probs(\n", " num_timesteps, gamma_shape_parameter, reporting_delay)\n", "\n", " seed = samplers.sanitize_seed(seed, salt='Inference')\n", "\n", " for i in range(num_iterations):\n", " start_if_time = time.time()\n", " seeds = samplers.split_seed(seed, n=4, salt='Initialize')\n", " if params_per_iter:\n", " parameter_variance = tf.nest.map_structure(\n", " lambda minval, maxval: variance_shrinkage_factor ** (\n", " 2 * i) * (maxval - minval) ** 2 / 4.,\n", " PARAMETER_LOWER_BOUNDS, PARAMETER_UPPER_BOUNDS)\n", " params_t = update_params(\n", " num_ensembles,\n", " num_batches,\n", " prev_params=params_per_iter[-1],\n", " parameter_variance=parameter_variance,\n", " seed=seeds.pop())\n", " else:\n", " params_t = initialize_params(num_ensembles, num_batches, seed=seeds.pop())\n", "\n", " state_t = initialize_state(num_ensembles, num_batches, seed=seeds.pop())\n", " population_t = sum(x for x in state_t)\n", " observations_over_time = tf.zeros(\n", " [num_ensembles,\n", " num_batches,\n", " actual_reported_cases.shape[0], num_timesteps])\n", "\n", " extra = SideInfo(\n", " observations_over_time=observations_over_time,\n", " initial_population=tf.identity(population_t),\n", " mobility_matrix_over_time=mobility_matrix_over_time,\n", " population=population_t,\n", " multinomial_probs=multinomial_probs,\n", " actual_reported_cases=actual_reported_cases,\n", " seed=seeds.pop())\n", "\n", " # Clip states\n", " state_t = clip_state(state_t, population_t)\n", " params_t = clip_params(params_t, seed=seeds.pop())\n", "\n", " # Accrue the parameter over time. We'll be averaging that\n", " # and using that as our MLE estimate.\n", " params_over_time = tf.nest.map_structure(\n", " lambda x: tf.identity(x), params_t)\n", "\n", " state_params = ParameterStatePair(state=state_t, params=params_t)\n", "\n", " eakf_state = tfes.EnsembleKalmanFilterState(\n", " step=tf.constant(0), particles=state_params, extra=extra)\n", "\n", " for j in range(num_timesteps):\n", " seeds = samplers.split_seed(eakf_state.extra.seed, n=3)\n", " \n", " extra = extra._replace(seed=seeds.pop())\n", " \n", " # Predict step.\n", "\n", " # Inflate and clip.\n", " new_particles = INFLATE_FN(eakf_state.particles)\n", " state_t = clip_state(new_particles.state, eakf_state.extra.population)\n", " params_t = clip_params(new_particles.params, seed=seeds.pop())\n", " eakf_state = eakf_state._replace(\n", " particles=ParameterStatePair(params=params_t, state=state_t))\n", "\n", " eakf_predict_state = ensemble_kalman_filter_predict(eakf_state, transition_fn)\n", "\n", " # Clip the state and particles.\n", " state_params = eakf_predict_state.particles\n", " state_t = clip_state(\n", " state_params.state, eakf_predict_state.extra.population)\n", " state_params = ParameterStatePair(state=state_t, params=state_params.params)\n", "\n", " # We preprocess the state and parameters by affixing a 1 dimension. This is because for\n", " # inference, we treat each city as independent. We could also introduce localization by\n", " # considering cities that are adjacent.\n", " state_params = tf.nest.map_structure(lambda x: x[..., tf.newaxis], state_params)\n", " eakf_predict_state = eakf_predict_state._replace(particles=state_params)\n", "\n", " # Update step.\n", " \n", " eakf_update_state = ensemble_adjustment_kalman_filter_update(\n", " eakf_predict_state,\n", " actual_reported_cases[..., j][..., tf.newaxis],\n", " observation_fn)\n", " \n", " state_params = tf.nest.map_structure(\n", " lambda x: x[..., 0], eakf_update_state.particles)\n", "\n", " # Clip to ensure parameters / state are well constrained.\n", " state_t = clip_state(\n", " state_params.state, eakf_update_state.extra.population)\n", " \n", " # Finally for the parameters, we should reduce over all updates. We get\n", " # an extra dimension back so let's do that.\n", " params_t = tf.nest.map_structure(\n", " lambda x, y: x + tf.reduce_sum(y[..., tf.newaxis] - x, axis=-2, keepdims=True),\n", " eakf_predict_state.particles.params, state_params.params)\n", " params_t = clip_params(params_t, seed=seeds.pop())\n", " params_t = tf.nest.map_structure(lambda x: x[..., 0], params_t)\n", "\n", " state_params = ParameterStatePair(state=state_t, params=params_t)\n", " eakf_state = eakf_update_state\n", " eakf_state = eakf_state._replace(particles=state_params)\n", "\n", " # Flatten and collect the inferred parameter at time step t.\n", " params_over_time = tf.nest.map_structure(\n", " lambda s, x: tf.concat([s, x], axis=-1), params_over_time, params_t)\n", "\n", " est_params = tf.nest.map_structure(\n", " # Take the average over the Ensemble and over time.\n", " lambda x: tf.math.reduce_mean(x, axis=[0, -1])[..., tf.newaxis],\n", " params_over_time)\n", " params_per_iter.append(est_params)\n", " print('Iterated Filtering {} / {} Ran in: {:.2f} seconds'.format(\n", " i, num_iterations, time.time() - start_if_time))\n", "\n", " return tf.nest.map_structure(\n", " lambda x: tf.squeeze(x, axis=-1), params_per_iter[-1])" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "UvALK7e1fgKU" }, "source": [ "Final detail: clipping the parameters and state consists of making sure they are within range, and non-negative." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "aQj7o0nU6-ru" }, "outputs": [], "source": [ "def clip_state(state, population):\n", " \"\"\"Clip state to sensible values.\"\"\"\n", " state = tf.nest.map_structure(\n", " lambda x: tf.where(x < 0, 0., x), state)\n", "\n", " # If S > population, then adjust as well.\n", " susceptible = tf.where(state.susceptible > population, population, state.susceptible)\n", " return SEIRComponents(\n", " susceptible=susceptible,\n", " exposed=state.exposed,\n", " documented_infectious=state.documented_infectious,\n", " undocumented_infectious=state.undocumented_infectious,\n", " daily_new_documented_infectious=state.daily_new_documented_infectious)\n", "\n", "def clip_params(params, seed):\n", " \"\"\"Clip parameters to bounds.\"\"\"\n", " def _clip(p, minval, maxval):\n", " return tf.where(\n", " p < minval,\n", " minval * (1. + 0.1 * tf.random.stateless_uniform(p.shape, seed=seed)),\n", " tf.where(p > maxval,\n", " maxval * (1. - 0.1 * tf.random.stateless_uniform(\n", " p.shape, seed=seed)), p))\n", " params = tf.nest.map_structure(\n", " _clip, params, PARAMETER_LOWER_BOUNDS, PARAMETER_UPPER_BOUNDS)\n", "\n", " return params" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "c7ACJedFAyHQ" }, "source": [ "## Running it all together" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": { "height": 207 }, "colab_type": "code", "id": "-T603NTSA0f3", "outputId": "690136df-c409-4b1b-fa06-97e46ced19ba" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Starting inference.\n", "Iterated Filtering 0 / 10 Ran in: 26.65 seconds\n", "Iterated Filtering 1 / 10 Ran in: 28.69 seconds\n", "Iterated Filtering 2 / 10 Ran in: 28.06 seconds\n", "Iterated Filtering 3 / 10 Ran in: 28.48 seconds\n", "Iterated Filtering 4 / 10 Ran in: 28.57 seconds\n", "Iterated Filtering 5 / 10 Ran in: 28.35 seconds\n", "Iterated Filtering 6 / 10 Ran in: 28.35 seconds\n", "Iterated Filtering 7 / 10 Ran in: 28.19 seconds\n", "Iterated Filtering 8 / 10 Ran in: 28.58 seconds\n", "Iterated Filtering 9 / 10 Ran in: 28.23 seconds\n" ] } ], "source": [ "# Let's sample the parameters.\n", "#\n", "# NOTE: Li et al. run inference 1000 times, which would take a few hours.\n", "# Here we run inference 30 times (in a single, vectorized batch).\n", "best_parameters = inference(\n", " num_ensembles=300,\n", " num_batches=30,\n", " num_iterations=10,\n", " actual_reported_cases=observed_daily_infectious_count,\n", " mobility_matrix_over_time=mobility_matrix_over_time)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "ZWjY1KpJ3JuT" }, "source": [ "The results of our inferences. We plot the maximum-likelihood values for all the global paramters to show their variation across our `num_batches` independent runs of inference. This corresponds to Table S1 in the supplemental materials." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": { "height": 298 }, "colab_type": "code", "id": "TZqHM3nIQ8Zj", "outputId": "b2d7e3f7-9ce6-401a-99b1-6d2a895c5f6d" }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "tags": [] }, "output_type": "display_data" } ], "source": [ "fig, axs = plt.subplots(2, 3)\n", "axs[0, 0].boxplot(best_parameters.documented_infectious_tx_rate,\n", " whis=(2.5,97.5), sym='')\n", "axs[0, 0].set_title(r'$\\beta$')\n", "\n", "axs[0, 1].boxplot(best_parameters.undocumented_infectious_tx_relative_rate,\n", " whis=(2.5,97.5), sym='')\n", "axs[0, 1].set_title(r'$\\mu$')\n", "\n", "axs[0, 2].boxplot(best_parameters.intercity_underreporting_factor,\n", " whis=(2.5,97.5), sym='')\n", "axs[0, 2].set_title(r'$\\theta$')\n", "\n", "axs[1, 0].boxplot(best_parameters.average_latency_period,\n", " whis=(2.5,97.5), sym='')\n", "axs[1, 0].set_title(r'$Z$')\n", "\n", "axs[1, 1].boxplot(best_parameters.fraction_of_documented_infections,\n", " whis=(2.5,97.5), sym='')\n", "axs[1, 1].set_title(r'$\\alpha$')\n", "\n", "axs[1, 2].boxplot(best_parameters.average_infection_duration,\n", " whis=(2.5,97.5), sym='')\n", "axs[1, 2].set_title(r'$D$')\n", "plt.tight_layout()" ] } ], "metadata": { "colab": { "collapsed_sections": [], "machine_shape": "hm", "name": "Substantial Undocumented Infection Facilitates the Rapid Dissemination of Novel Coronavirus (SARS-CoV2)", "toc_visible": true }, "kernelspec": { "display_name": "Python 3", "name": "python3" } }, "nbformat": 4, "nbformat_minor": 0 }