Tutorial exponential grow (synthetic data)¶
In this example, we create a synthenic (i.e. invented) data set, for which we assume pure exponential growth.
In more detail, for the number of daily new cases $n_d(t)$ as a function of day index $t$, we compute
$$ n_d(t) = n_0 R^{t/\tau} $$with $n_0$ being the initial number of infections, $R$ the reproduction number and $\tau$ the serial interval.
We use an R-number of 1.5, assume there are 10 infections in the beginning, and that the serial interval is 4 days. The we plot the 'usual' plots for OSCOVIDA. The numbers can be changed below, of course.
import oscovida as ov
ov.display_binder_link("tutorial-exponential-growth-example.ipynb")
%config InlineBackend.figure_formats = ['svg']
%matplotlib inline
import numpy as np
import pandas as pd
days = 100
n0 = 10 # initial infections
R = 1.2 # R number for infections
tau = 4 # serial interval
dates = pd.date_range("2021-01-01", periods=days, freq='D')
t = np.arange(0, days, 1)
# we need to compute the cumulutive sum of exponential growth
# as the exponential growth equation describes the daily change
# and oscovida expects by default the cumulutive sum of these daily changes
# (and that is also the observable reported by many data sources)
cases = pd.Series(n0*R**(t/tau), index=dates).cumsum()
# if we turn our synthetic data from real numbers to integers,
# then the R-number reconstruction for the first few days is not quite
# a flat line. This can be tested here by uncommenting the next line:
#cases = cases.astype(int)
# for deaths, we assume a different R (just to check the computation
# of R in oscovida works).
Rdeath = 1.3
deaths = pd.Series(n0*Rdeath**(t/tau), index=dates).cumsum()
# optionally turn deaths into integer numbers
#deaths = deaths.astype(int)
ax, _, _ = ov.overview(country="Exponential growth example",
data=(cases, deaths));
Plot 1: We see that the exponential growth appears as a straight line in the logarithmic plot.
Plot 2 and 3: Here the exponential curve of the daily cases and deaths is visible.
Plot 4: The green line rows the R number, and shows that this is 1.2 (as in the variable R
when we created the synthetic data above. In the reconstruction of R
, we assume the serial interval $\tau$ =tau
of 4 days: if tau
is changed in the creation of the data, the reconstruction of the value R
will give different results because it assumes tau=4
. (see compute_R
in this oscovida.py file)
The blue line shows the day-to-day growth factor $c$ of the daily new changes. So the daily new cases are given by $c$ multiplied with the cases from the day before:
daily_cases = cases.diff()
daily_cases[6]/daily_cases[5]
From the equation, we can also work out the general result for exponential growth and find (the same number):
R**(1/tau)
Plot 5 shows the same entities for deaths rather than cases.
Plot 6 shows the doubling time of the cumulative number of cases.
The doubling time of the daily cases can be computed (assuming exponential growth) using the oscovida function double_time_exponential
(see Wikipedia for equation). It needs as input the ratio of data points 2 and 1 (such as $n_d(2) / n_d(1) $), and the number of days between those two data points $t_2$ and $t_1$:
ov.double_time_exponential(daily_cases[6]/daily_cases[5], 1)
ov.double_time_exponential(daily_cases[60]/daily_cases[5], 55)
Because this is perfect exponential growth, we get the same doubling time irrespective of which two data points we base this on.
What is shown in plot 6 now is the doubling time of the cumulative cases. This does not show exponential growth and in particular the doubling time changes.
ov.double_time_exponential(cases[2]/cases[1], 1)
ov.double_time_exponential(cases[99]/cases[98], 1)
If we only plot the last few weeks of the data, the exponential growth is harder to see:
ax, _, _ = ov.overview(country="Exponential growth example", region="region", subregion="subregion",
weeks=5, data=(cases, deaths));