<jupyter_start><jupyter_text>Estimating Current Cases by CategoryThis notebook explores a methodology to estimate current mild, severe and critical patients. Both mild and critical categories appear to be correlated to independently reported categories from Italy's ministry of health.Most of the reporting of COVID-19 data, including what is reported by the ECDC, focuses on the daily counts of new cases and deaths. While this is useful for tracking the general development of the disease, it provides little information about the capacity required by a health care system to cope with the case load. Here we explore a methodology to estimate total active cases (cases between onset and recovery / death) broken down by category.  Breakdown of casesEarly data from China classified the cases into *mild*, *severe* and *critical* with 80.9%, 13.8% and 4.7% of occurrences respectively ([source](https://www.cnn.com/2020/03/20/health/covid-19-recovery-rates-intl/index.html)). While this might be useful for categorising cases, it does not appear to match some outcome-based data like hospitalization rate where, as of March 27, Italy reported 43.2%, Spain 56.80% and New York 15% of all confirmed cases. Such wild range in hospitalization rates is potentially due to different criteria being used across health care systems as well as hitting potential system capacity limits. Therefore, the estimations performed here cannot be used as a proxy for hospitalization rates unless a country-dependent correcting factor is applied. However, using an estimate of 5% of all cases appears to be a good predictor for ICU admission rates, and 15% of all cases seem to correlate to a rate of confirmed cases that only experience mild symptoms.<jupyter_code># Since reported numbers are approximate, they are rounded for the sake of simplicity
severe_ratio = .15
critical_ratio = .05
mild_ratio = 1 - severe_ratio - critical_ratio<jupyter_output><empty_output><jupyter_text>Discharge time for severe vs critical casesUnfortunately, early data from Chinese sources only reported a median stay of 12 and a mean stay of 12.8 for *all hospitalizations* without specifying which of them required ICU resources.Since we know the ratio of severe vs critical cases, we only need to guess the discharge time of severe cases since there will only be one way to satisfy the constraint of overall hospitalization median and mean. Here, we plot the estimated discharge time for critical cases (y axis) given a discharge time for severe cases (x axis): Seaborn is a Python data visualization library based on matplotlib. It provides a high-level interface for drawing attractive and informative statistical graphics.(*Instead of matplotlib*)![Screenshot 2020-11-26 215020.png](data:image/png;base64,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)<jupyter_code>import numpy as np
import pandas as pd
import seaborn as sns
sns.set()

# Data from early Chinese reports
mean_discharge_time = 12.8
severe_ratio_norm = severe_ratio / (severe_ratio + critical_ratio) 
critical_ratio_norm = critical_ratio / (severe_ratio + critical_ratio) 

def compute_icu_discharge_time(severe_discharge_time, mean_discharge_time: float = 12.8):
    ''' Using mean discharge time from https://www.cnn.com/2020/03/20/health/covid-19-recovery-rates-intl/index.html '''
    return (mean_discharge_time - severe_discharge_time * severe_ratio_norm) / critical_ratio_norm

X = np.linspace(10, 15, 100)
y = np.array([compute_icu_discharge_time(x) for x in X])

