大流行何时会下降?使用Pandas在Python中进行评估

图片
大家好。

我在COVID-19上看到了几个仪表板,但是我还没有找到主要的东西-对流行病衰退时间的预测。因此,我写了一个小的Python脚本。他从WHO在Github上的表格中获取数据,按国家进行布局,并绘制趋势线。他根据这些预测做出预测-在每个国家中,按COVID-19病例数排名前20位的国家,感染率预计将下降。我承认,我不是流行病学领域的专家。以下计算基于可公开获得的数据和常识。所有细节均已删减。

从2020年10月10日开始更新-主表和图形已更新。

更新04/16/2020-用户h3cksl更新了这些图并张贴在他的网站上

从04/29/2020开始的更新-现在很明显,不同国家/地区每天感染次数的曲线非常不同。而且它似乎在很大程度上取决于感染的程度。以韩国为模型的理想钟形曲线更有可能是该规则的例外。一种更常见的形式是急剧增加到峰值,然后随着时间的推移逐渐减小。因此,实际上,发病率的下降将比该模型在4月初预测的下降持续的时间更长。

不明飞行物护理分钟


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



, .

, , .

: |


首先,为了评估流行的时间,我使用了公开提供的仪表板。首先是约翰霍普金斯大学系统科学与工程中心所在地

图片

他不祥的朴素漂亮。直到最近,它仍无法建立逐日感染增量的动态,但已得到纠正。令人好奇的是,它使您可以在世界地图上看到大流行的蔓延。考虑到仪表板的黑色和红色色域,建议不要长时间观看。我认为这可能与焦虑发作的发生有关,并引起各种形式的恐慌。

为了让我的手指保持脉搏,我更喜欢关于COVID-19页面在Worldometer资源上。它以表格的形式包含有关国家的信息:

图片

当您单击所需的国家时,我们会陷入有关该国家的更详细的信息,包括感染/恢复/死亡的每日和累积曲线。

还有其他仪表板。例如,对于有关我们国家的深入信息,您只需在Yandex搜索栏中输入“ COVID-19”,您就会发现:

图片

好吧,也许这会停止。在这三个仪表盘上,或者在其他几个仪表盘上,我都找不到带有预测的信息,直到大流行将最终下降。

关于图的一点


目前,感染仅在增加,最有趣的是病例数每天都在增加的图表。这是美国的一个例子:

图片

可以看出,感染人数每天都在增长。当然,在这些图表上,我们并不是在谈论所有感染者(无法确定其确切人数),而只是在谈论确诊病例。为了简洁起见,以下我们将这些已确认感染的病毒简称为“已感染”。被驯服的大流行是

什么样的?这里的一个例子是韩国的图表:

图片

可以看出,感染者的每日增量首先增长,然后达到峰值,然后下降并固定在一定的恒定水平(每天约100人)。这不是对病毒的完全胜利,而是巨大的成功。这使该国得以开始经济发展(尽管他们说,韩国人设法不放慢经济增长速度)并恢复了正常生活。

可以假设其他国家的情况也会以类似的方式发展。也就是说,第一阶段的增长将被稳定所取代,然后,每天的患病人数将下降。结果是钟形曲线。让我们寻找最“受感染”的国家的曲线的峰值。

下载并处理数据


冠状病毒分布数据更新持续的基础上在这里源表包含累积曲线,可以使用小脚本对其进行拾取和预处理。

像这样
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()


因此,您可以获得与仪表板上相同的曲线:

图片

脚本中有一些多余的东西,不需要显示图形,但在接下来的步骤中将需要。例如,我立即列出了20个国家/地区的清单,这些国家今天的感​​染人数最多。顺便说一句-这是所有感染的90%。

继续。病人每天增加的数字相当“嘈杂”。因此,最好使图表平滑。在每日图表中添加趋势线(我使用居中移动平均线)。原来是这样的:

图片

趋势以黑色显示。这是一条具有单个峰的相当平滑的曲线。寻找疾病爆发的开始(红色箭头)和发病高峰(绿色)还有待观察。有了一个峰值,一切都很简单-这是平滑数据的最大值。此外,如果最大值落在图形的最右边,则该峰尚未通过。如果最大值仍留在左侧-最有可能过去是峰值。

爆发的开始可以以不同的方式找到。为简单起见,假设这是每天感染的数量开始超过每天最大感染数量的1%的时间点。

该图非常对称。即,从流行病到高峰的持续时间大约等于从高峰到衰退的持续时间。因此,如果我们找到了从开始到高峰的天数,则大约需要等待相同的天数,直到流行病消退

我们将在下面的脚本中放置所有这些逻辑。

在这样的
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


在输出中,我们得到了前20个国家/地区的此类表格。

更新2020年4月10日:在撰写本文时,俄罗斯不在前二十名之列,但在4月7日,它出现在第二十位。 4月10日离开18日。该表还包括不同国家的隔离措施的日期。

图片

表中的以下各列:
total_confirmed-该国家/地区的受感染总数;
last_day_conf-最后一天的感染数量;
死亡率,%-死亡率(死亡人数/感染人数);
trend_max-趋势最大值;
start_date-流行病在该国开始的日期;
peak_date-高峰日期;
peak_passed-峰值标志(如果为True-峰值已通过);
days_to_peak-从开始到高峰已经过去了多少天;
end_date-流行病的结束日期。

更新日期:2020年4月10日:在20个国家中,有14个国家达到了发病高峰。此外,从大规模感染的开始到高峰,平均需要经过25天:

图片

根据上述逻辑,到4月底,几乎所有正在考虑的国家中的情况都必须恢复正常将会,只有时间会证明一切。

2020年4月10日更新:您可以看到,与韩国的图表相比,欧洲国家的图表在达到峰值后出现了更为缓和的衰退。

还有另一个脚本,可让您显示每个国家的图表。

这个
@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()


俄罗斯的当前情况(2020年4月10日更新):

图片

不幸的是,高峰尚未过去,因此很难对发病率下降的时间做出预测。但是,鉴于疫情持续了26天,我们可以预期在一周内我们会看到一个高峰,并且发病率将开始下降。我敢建议在五月初,这种情况正在恢复正常(我一直是个乐观主义者,我必须说)。

非常感谢您读完本书。健康,力量将与我们同在。以下是按感染人数降序排列的其他20个国家/地区的图表。如果您需要更多最新数据-您可以运行文本中提供的脚本,则将重新计算当前日期的所有内容。

更新10.04.2020-图形已更新。

美国
image

西班牙
image

意大利
image

德国
image

法国
image

中国
image

伊朗
image

英国
image

火鸡
image

瑞士
image

比利时
image

荷兰
image

加拿大
image

奥地利
image

葡萄牙
image

巴西
image

南韩
image

以色列
image

瑞典
image

挪威
image

All Articles