Wann wird die Pandemie abnehmen? Auswertung in Python mit Pandas

Bild
Hallo alle zusammen.

Ich habe mehrere Dashboards auf COVID-19 gesehen, aber ich habe die Hauptsache noch nicht gefunden - die Vorhersage des Zeitpunkts des Niedergangs der Epidemie. Deshalb habe ich ein kleines Python-Skript geschrieben. Er nimmt Daten aus WHO-Tabellen zu Github, legt sie nach Ländern an und zeichnet Trendlinien. Und er macht darauf basierende Vorhersagen - wenn in jedem Land der TOP 20 nach der Anzahl der Fälle von COVID-19 ein Rückgang der Infektionen zu erwarten ist. Ich gebe zu, ich bin kein Experte auf dem Gebiet der Epidemiologie. Die folgenden Berechnungen basieren auf öffentlich verfügbaren Daten und gesundem Menschenverstand. Alle Details sind unterschnitten.

Update vom 10.04.2020 - Die Haupttabelle und die Grafiken wurden aktualisiert.

Update 16.04.2020 - Benutzerh3ckslhat die Grafiken aktualisiert und auf seiner Website veröffentlicht .

Update vom 29.04.2020 - Es hat sich nun gezeigt, dass die Kurven der täglichen Anzahl von Infektionen in verschiedenen Ländern sehr unterschiedlich sind. Und es scheint stark vom Ausmaß der Infektion abzuhängen. Eine ideale glockenförmige Kurve nach dem Vorbild Südkoreas ist eher eine Ausnahme von der Regel. Eine häufigere Form ist eine starke Zunahme eines Peaks und eine anschließende Abnahme, die sich im Laufe der Zeit verlängert. In der Realität wird der Rückgang der Inzidenz daher länger anhalten als von diesem Modell Anfang April vorhergesagt.

UFO Care Minute


COVID-19 — , SARS-CoV-2 (2019-nCoV). — , /, .



, .

, , .

: |


Um den Zeitpunkt der Epidemie zu beurteilen, habe ich zunächst öffentlich zugängliche Dashboards verwendet. Eine der ersten war die Website des Zentrums für Systemwissenschaft und -technik der Johns Hopkins University.

Bild

Er ist ziemlich hübsch mit seiner bedrohlichen Einfachheit. Bis vor kurzem war es nicht möglich, die Dynamik der Zunahme von Infektionen um Tage aufzubauen, aber es wurde korrigiert. Und es ist insofern merkwürdig, als Sie die Ausbreitung einer Pandemie auf einer Weltkarte sehen können. Angesichts der Schwarz-Rot-Farbskala des Dashboards wird nicht empfohlen, es lange anzusehen. Ich denke, dies kann mit dem Auftreten von Angstattacken behaftet sein, die sich in verschiedene Formen der Panik verwandeln.

Um immer am Puls der Zeit zu bleiben, hat mir die Seite über COVID-19 mehr gefallenauf der Worldometer-Ressource. Es enthält Informationen zu Ländern in Form einer Tabelle:

Bild

Wenn Sie auf das gewünschte Land klicken, werden detailliertere Informationen dazu angezeigt, einschließlich täglicher und kumulativer Kurven für Infizierte / Wiederhergestellte / Tote.

Es gibt andere Dashboards. Für detaillierte Informationen über unser Land können Sie beispielsweise einfach "COVID-19" in die Yandex-Suchzeile eingeben und Sie werden Folgendes finden:

Bild

Nun, vielleicht hört dies auf. Weder auf diesen drei Dashboards noch auf mehreren anderen konnte ich Informationen mit Prognosen finden, wann die Pandemie schließlich abnehmen wird.

Ein bisschen über Grafiken


Derzeit gewinnt die Infektion nur an Dynamik und am interessantesten sind die Grafiken mit einer täglichen Zunahme der Fallzahlen. Hier ein Beispiel für die USA:

Bild

Es ist zu sehen, dass die Zahl der Infizierten täglich steigt. In solchen Grafiken sprechen wir natürlich nicht über alle infizierten Personen (ihre genaue Anzahl kann nicht bestimmt werden), sondern nur über bestätigte Fälle. Der Kürze halber werden wir diese bestätigten Infektionen im Folgenden einfach als "infiziert" bezeichnen.