X_name = 'Hospitalization time for severe cases (days)'
y_name = 'Hospitalization time for critical cases(days)'
df = pd.DataFrame([(x, y_) for x, y_ in zip(X, y)], columns=[X_name, y_name]).set_index(X_name)
df.plot(figsize=(16, 8), grid=True, ylim=(0, max(y)));<jupyter_output><empty_output><jupyter_text>Because the data is reported daily, we can only pick an estimated whole number for both variables. The only possible value for *hospital discharge days* that would result in a median discharge time of 12 days is, unsurprisingly, 12. Then, the estimated *ICU discharge days* is 15 days.<jupyter_code>severe_recovery_days = 12
critical_recovery_days = 15<jupyter_output><empty_output><jupyter_text>Recovery time for mild casesIn order to estimate the current number of mild cases, there is one more number that we must guess: how many days it takes for recovery, on average, for all cases that are not severe or critical. Reported recovery times from a COVID-19 infection range from 2 weeks ([source](https://www.who.int/docs/default-source/coronaviruse/who-china-joint-mission-on-covid-19-final-report.pdf)) to "a week to 10 days" ([source](https://www.webmd.com/lung/news/20200324/the-other-side-of-covid-19-milder-cases-recovery1)). After experimenting with several choices, using a median recovery time of 7 days appears to match empirical data from multiple official reports.<jupyter_code>mild_recovery_days = 7<jupyter_output><empty_output><jupyter_text>Estimating new cases breakdownUsing Italy's data up to March 27, assuming the proportion of each category remains constant for every new case, daily breakdowns can be estimated by multiplying the number of new cases by the ratios of the respective categories:<jupyter_code>import pandas as pd

# Load country-level data for Italy
data = pd.read_csv('https://storage.googleapis.com/covid19-open-data/v2/IT/main.csv').set_index('date')

# Estimate daily counts per category assuming ratio is constant
data = data[data.index <= '2020-03-27']
data['new_mild'] = data['new_confirmed'] * mild_ratio
data['new_severe'] = data['new_confirmed'] * severe_ratio
data['new_critical'] = data['new_confirmed'] * critical_ratio
data = data[['new_confirmed', 'new_deceased', 'new_mild', 'new_severe', 'new_critical']]

data.tail(7)<jupyter_output><empty_output><jupyter_text>Estimating current cases breakdownNow that we have an estimate for the category breakdown of new cases as well as for the discharge time per category, we can estimate the number of current cases per category by adding up each category over a rolling window:<jupyter_code>data['current_mild'] = data['new_mild'].rolling(round(mild_recovery_days)).sum()
data['current_severe'] = data['new_severe'].rolling(round(severe_recovery_days)).sum()
data['current_critical'] = data['new_critical'].rolling(round(critical_recovery_days)).sum()
data.tail(7)<jupyter_output><empty_output><jupyter_text>Comparing with Italy's home care, hospitalizations and ICU countsItaly categorises the cases into home care, hospitalizations and ICU admission, which appear to map well into *mild*, *severe* and *critical* categories. From Italy's ministry of health, this is the breakdown [as of March 27](https://web.archive.org/web/20200325181518/http://www.salute.gov.it/portale/nuovocoronavirus/dettaglioContenutiNuovoCoronavirus.jsp?lingua=italiano&id=5351&area=nuovoCoronavirus&menu=vuoto) of cases compared to our model estimates:<jupyter_code>estimated = data.iloc[-1]
reported = pd.DataFrame.from_records([
    {'Category': 'current_mild', 'Count': 30920},
    {'Category': 'current_severe', 'Count': 23112},
    {'Category': 'current_critical', 'Count': 3489},
]).set_index('Category')

pd.DataFrame.from_records([
    {
        'Category': col, 
        'Estimated': '{0:.02f}'.format(estimated[col]),
        'Reported': reported.loc[col, 'Count'],
        'Difference': '{0:.02f}%'.format(100.0 * (estimated[col]  - reported.loc[col, 'Count']) / reported.loc[col, 'Count']),
    }
    for col in reported.index.tolist()
]).set_index('Category')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.06753534321239993, 'fraction_numerical': 0.0656617271333674, 'mean_word_length': 8.951694915254237, 'pattern_counts': {'":': 0, '<': 30, '<?xml version=': 0, '>': 29, 'https://': 6, 'lorem ipsum': 0, 'www.': 5, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '108341', 'license': 'Unlicense', 'n_tokens_mistral': 5661, 'n_tokens_neox': 5153, 'n_words': 822, 'path': 'Covid_19_dataset_2.ipynb', 'repo_name': 'dru-44/PDA', 'size': '11742'}