看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
本例我们利用 Python 的 pandas 库来实现对疫情播报文案的自动化生成。首先看一下目标文案。新华社 2022年01月23日公众号文章《最新!新增本土病例19例,在这几个地方》原文(节选):
1月22日0—24时,31个省(自治区、直辖市)和新疆生产建设兵团报告新增确诊病例56例。其中境外输入病例37例(上海13例,浙江6例,广东5例,四川4例,云南4例,山东3例,福建1例,广西1例),含14例由无症状感染者转为确诊病例(浙江6例,四川4例,广东3例,广西1例);本土病例19例(北京9例,其中丰台区6例、房山区2例、海淀区1例;天津5例,均在津南区;广东3例,均在珠海市;河南1例,在安阳市;云南1例,在西双版纳傣族自治州),含1例由无症状感染者转为确诊病例(在北京)。无新增死亡病例。新增疑似病例3例,均为境外输入(均在上海)。
接下来,我们进行分析,先将文字描述中的数据结构化,然后再实现自动化生成。
分析上文结构,我们可以得到在表述数据时,分为以下几项:
# 总述
1月22日0—24时,31个省(自治区、直辖市)和新疆生产建设兵团报告新增确诊病例56例。
# 境外
其中境外输入病例37例(上海13例,浙江6例,
广东5例,四川4例,云南4例,山东3例,福建1例,广西1例),
含14例由无症状感染者转为确诊病例(浙江6例,四川4例,广东3例,广西1例);
# 本土
本土病例19例(
北京9例,其中丰台区6例、房山区2例、海淀区1例;
天津5例,均在津南区;
广东3例,均在珠海市;
河南1例,在安阳市;
云南1例,在西双版纳傣族自治州
),
含1例由无症状感染者转为确诊病例(在北京)。
# 死亡病例
无新增死亡病例。
# 疑似病例
新增疑似病例3例,均为境外输入(均在上海)。
再将相关维度进行分析,口径有:
我们整理一下上述的数据,得到一个表格:
'''
日期,来源类型,一级行政区,二级行政区,确诊病例,无症状感染者转为确诊,疑似病例,死亡病例
11月22日,本土病例,北京,丰台区,5,1,0,0
11月22日,本土病例,北京,房山区,2,0,0,0
11月22日,本土病例,北京,海淀区,1,0,0,0
11月22日,本土病例,天津,津南区,5,0,0,0
11月22日,本土病例,广东,珠海市,3,0,0,0
11月22日,本土病例,河南,安阳市,1,0,0,0
11月22日,本土病例,云南,西双版纳傣族自治州,1,0,0,0
11月22日,境外输入,上海,,13,0,3,0
11月22日,境外输入,浙江,,0,6,0,0
11月22日,境外输入,广东,,2,3,0,0
11月22日,境外输入,四川,,0,4,0,0
11月22日,境外输入,云南,,4,0,0,0
11月22日,境外输入,山东,,3,0,0,0
11月22日,境外输入,福建,,1,0,0,0
11月22日,境外输入,广西,,0,1,0,0
'''
这样,我们就提取出了文案中的数据,往后可以按照这个结构整理数据,程序会对这个结构的数据进行处理,生成文案。
以下是读取文案中各个信息的文案生成过程:
df = pd.read_clipboard(sep=',')
df
# ...
# 取当日数据(假定以上表格为所有日期的)
df = df.loc[df.日期=='11月22日']
# 涉及确诊的列
confirmed_cols = ['确诊病例','无症状感染者转为确诊']
# 总病例数
df[confirmed_cols].sum().sum()
# 56
# 境外总数
df.loc[df.来源类型=='境外输入', confirmed_cols].sum().sum()
# 37
# 境外确诊分布
(
df.loc[df.来源类型=='境外输入', ['一级行政区']+confirmed_cols]
.set_index('一级行政区')
.sum(1)
.to_frame('病例数')
.apply(lambda x: x.name+f'{x.病例数}例', axis=1)
.pipe(','.join)
)
# '上海13例,浙江6例,广东5例,四川4例,云南4例,山东3例,福建1例,广西1例'
# 无症状感染者转为确诊病例
df.loc[df.来源类型=='境外输入', '无症状感染者转为确诊'].sum()
# 14
# 无症状感染者转为确诊病例分布
(
df.loc[df.来源类型=='境外输入', ['一级行政区', '无症状感染者转为确诊']]
.loc[df.无症状感染者转为确诊>0]
.set_index('一级行政区')
.sum(1)
.to_frame('病例数')
.apply(lambda x: x.name+f'{x.病例数}例', axis=1)
.pipe(','.join)
)
# '浙江6例,广东3例,四川4例,广西1例'
# 本土病例总数
df.loc[df.来源类型=='本土病例', confirmed_cols].sum().sum()
# 19
# 本土病例分布-二级行政区
district = (
df.set_index(['一级行政区', '二级行政区'])
.loc[lambda d: d.来源类型=='本土病例', confirmed_cols]
.assign(total=lambda x: x.sum(1))
# .total
)
district
# ...
# 一级区域中二级的分布
(
district.query("一级行政区=='北京'")
.total
.to_frame('病例数')
.reset_index()
.apply(lambda x: x.二级行政区+f'{x.病例数}例', axis=1)
.pipe('、'.join)
)
# '丰台区6例、房山区2例、海淀区1例'
以下是本土病例及在二级区域中的分布:
# 将一级区域和二级分布封装为一个函数
def city_district(city_name):
data_str = (
district.query(f"一级行政区=='{city_name}'")
.total
.to_frame('病例数')
.reset_index()
.apply(lambda x: x.二级行政区+f'{x.病例数}例', axis=1)
.pipe('、'.join)
)
# 去掉字符中多少例方法
no_number = lambda x: pd.Series(x).str.split('\d+').str[0].at[0]
# 城市共一例
if district.query(f"一级行政区=='{city_name}'").total.sum() == 1:
by_prefix = '在' + no_number(data_str)
# 城市在一个区
elif district.query(f"一级行政区=='{city_name}'").pipe(len) == 1:
by_prefix = '均在' + no_number(data_str)
else:
by_prefix = '其中'+ data_str
return by_prefix
# 本土病例分布-一级
(
df.set_index(['一级行政区'])
.loc[lambda d: d.来源类型=='本土病例', confirmed_cols]
.assign(total=lambda x: x.sum(1))
.groupby(level=0, sort=False)
.sum()
.total
.to_frame('病例数')
# 调用 city_district
.apply(lambda x: x.name+f'{x.病例数}例,{city_district(x.name)}', axis=1)
.pipe(';'.join)
)
# '北京9例,其中丰台区6例、房山区2例、海淀区1例;天津5例,均在津南区;
# 广东3例,均在珠海市;河南1例,在安阳市;云南1例,在西双版纳傣族自治州'
再最后将这些文案及逻辑拼装为函数就完成了需求。
(完)
更新时间:2024-08-18 16:32:27 标签:pandas 疫情