Wie sieht eine gezähmte Pandemie aus ? Ein Beispiel hier ist eine Grafik von Südkorea:

Bild

Es ist ersichtlich, dass das tägliche Inkrement der Infizierten zuerst wuchs, dann einen Höhepunkt erreichte, sank und auf ein bestimmtes konstantes Niveau (etwa 100 Personen pro Tag) fixierte. Dies ist kein vollständiger Sieg über das Virus, sondern ein bedeutender Erfolg. Dies ermöglichte es dem Land, die Wirtschaft anzukurbeln (obwohl es den Koreanern gelungen ist, sie nicht zu verlangsamen) und zu einem weniger normalen Leben zurückzukehren.

Es ist davon auszugehen, dass sich die Situation in anderen Ländern ähnlich entwickeln wird. Das heißt, das Wachstum in der ersten Phase wird durch eine Stabilisierung ersetzt, und dann wird die Zahl der Kranken jeden Tag sinken. Das Ergebnis ist eine glockenförmige Kurve. Lassen Sie uns nach den Spitzen der Kurven der am stärksten „infizierten“ Länder suchen.

Daten herunterladen und verarbeiten


Coronaverteilungsdaten werden laufend auf dem neuesten Stand hier . Die Quelltabellen enthalten kumulative Kurven, sie können mit einem kleinen Skript aufgenommen und vorverarbeitet werden.

So was
import pandas as pd
import ipywidgets as widgets
from ipywidgets import interact
import matplotlib.pyplot as plt

pd.set_option('display.max_columns', None)

#  
url = 'https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/'
confirmed = pd.read_csv(url + 'time_series_covid19_confirmed_global.csv', sep = ',')
deaths = pd.read_csv(url + 'time_series_covid19_deaths_global.csv', sep = ',')
recovered = pd.read_csv(url + 'time_series_covid19_recovered_global.csv', sep = ',')

#   -   'dd.mm.yy'
new_cols = list(confirmed.columns[:4]) + list(confirmed.columns[4:].map(lambda x: '{0:02d}.{1:02d}.{2:d}'.format(int(x.split(sep='/')[1]), int(x.split(sep='/')[0]), int(x.split(sep='/')[2]))))
confirmed.columns = new_cols
recovered.columns = new_cols
deaths.columns = new_cols

#     
confirmed_daily = confirmed.copy()
confirmed_daily.iloc[:,4:] = confirmed_daily.iloc[:,4:].diff(axis=1)
deaths_daily = deaths.copy()
deaths_daily.iloc[:,4:] = deaths_daily.iloc[:,4:].diff(axis=1)
recovered_daily = recovered.copy()
recovered_daily.iloc[:,4:] = recovered_daily.iloc[:,4:].diff(axis=1)

#       
smooth_conf_daily = confirmed_daily.copy()
smooth_conf_daily.iloc[:,4:] = smooth_conf_daily.iloc[:,4:].rolling(window=8, min_periods=2, center=True, axis=1).mean()
smooth_conf_daily.iloc[:,4:] = smooth_conf_daily.iloc[:,4:].round(1)

#   ,    
last_date = confirmed.columns[-1]

#  20       
confirmed_top = confirmed.iloc[:, [1, -1]].groupby('Country/Region').sum().sort_values(last_date, ascending = False).head(20)
countries = list(confirmed_top.index)

# ,      20 
conf_tot_ratio = confirmed_top.sum() / confirmed.iloc[:, 4:].sum()[-1]

#    
# countries.append('Russia')

#       ,   
l1 = 'Infected at ' + last_date + ' - ' + str(confirmed.iloc[:, 4:].sum()[-1])
l2 = 'Recovered at ' + last_date + ' - ' + str(recovered.iloc[:, 4:].sum()[-1])
l3 = 'Dead at ' + last_date + ' - ' + str(deaths.iloc[:, 4:].sum()[-1])

