基于正则表达式提取新冠疫情数据
这篇博客主要基于新冠数据进行每日新增病例与累计病例的统计
开发环境:Pycharm 2019.1.1 + python 3.7
一、数据集介绍
数据集中的数据是从2019年12月31到2019年2月28日的新闻数据。
地区信息由“provinceName”标识,其中,每个省份对应着不同的’provinceId’
原始数据属性(部分)为:
属性标签 |
含义 |
id |
标识各条新闻 |
pubDate |
新闻发布时间 |
title |
新闻标题 |
summary |
新闻摘要(主要内容) |
infoSource |
新闻来源 |
provinceId |
地区ID |
provinceName |
地区名称 |
示例:
二、数据处理
-
数据清洗
显然,要从新闻数据中提取湖北和全国每天的新冠肺炎的新增确诊病例数,累计确诊病例数,许多数据属性(如id, infoSource, sourceUrl)是无效的。经过筛选,其中有用的数据属性仅有’pubDate’, ‘title’, ‘summary’, ‘provinceId’ 四种。
使用pandas进行数据清洗,完成后将数据输出为CSV文件。代码如下:
# -*- coding:utf-8 -*-
import pandas as pd
data = pd.read_csv("DXYNews.csv", encoding="utf_8_sig",
usecols=['pubDate', 'title', 'summary', 'provinceId'])
data.to_csv("DXYNews_processed.csv", index=False, encoding="utf_8_sig")
2.读取文件,数据清洗
2. #### 提取指定数据
#根据'provinceId'参数:
#'provinceId'=42 表示湖北省
# 'provinceId'=100 表示全国
# 以此为判别依据进行数据划分。完成后分别导出CSV文件
```python
# 判定省ID,挑选出湖北省的新闻,单独输出为表格
data_hubeiprovince = pd.DataFrame(columns=['pubDate', 'title', 'summary', 'provinceId'])
data_chanese = pd.DataFrame(columns=['pubDate', 'title', 'summary', 'provinceId'])
# 筛选湖南省和全国疫情数据
# provinceId:42表示湖北, 100表示全国
for i in range(data.shape[0]):
if data.loc[i, 'provinceId'] == 42:
data_hubeiprovince = data_hubeiprovince.append(data.iloc[i])
if data.loc[i, 'provinceId'] == 100:
data_chanese = data_chanese.append(data.iloc[i])
data_hubeiprovince.to_csv("DXYNews_hubei_province.csv", index=False, encoding="utf_8_sig")
data_chanese.to_csv("DXYNews_chanese.csv", index=False, encoding="utf_8_sig")
三、正则表达式提取每天新增确诊病例数,累计确诊病例数
匹配策略:
先按标题匹配,关键词为:新增—例,累计—例 若得到匹配结果则用,若无则按内容匹配
按内容匹配时,关键词为:“新增***确诊—例”和“累计确诊—例”或“累计新冠肺炎—例”
若标题和内容中均未匹配到结果,则表明该条新闻不包含疫情数据信息,可以舍弃。如果一条新闻中包含新增病例数或累计病例数其中一种数据的话,将未被包含的那位数置零。
代码实现如下:
# -*- coding:utf-8 -*-
import re
import pandas as pd
# 匹配策略:先按标题匹配,关键词:新增***例,累计***例
# 若有结果则用,若无结果则按内容匹配
def match(datapath, outpath):
dataNews = pd.read_csv(datapath, encoding="utf_8_sig",
usecols=['pubDate', 'title', 'summary', 'provinceId'])
data = dataNews.reindex(columns=['pubDate', 'title', 'summary', 'provinceId', 'New', 'accumulation'])
for i in range(data.shape[0]):
res_new_num = 0
res_add_num = 0
# 新增
res_new_title = re.search(r'新增[\u4e00-\u9fa5]*[0-9]+例', data.iat[i, 1])
if res_new_title is not None:
res_new_num = re.search(r'[0-9]+', res_new_title.group(0)).group(0)
else:
res_new_summary = re.search(r'新增[\u4e00-\u9fa5]*确诊[\u4e00-\u9fa5]*[0-9]+例', data.iat[i, 2])
if res_new_summary is not None:
res_new_num = re.search(r'[0-9]+', res_new_summary.group(0)).group(0)
# 累计
res_add_title = re.search(r'累计[\u4e00-\u9fa5]*[0-9]+例', data.iat[i, 1])
res_add_summary = re.search(r'累计[\u4e00-\u9fa50-9,]*?[确诊|新冠肺炎][\u4e00-\u9fa5]*[0-9]+例', data.iat[i, 2])
print(res_add_summary)
if res_add_title is not None:
res_class = re.search(r'累计治愈出院', res_add_title.group(0))
# 如果不是累计出院的数据则保留
if res_class is None:
res_add_num = re.search(r'[0-9]+', res_add_title.group(0)).group(0)
elif res_add_summary is not None:
res_add = re.search(r'确诊[\u4e00-\u9fa5]*[0-9]+|新冠肺炎[\u4e00-\u9fa5]*[0-9]+', res_add_summary.group(0))
if res_add is not None:
res_add_num = re.search(r'[0-9]+', res_add.group(0)).group(0)
else:
if res_add_summary is not None:
res_add = re.search(r'确诊[\u4e00-\u9fa5]*[0-9]+|新冠肺炎[\u4e00-\u9fa5]*[0-9]+', res_add_summary.group(0))
if res_add is not None:
res_add_num = re.search(r'[0-9]+', res_add.group(0)).group(0)
# 数据调整
if res_new_num != 0 or res_add_num != 0:
data.iat[i, 4] = res_new_num
data.iat[i, 5] = res_add_num
data_result = data.dropna(axis=0, how='any')
data_result.to_csv(outpath, index=False, encoding="utf_8_sig")
return data_result
数据提取后将新数据导出到CSV文件中方便查看。
四、可视化
绘制以日期为横坐标轴的折线图
注:对累计病例来讲,匹配时由于新闻中未提及而设置为0,绘制时需要将这些为零的数据从列表中剔除。尝试了几种不同的方法后,最终使用了最便捷的函数np.isin()方法进行数据剔除。
代码实现如下:
# 绘图函数
def data_draw(data, data2, data3):
# data
time = [datetime.strptime(d, '%Y/%m/%d %H:%M').date() for d in data.values[:, 0]]
plt.figure(1)
plt.subplot(3, 2, 1)
plt.plot(time, data.values[:, 4], 'ro-', color='r', alpha=0.8, linewidth=1)
plt.xlabel('日期')
plt.ylabel('全国新增人数')
data_add = data[~data['accumulation'].isin([0])]
time_add = [datetime.strptime(d, '%Y/%m/%d %H:%M').date() for d in data_add.values[:, 0]]
plt.subplot(3, 2, 2)
plt.plot(time_add, data_add.values[:, 5], 'ro-', color='r', alpha=0.8, linewidth=1)
plt.xlabel('日期')
plt.ylabel('全国累计人数')
# data2
time2 = [datetime.strptime(d, '%Y/%m/%d %H:%M').date() for d in data2.values[:, 0]]
plt.subplot(3, 2, 3)
plt.plot(time2, data2.values[:, 4], 'ro-', color='r', alpha=0.8, linewidth=1)
plt.xlabel('日期')
plt.ylabel('湖北新增人数')
data2_add = data2[~data2['accumulation'].isin([0])]
time2_add = [datetime.strptime(d, '%Y/%m/%d %H:%M').date() for d in data2_add.values[:, 0]]
plt.subplot(3, 2, 4)
plt.plot(time2_add, data2_add.values[:, 5], 'ro-', color='r', alpha=0.8, linewidth=1)
plt.xlabel('日期')
plt.ylabel('湖北累计人数')
# data3
time3 = [datetime.strptime(d, '%Y/%m/%d %H:%M').date() for d in data3.values[:, 0]]
plt.subplot(3, 2, 5)
plt.plot(time3, data3.values[:, 4], 'ro-', color='r', alpha=0.8, linewidth=1)
plt.xlabel('日期')
plt.ylabel('上海新增人数')
data3_add = data3[~data3['accumulation'].isin([0])]
time3_add = [datetime.strptime(d, '%Y/%m/%d %H:%M').date() for d in data3_add.values[:, 0]]
plt.subplot(3, 2, 6)
plt.plot(time3_add, data3_add.values[:, 5], 'ro-', color='r', alpha=0.8, linewidth=1)
plt.xlabel('日期')
plt.ylabel('上海累计人数')
plt.gcf().autofmt_xdate() # 自动旋转日期标记
plt.show()
if __name__ == '__main__':
data_chanese = match("DXYNews_chanese.csv", "match_result_chanese.csv")
data_hubei = match("DXYNews_hubei_province.csv", "match_result_HuBei.csv")
data_shanghai = match('DXYNews_shanghai.csv', "match_result_Shanghai.csv")
data_draw(data_chanese, data_hubei, data_shanghai)
运行结果如下: