<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Exponential Modeling of COVID-19 Confirmed Cases
This notebook explores modeling the spread of COVID-19 confirmed cases as an exponential function. While this is not a good model for long or even medium-term predictions, it is able to fit initial outbreaks quite well. For a more sophisticated and accurate model, see the logistic modeling notebook.
Defining our parameters and loading the data
Here we are looking at the confirmed and fatal cases for Italy through March 17. To apply the model to other countries or dates, just change the code below.
Step1:  Looking at the outbreak
There are months of data, but we only care about when the number of cases started to grow. We define outbreak as whenever the number of cases exceeded certain threshold. In this case, we are using 10.
Step2:  Plotting the data
Let's take a first look at the data. A visual inspection will typically give us a lot of information.
Step3:  Modeling the data
The data appears to follow an exponential curve, it looks straight out of a middle school math textbook cover. Let's see if we can model it using some parameter fitting
Step4:  Validating the model
That curve looks like a very good fit! Even though proper epidemiology models are fundamentally different (because diseases can't grow exponentially indefinitely), the exponential model should be good for short term predictions.
To validate our model, let's try to fit it again without looking at the last 3 days of data. Then, we can estimate the missing days using our model, and verify if the results still hold by comparing what the model thought was going to happen with the actual data.
Step5:  Projecting future data
It looks like our exponential model slightly overestimates the confirmed cases. That's a good sign! It means that the disease is slowing down a bit. The numbers are close enough that a 3-day projection is probably an accurate enough estimate.
Now, let's use the model we fitted earlier which used all the data, and try to predict what the next 3 days will look like.
<ASSISTANT_TASK:>
Python Code:
ESTIMATE_DAYS = 3
data_key = 'IT'
date_limit = '2020-03-17'
import pandas as pd
import seaborn as sns
sns.set()
df = pd.read_csv(f'https://storage.googleapis.com/covid19-open-data/v3/location/{data_key}.csv').set_index('date')
Explanation: Exponential Modeling of COVID-19 Confirmed Cases
This notebook explores modeling the spread of COVID-19 confirmed cases as an exponential function. While this is not a good model for long or even medium-term predictions, it is able to fit initial outbreaks quite well. For a more sophisticated and accurate model, see the logistic modeling notebook.
Defining our parameters and loading the data
Here we are looking at the confirmed and fatal cases for Italy through March 17. To apply the model to other countries or dates, just change the code below.
End of explanation
def get_outbreak_mask(data: pd.DataFrame, threshold: int = 10):
    ''' Returns a mask for > N confirmed cases '''
    return data['total_confirmed'] > threshold
cols = ['total_confirmed', 'total_deceased']
# Get data only for the columns we care about
df = df[cols]
# Get data only for the selected dates
df = df[df.index <= date_limit]
# Get data only after the outbreak begun
df = df[get_outbreak_mask(df)]
Explanation: Looking at the outbreak
There are months of data, but we only care about when the number of cases started to grow. We define outbreak as whenever the number of cases exceeded certain threshold. In this case, we are using 10.
End of explanation
df.plot(kind='bar', figsize=(16, 8));
Explanation: Plotting the data
Let's take a first look at the data. A visual inspection will typically give us a lot of information.
End of explanation
from scipy import optimize
def exponential_function(x: float, a: float, b: float, c: float):
    ''' a * (b ^ x) + c '''
    return a * (b ** x) + c
X, y = list(range(len(df))), df['total_confirmed'].tolist()
params, _ = optimize.curve_fit(exponential_function, X, y)
print('Estimated function: {0:.3f} * ({1:.3f} ^ X) + {2:.3f}'.format(*params))
confirmed = df[['total_confirmed']].rename(columns={'total_confirmed': 'Ground Truth'})
ax = confirmed.plot(kind='bar', figsize=(16, 8))
estimate = [exponential_function(x, *params) for x in X]
ax.plot(df.index, estimate, color='red', label='Estimate')
ax.legend();
Explanation: Modeling the data
The data appears to follow an exponential curve, it looks straight out of a middle school math textbook cover. Let's see if we can model it using some parameter fitting
End of explanation
params_validate, _ = optimize.curve_fit(exponential_function, X[:-ESTIMATE_DAYS], y[:-ESTIMATE_DAYS])
# Project zero for all values except for the last ESTIMATE_DAYS
projected = [0] * len(X[:-ESTIMATE_DAYS]) + [exponential_function(x, *params_validate) for x in X[-ESTIMATE_DAYS:]]
projected = pd.Series(projected, index=df.index, name='Projected')
confirmed = pd.DataFrame({'Ground Truth': df['total_confirmed'], 'Projected': projected})
ax = confirmed.plot(kind='bar', figsize=(16, 8))
estimate = [exponential_function(x, *params_validate) for x in X]
ax.plot(df.index, estimate, color='red', label='Estimate')
ax.legend();
Explanation: Validating the model
That curve looks like a very good fit! Even though proper epidemiology models are fundamentally different (because diseases can't grow exponentially indefinitely), the exponential model should be good for short term predictions.
To validate our model, let's try to fit it again without looking at the last 3 days of data. Then, we can estimate the missing days using our model, and verify if the results still hold by comparing what the model thought was going to happen with the actual data.
End of explanation
import datetime
# Append N new days to our indices
date_format = '%Y-%m-%d'
date_range = [datetime.datetime.strptime(date, date_format) for date in df.index]
for _ in range(ESTIMATE_DAYS): date_range.append(date_range[-1] + datetime.timedelta(days=1))
date_range = [datetime.datetime.strftime(date, date_format) for date in date_range]
# Perform projection with the previously estimated parameters
projected = [0] * len(X) + [exponential_function(x, *params) for x in range(len(X), len(X) + ESTIMATE_DAYS)]
projected = pd.Series(projected, index=date_range, name='Projected')
df_ = pd.DataFrame({'Confirmed': df['total_confirmed'], 'Projected': projected})
ax = df_.plot(kind='bar', figsize=(16, 8))
estimate = [exponential_function(x, *params) for x in range(len(date_range))]
ax.plot(date_range, estimate, color='red', label='Estimate')
ax.legend();
Explanation: Projecting future data
It looks like our exponential model slightly overestimates the confirmed cases. That's a good sign! It means that the disease is slowing down a bit. The numbers are close enough that a 3-day projection is probably an accurate enough estimate.
Now, let's use the model we fitted earlier which used all the data, and try to predict what the next 3 days will look like.
End of explanation
<END_TASK>