#      
fig, ax = plt.subplots(figsize = [16,6])
ax.plot(confirmed.iloc[:, 4:].sum(), '-', alpha = 0.6, color = 'orange', label = l1)
ax.plot(recovered.iloc[:, 4:].sum(), '-', alpha = 0.6, color = 'green', label = l2)
ax.plot(deaths.iloc[:, 4:].sum(), '-', alpha = 0.6, color = 'red', label = l3)

ax.legend(loc = 'upper left', prop=dict(size=12))
ax.xaxis.grid(which='minor')
ax.yaxis.grid()
ax.tick_params(axis = 'x', labelrotation = 90)
plt.title('COVID-19 in all countries. Top 20 countries consists {:.2%} of total confirmed infected cases.'.format(conf_tot_ratio[0]))
plt.show()


Auf diese Weise können Sie dieselben Kurven wie auf Dashboards erhalten:

Bild

Das Skript enthält ein kleines Extra, das nicht zum Anzeigen des Diagramms benötigt wird, aber in den nächsten Schritten benötigt wird. Zum Beispiel habe ich sofort eine Liste von 20 Ländern mit der heutigen Höchstzahl an Infizierten erstellt. Übrigens - das sind 90% aller Infizierten.

Mach weiter. Die Zahlen der täglichen Zunahme der Kranken sind ziemlich "laut". Daher wäre es schön, das Diagramm zu glätten. Fügen Sie den Tages-Charts eine Trendlinie hinzu (ich habe einen zentrierten gleitenden Durchschnitt verwendet). Es stellt sich irgendwie so heraus:

Bild

Der Trend ist schwarz dargestellt. Dies ist eine ziemlich glatte Kurve mit einem einzelnen Peak. Es bleibt der Beginn des Ausbruchs der Krankheit (roter Pfeil) und die maximale Inzidenz (grün) zu ermitteln. Mit einem Peak ist alles einfach - dies ist das Maximum für geglättete Daten. Wenn das Maximum auf den äußersten rechten Punkt des Diagramms fällt, wurde der Peak noch nicht überschritten. Wenn das Maximum links bleibt, ist der Peak höchstwahrscheinlich in der Vergangenheit geblieben.

Der Beginn des Bursts kann auf verschiedene Arten gefunden werden. Nehmen wir der Einfachheit halber an, dass dies der Zeitpunkt ist, an dem die Anzahl der Infizierten pro Tag 1% der maximalen Anzahl der Infizierten pro Tag überschreitet.

Der Graph ist ziemlich symmetrisch. Das heißt, die Dauer vom Ausbruch der Epidemie bis zu einem Höhepunkt entspricht ungefähr der Dauer vom Höhepunkt bis zum Rückgang.Wenn wir also die Anzahl der Tage vom Beginn bis zum Höhepunkt finden, muss ungefähr die gleiche Anzahl von Tagen warten, bis die Epidemie abgeklungen ist .

Wir werden all diese Logik in das folgende Skript legen.

In solch einem
from datetime import timedelta, datetime

#     20  + .
confirmed_top = confirmed_top.rename(columns={str(last_date): 'total_confirmed'})
dates = [i for i in confirmed.columns[4:]]

