2019新型冠状病毒(2019-nCoV) - 数据采集、模型预测
关于2019-nCoV的数据采集、模型预测
武汉加油、湖北加油、中国加油!!!
项目背景
2020年开年爆发的新型冠状病毒,新的一年相信对于大家来说都是地狱模式开局,对于我本人也是如此,打乱了很多计划,有些不知所措,但是灾难面前,唯有同舟共济,对此我个人是乐观的,中华民族是不服输的民族,上下5000年历史,比这大的灾难比比皆是,但是我们依然屹立于此,依然活跃于世界舞台,这充分证明了中华民族的韧性,中国万岁;
之前看到丁香园上有实时的动态数据,就想着拉下来进行分析挖掘预测,第一版之前跑了两天后停止了,因为当时数据格式变化比较大,从2月5号开始第二版数据采集脚本,脚本很简单,目前采集间隔是10分钟,不是每10分钟都会采集,这取决于数据是否有变动,这里主要展示数据采集脚本以及一个简单的基于prophet的确诊、疑似、死亡、治愈的预测;
数据采集
数据基于丁香园的实时动态数据,感谢数据展示分享,对于大家了解疫情的实时情况真的帮助很大,各种数据可视化展示,大家也可以点进去看看,做的还是比较精细的,颗粒度最低可以到某个市的某个区,这也证明中国目前在全国统筹方面的能力在日益完善,当然还有很长的路要走,毕竟咱们的目标是星辰大海;
采集方式:主要数据分两部分,一部分是全国的整体情况,一部分是各省市情况,这两部分都处于script元素内,因此其实只需要找到对应的script元素,对于内容文本做截取后,转为json对象即可直接读取内部内容,而整体结构也是简洁明了,相信大家都能搞定的,下面是我的采集脚本,可以直接copy运行的,大家需要注意的主要以下几个点:1. 首先同级目录创建data_new文件夹,2. 一些注释要打开,主要是两部分注释是给csv文件写头行的,所以我写过一次就注释了,第一次运行需要打开,后续注释掉就行,我主要获取五类数据:城市名、确诊数、疑似数(这个只在全国部分有,各省市是没有的)、死亡数、治愈数;
#!/usr/bin/env python
# coding=utf-8
import requests
from bs4 import BeautifulSoup as BS
import json
import time
import sys,os
reload(sys)
sys.setdefaultencoding('utf-8')
while(True):
try:
r = requests.get('https://3g.dxy.cn/newh5/view/pneumonia_peopleapp?from=timeline&isappinstalled=0')
soup = BS(r.content, 'html.parser')
_cn_data = soup.find('script',id='getStatisticsService').get_text()
_s = _cn_data.index('{', _cn_data.index('{')+1)
_e = _cn_data.index('catch')-1
_china = json.loads(_cn_data[_s:_e])
_timestamp = _china['modifyTime']
_cc,_sc,_dc,_cuc = _china['confirmedCount'],_china['suspectedCount'],_china['deadCount'],_china['curedCount']
print _timestamp,_cc,_sc,_dc,_cuc
if open('data_new/湖北省.csv').readlines()[-1].split(',')[0]==str(_timestamp):
#if False:
print('data not flush')
else:
#row = 'timestamp,confirmedCount,suspectedCount,curedCount,deadCount'
#os.system('echo '+row+' >> data_new/中国.csv')
row = ','.join([str(_timestamp),str(_cc),str(_sc),str(_cuc),str(_dc)])
os.system('echo '+row+' >> data_new/中国.csv')
_data = soup.find('script',id='getAreaStat').get_text()
_data = _data[_data.find('['):_data.rfind(']')+1]
_provinces = json.loads(_data)
for _province in _provinces:
print _timestamp,_province['provinceName'],_province['provinceShortName'],_province['confirmedCount'],_province['suspectedCount'],_province['curedCount'],_province['deadCount'],len(_province['cities'])
_fn = _province['provinceName']+'.csv'
#row = 'timestamp,provinceName,cityName,confirmedCount,suspectedCount,curedCount,deadCount,locationId'
#os.system('echo '+row+' >> data_new/'+_fn)
for _city in _province['cities']:
row = ','.join([str(_timestamp),_province['provinceName'],_city['cityName'],str(_city['confirmedCount']),str(_city['suspectedCount']),str(_city['curedCount']),str(_city['deadCount']),str(_city['locationId'])])
os.system('echo '+row+' >> data_new/'+_fn)
except Exception as e:
print(e)
pass
time.sleep(60*10) # 10分钟flush一次
再次感谢丁香园的同学们,对于数据没有做太多保护处理,当然希望大家能够妥善使用;
疫情数据分析
这部分的代码在这里,大家可以随便取之食用,用的数据是WHO发布的全球数据,颗粒度是天,单位是省,分析主要是两部分第一部分是中国各省情况,第二部分是中国整体情况;
中国各省情况 - 确诊人数、死亡/确诊、治愈/确诊
可以看到,死亡率最高的依然是湖北,整个湖北、武汉人民来说却承受了太多太多,我想大家都欠他们一声“你们辛苦了”;
中国整体趋势 - 确诊、死亡、治愈的趋势图,死亡率、治愈率、死亡/治愈
可以看到,确诊、死亡、治愈人数曲线图依然没有缓和的趋势,但是好消息是治愈率在上升,而死亡率在下降,这一点从死亡/治愈的先升后降中也能看到;
确诊、疑似、死亡、治愈预测
这里我只用到了全国的总数据做预测,实际上因为脚本获取的也有各城市的情况,大家一样可以对数据源做一点点修改,就可以做大家感兴趣(比如家乡、工作地、女朋友所在地)等做预测了,还有一个问题需要大家注意,浏览数据时会看到数据有一个跳变的过程,这是因为丁香园的数据来源于国家相关部分,而这些数据的发布应该是有固定时间点的,所以会出现两个相邻数据之间,突然增长了一大段的情况,正常,不需要太惊讶;
全国确诊人数实际情况(2020/02/05到2020/02/09)+预测(实际数据后24小时)
横坐标是时间,纵坐标是人数,右侧没有点的部分的线就是往后24小时的预测人数,可以看到明显的阶梯状,这个我看了数据后大概是这么理解的,只有治愈人数是一天内多次有效更新的,其他确诊、疑似、死亡基本一天内的数据变动不大,所以看起来会有阶梯状;
疑似
死亡
治愈
把治愈的情况放到了最后,是想强调一下,大家对这次疫情要有足够的信心,看目前的数据上升趋势,情况正在逐步得到控制,当然也不可以掉以轻心,隔离依然是最最重要且有效的手段,每个人都做好自己的工作,我相信疫情结束的那一天很快就会到来;
预测部分的代码
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from fbprophet import Prophet
df_train = pd.read_csv('./中国.csv', parse_dates=['timestamp'])
df_train['timestamp'] = df_train['timestamp'].apply(lambda ts:pd.Timestamp(int(ts), unit='ms'))
#df_train.sort_values(['timestamp'],inplace=True)
# confirmedCount
df_train_confirmed = df_train[['timestamp','confirmedCount']].copy()
df_train_confirmed = df_train_confirmed.rename(index=str, columns={"timestamp": "ds", "confirmedCount": "y"})
# suspectedCount
df_train_suspected = df_train[['timestamp','suspectedCount']].copy()
df_train_suspected = df_train_suspected.rename(index=str, columns={"timestamp": "ds", "suspectedCount": "y"})
# deadCount
df_train_dead = df_train[['timestamp','deadCount']].copy()
df_train_dead = df_train_dead.rename(index=str, columns={"timestamp": "ds", "deadCount": "y"})
# curedCount
df_train_cured = df_train[['timestamp','curedCount']].copy()
df_train_cured = df_train_cured.rename(index=str, columns={"timestamp": "ds", "curedCount": "y"})
# test
df_test = pd.DataFrame({})
df_test['ds'] = pd.date_range(start=df_train_confirmed.ds.max(), freq="H", periods=24)
m = Prophet()
#m.fit(df_train_confirmed)
#m.fit(df_train_suspected)
#m.fit(df_train_dead)
m.fit(df_train_cured)
forecast = m.predict(pd.concat([df_train_confirmed[['ds']],df_test[['ds']]]))
#print forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail()
m.plot(forecast)
plt.xlabel('Date')
plt.ylabel('Cured Count')
plt.show()
最后
引用一句WHO的话:
We must remember that these are people, not numbers.
翻译过来意思是:我们必须记住这不是数字,而是人。
希望疫情结束后,每个人都能见到自己的亲人、朋友、同事、每一个自己关心的人,能够给他们一个拥抱,谢谢他们还能陪伴自己,谢谢他们没有抛下自己。
最后的最后
大家可以到我的Github上看看有没有其他需要的东西,目前主要是自己做的机器学习项目、Python各种脚本工具、数据分析挖掘项目以及Follow的大佬、Fork的项目等:
https://github.com/NemoHoHaloAi