Kapan pandemi akan menurun? Mengevaluasi dengan Python dengan Pandas

gambar
Halo semuanya.

Saya melihat beberapa dasbor pada COVID-19, tetapi saya belum menemukan hal utama - perkiraan waktu resesi epidemi. Oleh karena itu, saya menulis skrip Python kecil. Dia mengambil data dari tabel WHO di Github, menjabarkan negara, dan menggambar garis tren. Dan dia membuat prediksi berdasarkan pada mereka - ketika di masing-masing negara TOP 20 dengan jumlah kasus COVID-19, penurunan infeksi dapat diharapkan. Saya akui, saya bukan ahli di bidang epidemiologi. Perhitungan di bawah ini didasarkan pada data yang tersedia untuk umum dan akal sehat. Semua detail terpotong.

Pembaruan dari 04/10/2020 - tabel utama dan grafik telah diperbarui.

Pembaruan 04/16/2020 - Penggunah3ckslmembuat pembaruan grafik dan mempostingnya di situs webnya .

Pembaruan dari 04/29/2020 - Sekarang menjadi jelas bahwa kurva jumlah infeksi harian sangat berbeda di berbagai negara. Dan tampaknya sangat tergantung pada tingkat infeksi. Kurva berbentuk lonceng yang ideal dimodelkan di Korea Selatan lebih mungkin pengecualian untuk aturan. Bentuk yang lebih umum adalah dengan peningkatan tajam ke puncak dan penurunan selanjutnya yang lebih panjang dari waktu ke waktu. Oleh karena itu, pada kenyataannya, penurunan insidensi akan berlangsung lebih lama daripada yang diprediksi oleh model ini pada awal April.

Menit Perawatan UFO


COVID-19 β€” , SARS-CoV-2 (2019-nCoV). β€” , /, .



, .

, , .

: |


Pada awalnya, untuk menilai waktu epidemi, saya menggunakan dasbor yang tersedia untuk umum. Salah satu yang pertama adalah situs Pusat Sains dan Teknik Sistem Universitas Johns Hopkins.

gambar

Dia cukup cantik dengan kesederhanaannya yang tidak menyenangkan. Sampai saat ini, itu tidak memungkinkan membangun dinamika peningkatan infeksi beberapa hari, tetapi sudah diperbaiki. Dan itu aneh karena memungkinkan Anda untuk melihat penyebaran pandemi di peta dunia. Mengingat gamut hitam dan merah pada dasbor, tidak disarankan untuk menontonnya untuk waktu yang lama. Saya pikir ini mungkin penuh dengan terjadinya serangan kecemasan, berubah menjadi berbagai bentuk panik.

Untuk menjaga agar jari saya tetap berdenyut, saya lebih menyukai halaman tentang COVID-19pada sumber daya Worldometer. Ini berisi informasi tentang negara-negara dalam bentuk tabel:

gambar

Ketika Anda mengklik negara yang diinginkan, kami masuk ke dalam informasi yang lebih rinci tentang itu, termasuk kurva harian dan kumulatif untuk yang terinfeksi / pulih / mati.

Ada dashboard lain. Misalnya, untuk informasi mendalam tentang negara kami, Anda cukup mengetik "COVID-19" di baris pencarian Yandex dan Anda akan menemukan ini:

gambar

Ya, mungkin ini akan berhenti. Baik pada ketiga dasbor ini, maupun pada beberapa dasbor lainnya, saya dapat menemukan informasi dengan perkiraan kapan pandemi akhirnya akan menurun.

Sedikit tentang grafik


Saat ini, infeksi hanya mendapatkan momentum dan yang paling menarik adalah grafik dengan peningkatan jumlah kasus setiap hari. Berikut adalah contoh untuk AS:

gambar

Dapat dilihat bahwa jumlah orang yang terinfeksi bertambah setiap hari. Pada grafik seperti itu, tentu saja, kita tidak berbicara tentang semua orang yang terinfeksi (jumlah pastinya tidak mungkin ditentukan), tetapi hanya tentang kasus yang dikonfirmasi. Tetapi untuk singkatnya, selanjutnya kita akan menyebut ini terinfeksi hanya "terinfeksi".

Seperti apa pandemi yang dijinakkan itu ? Contoh di sini adalah grafik dari Korea Selatan:

gambar

Dapat dilihat bahwa peningkatan harian dari yang terinfeksi pertama kali tumbuh, kemudian mencapai puncaknya, turun dan diperbaiki pada tingkat konstan tertentu (sekitar 100 orang per hari). Ini bukan kemenangan penuh atas virus, tetapi keberhasilan yang signifikan. Ini memungkinkan negara untuk memulai ekonomi (meskipun, kata mereka, orang Korea berhasil tidak memperlambatnya) dan kembali ke kehidupan yang kurang normal.

Dapat diasumsikan bahwa situasi di negara lain akan berkembang dengan cara yang sama. Artinya, pertumbuhan pada tahap pertama akan digantikan oleh stabilisasi, dan kemudian jumlah orang sakit akan menurun setiap hari. Hasilnya adalah kurva berbentuk lonceng. Mari kita mencari puncak kurva negara-negara yang paling β€œterinfeksi”.

Unduh dan proses data