for country in countries:
    
    #       ,      ,  
    confirmed_top.loc[country, 'total_confirmed'] = confirmed.loc[confirmed['Country/Region'] == country,:].sum()[4:][-1]
    confirmed_top.loc[country, 'last_day_conf'] = confirmed.loc[confirmed['Country/Region'] == country,:].sum()[-1] - confirmed.loc[confirmed['Country/Region'] == country,:].sum()[-2]
    confirmed_top.loc[country, 'mortality, %'] = round(deaths.loc[deaths['Country/Region'] == country,:].sum()[4:][-1]/confirmed.loc[confirmed['Country/Region'] == country,:].sum()[4:][-1]*100, 1)
    
    #       .
    smoothed_conf_max = round(smooth_conf_daily[smooth_conf_daily['Country/Region'] == country].iloc[:,4:].sum().max(), 2)
    peak_date = smooth_conf_daily[smooth_conf_daily['Country/Region'] == country].iloc[:,4:].sum().idxmax()
    peak_day = dates.index(peak_date)
    
    #      ,      1%    
    start_day = (smooth_conf_daily[smooth_conf_daily['Country/Region'] == country].iloc[:,4:].sum() < smoothed_conf_max/100).sum()
    start_date = dates[start_day-1]
    
    #     
    confirmed_top.loc[country, 'trend_max'] = smoothed_conf_max
    confirmed_top.loc[country, 'start_date'] = start_date
    confirmed_top.loc[country, 'peak_date'] = peak_date
    confirmed_top.loc[country, 'peak_passed'] = round(smooth_conf_daily.loc[smooth_conf_daily['Country/Region'] == country, last_date].sum(), 2) != smoothed_conf_max
    confirmed_top.loc[country, 'days_to_peak'] = peak_day - start_day
    
    #   ,    
    if confirmed_top.loc[country, 'peak_passed']:
         confirmed_top.loc[country, 'end_date'] = (datetime.strptime(confirmed_top.loc[country, 'peak_date']+'20', "%d.%m.%Y").date() + timedelta(confirmed_top.loc[country, 'days_to_peak'])).strftime('%d.%m.%Y')

#    
confirmed_top.loc['China', 'start_date'] = '22.01.20'
confirmed_top


Am Ausgang bekommen wir genau eine solche Tabelle für die Top 20 Länder.

Update 10.04.2020: Zum Zeitpunkt des Schreibens war Russland nicht unter den Top 20, aber am 7. April erschien es auf dem 20. Platz. Der 10. April reiste am 18. ab. Die Tabelle enthält auch die Daten der Quarantänemaßnahmen in verschiedenen Ländern.

Bild

Die folgenden Spalten befinden sich in der Tabelle:
total_confirmed - die Gesamtzahl der im Land infizierten Personen;
last_day_conf - die Anzahl der am letzten Tag infizierten Personen;
Mortalität,% - Mortalitätsrate (Anzahl der Toten / Anzahl der Infizierten);
trend_max - Trendmaximum;
start_date - Datum, an dem die Epidemie im Land begann;
peak_date - Spitzendatum;
Peak_passed - Peak Flag (wenn True - Peak bestanden);
days_to_peak - wie viele Tage sind vom Anfang bis zum Höhepunkt vergangen;
end_date - Enddatum der Epidemie.

Update 10.04.2020: Der Inzidenzpeak wurde in 14 von 20 Ländern erreicht. Darüber hinaus dauert es im Durchschnitt vom Beginn der Masseninfektionen bis zum Peak durchschnittlich 25 Tage:

Bild

Nach der obigen Logik muss sich die Situation bis Ende April in fast allen betrachteten Ländern normalisieren . Wie es sein wird, wird nur die Zeit zeigen.

Update 10.04.2020: Sie können sehen, dass die Charts der europäischen Länder im Gegensatz zum Chart von Südkorea nach dem Höhepunkt eine leichtere Rezession haben.

Es gibt ein anderes Skript, mit dem Sie Diagramme für jedes Land anzeigen können.

Diese
@interact
def plot_by_country(country = countries):
    
    #   
    l1 = 'Infected at ' + last_date + ' - ' + str(confirmed.loc[confirmed['Country/Region'] == country,:].sum()[-1])
    l2 = 'Recovered at ' + last_date + ' - ' + str(recovered.loc[recovered['Country/Region'] == country,:].sum()[-1])
    l3 = 'Dead at ' + last_date + ' - ' + str(deaths.loc[deaths['Country/Region'] == country,:].sum()[-1])
    
    #        
    df = pd.DataFrame(confirmed_daily.loc[confirmed_daily['Country/Region'] == country,:].sum()[4:])
    df.columns = ['confirmed_daily']
    df['recovered_daily'] = recovered_daily.loc[recovered_daily['Country/Region'] == country,:].sum()[4:]
    df['deaths_daily'] = deaths_daily.loc[deaths_daily['Country/Region'] == country,:].sum()[4:]
    df['deaths_daily'] = deaths_daily.loc[deaths_daily['Country/Region'] == country,:].sum()[4:]
    df['smooth_conf_daily'] = smooth_conf_daily.loc[smooth_conf_daily['Country/Region'] == country,:].sum()[4:]
    
    #  
    fig, ax = plt.subplots(figsize = [16,6], nrows = 1)
    plt.title('COVID-19 dinamics daily in ' + country)
    
    #      ,   
    ax.bar(df.index, df.confirmed_daily, alpha = 0.5, color = 'orange', label = l1)
    ax.bar(df.index, df.recovered_daily, alpha = 0.6, color = 'green', label = l2)
    ax.bar(df.index, df.deaths_daily, alpha = 0.7, color = 'red', label = l3)
    ax.plot(df.index, df.smooth_conf_daily, alpha = 0.7, color = 'black')
    
    #     .
    start_date = confirmed_top[confirmed_top.index == country].start_date.iloc[0]
    start_point = smooth_conf_daily.loc[smooth_conf_daily['Country/Region'] == country, start_date].sum()
    ax.plot_date(start_date, start_point, 'o', alpha = 0.7, color = 'black')
    shift = confirmed_top.loc[confirmed_top.index == country, 'trend_max'].iloc[0]/40
    plt.text(start_date, start_point + shift, 'Start at ' + start_date, ha ='right', fontsize = 20)
    
    peak_date = confirmed_top[confirmed_top.index == country].peak_date.iloc[0]
    peak_point = smooth_conf_daily.loc[smooth_conf_daily['Country/Region'] == country, peak_date].sum()
    ax.plot_date(peak_date, peak_point, 'o', alpha = 0.7, color = 'black')
    plt.text(peak_date, peak_point + shift, 'Peak at ' + peak_date, ha ='right', fontsize = 20)
    
    ax.xaxis.grid(False)
    ax.yaxis.grid(False)
    ax.tick_params(axis = 'x', labelrotation = 90)
    ax.legend(loc = 'upper left', prop=dict(size=12))
    
    #         .
    max_pos = max(df['confirmed_daily'].max(), df['recovered_daily'].max())
    if confirmed_top[confirmed_top.index == country].peak_passed.iloc[0]:
        estimation = 'peak is passed - end of infection ' + confirmed_top[confirmed_top.index == country].end_date.iloc[0]
    else:
        estimation = 'peak is not passed - end of infection is not clear'
    plt.text(df.index[len(df.index)//2], 3*max_pos//4, country, ha ='center', fontsize = 50)
    plt.text(df.index[len(df.index)//2], 2*max_pos//3, estimation, ha ='center', fontsize = 20)
    
    #plt.savefig(country + '.png', bbox_inches='tight', dpi = 75)
    plt.show()


Hier ist die aktuelle Situation in Russland (Aktualisierung vom 10.04.2020):

Bild

Leider wurde der Höchststand noch nicht überschritten, so dass es schwierig ist, Vorhersagen über den Zeitpunkt des Rückgangs der Inzidenz zu treffen. Angesichts der Tatsache, dass der Ausbruch derzeit 26 Tage dauert, können wir davon ausgehen, dass wir während der Woche einen Höhepunkt sehen und die Inzidenz abnehmen wird. Ich würde es wagen vorzuschlagen, dass sich die Situation Anfang Mai normalisiert (ich war immer ein Optimist, muss ich sagen).

Vielen Dank für das Lesen bis zum Ende. Sei gesund und Kraft wird bei uns sein. Nachfolgend finden Sie Diagramme für die übrigen zwanzig Länder in absteigender Reihenfolge der Anzahl der Infizierten. Wenn Sie neuere Daten benötigen - Sie können die im Text angegebenen Skripte ausführen, wird alles für das aktuelle Datum neu berechnet.

Update 10.04.2020 - Die Grafiken werden aktualisiert.

USA
image

Spanien
image

Italien
image

Deutschland
image

Frankreich
image

China
image

Ich rannte
image

Großbritannien
image

Truthahn
image

Schweiz
image

Belgien
image

Niederlande
image

Kanada
image

Österreich
image

Portugal
image

Brasilien
image

Südkorea
image

Israel
image

Schweden
image

Norwegen
image

All Articles