Data distribusi Coronavirus diperbarui secara berkelanjutan di sini . Tabel sumber berisi kurva kumulatif, mereka dapat diambil dan pra-diproses dengan skrip kecil.

Seperti ini
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()


Dengan demikian, Anda bisa mendapatkan kurva yang sama seperti pada dasbor:

gambar

Ada sedikit tambahan dalam skrip yang tidak diperlukan untuk menampilkan grafik, tetapi akan diperlukan pada langkah selanjutnya. Sebagai contoh, saya segera membentuk daftar 20 negara dengan jumlah maksimum yang terinfeksi hari ini. By the way - ini adalah 90% dari semua yang terinfeksi.

Berpindah. Angka peningkatan harian orang sakit cukup "berisik". Karena itu, alangkah baiknya untuk memperlancar grafik. Tambahkan garis tren ke grafik harian (saya menggunakan rata-rata bergerak terpusat). Ternyata entah bagaimana seperti ini:

gambar

Tren ditampilkan dalam warna hitam. Ini adalah kurva yang cukup halus dengan puncak tunggal. Masih menemukan awal wabah penyakit (panah merah) dan puncak kejadian (hijau). Dengan puncak, semuanya sederhana - ini adalah maksimum pada data yang dihaluskan. Selain itu, jika maksimum jatuh pada titik paling kanan dari grafik, maka puncaknya belum terlewati. Jika maksimum tetap ke kiri - kemungkinan puncak tetap di masa lalu.

Awal ledakan dapat ditemukan dengan berbagai cara. Misalkan untuk kesederhanaan bahwa ini adalah titik waktu ketika jumlah yang terinfeksi per hari mulai melebihi 1% dari jumlah maksimum yang terinfeksi per hari.

Grafiknya cukup simetris. Artinya, durasi dari awal epidemi ke puncak kira-kira sama dengan durasi dari puncak ke penurunan.Jadi, jika kita menemukan jumlah hari dari awal hingga puncak, maka kira-kira jumlah hari yang sama harus menunggu sampai epidemi mereda .

Kami akan meletakkan semua logika ini dalam skrip berikut.

Seperti
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


Pada output kami mendapatkan tabel seperti itu untuk 20 negara teratas.

Pembaruan 10.04.2020: Pada saat penulisan, Rusia tidak berada di posisi dua puluh besar, tetapi pada tanggal 7 April muncul di posisi ke-20. 10 April tersisa pada tanggal 18. Tabel ini juga mencakup tanggal tindakan karantina di berbagai negara.

gambar

Kolom berikut ada di tabel:
total_confirmed - jumlah total yang terinfeksi di negara ini;
last_day_conf - jumlah yang terinfeksi pada hari terakhir;
mortalitas,% - tingkat kematian (jumlah orang mati / jumlah yang terinfeksi);
trend_max - tren maksimum;
start_date - tanggal epidemi dimulai di negara ini;
peak_date - tanggal puncak;
peak_passed - flag puncak (jika Benar - puncak lewat);
days_to_peak - berapa hari telah berlalu dari awal hingga puncak;
end_date - tanggal akhir epidemi.

Pembaruan 10.04.2020: puncak kejadian dicapai di 14 negara dari 20. Selain itu, rata-rata, dari awal infeksi massal hingga puncaknya, dibutuhkan rata-rata 25 hari:

gambar

Menurut logika di atas, pada akhir April, situasi harus dinormalisasi di hampir semua negara yang sedang dipertimbangkan . Seperti yang akan terjadi, hanya waktu yang akan mengatakan.

Pembaruan 10.04.2020: Anda dapat melihat bahwa grafik negara-negara Eropa, berbeda dengan grafik Korea Selatan, mengalami resesi yang lebih lembut setelah puncaknya.

Ada skrip lain yang memungkinkan Anda untuk menampilkan grafik untuk masing-masing negara.

Ini
@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()


Berikut adalah situasi saat ini di Rusia (pembaruan 04/10/2020):

gambar

Sayangnya, puncak belum terlewati, sehingga sulit untuk membuat prediksi mengenai waktu penurunan kejadian. Tetapi mengingat bahwa wabah berlangsung selama 26 hari, kita dapat berharap bahwa selama seminggu kita akan melihat puncaknya dan insiden akan mulai menurun. Saya berani mengatakan bahwa pada awal Mei situasinya normal (saya selalu optimis, saya harus mengatakan).

Terima kasih banyak sudah membaca sampai akhir. Jadilah sehat dan kekuatan akan bersama kita. Di bawah ini adalah bagan untuk sisa dari dua puluh negara dalam urutan jumlah yang terinfeksi. Jika Anda memerlukan lebih banyak data terbaru - Anda dapat menjalankan skrip yang diberikan dalam teks, semuanya akan dihitung ulang untuk tanggal saat ini.

Perbarui 10.04.2020 - grafik diperbarui.

Amerika Serikat
image

Spanyol
image

Italia
image

Jerman
image

Perancis
image

Cina
image

Iran
image

Britania Raya
image

Turki
image

Swiss
image

Belgium
image

Belanda
image

Kanada
image

Austria
image

Portugal
image

Brazil
image

Korea Selatan
image

Israel
image

Swedia
image

Norway
image

All Articles