​ 20年开始的新冠肺炎席卷全球,我们能从肺炎数据中发现什么规律呢?我提前给你准备了从 2020 年 1 月 22 日到 2020 年 7 月 27 日的数据。

疫情数据分析

数据下载

​ 2020年1月22日到2020年7月27日的数据下载链接:提取码:5mrb

加载数据

​ 用下面的代码在你本地加载数据。

with open("你下载的 day_wise.csv 数据", "r", encoding="utf-8") as f:
    data = f.readlines()

covid = {
    "date": [],
    "data": [],
    "header": [h for h in data[0].strip().split(",")[1:]]
}
for row in data[1:]:
    split_row = row.strip().split(",")
    covid["date"].append(split_row[0])
    covid["data"].append([float(n) for n in split_row[1:]])

​ 确保你的文件引入正确

# 数据
print(covid["data"][:5]) # 数据太多了,我先打 5 行
# print(covid["data"]) # 如果你实在想看全部,就执行这一行
# 日期数据
print(covid["date"][:5]) # 数据太多了,我先打 5 行
# print(covid["date"]) # 如果你实在想看全部,就执行这一行

​ 了解了数据的大概样子,那么来使用你所学到的 Numpy 技能,我们来分析下面这几个问题。

  1. 获取 2020 年 2 月 3 日的所有数据
  2. 2020 年 1 月 24 日之前的累积确诊病例有多少个?
  3. 2020 年 7 月 23 日的新增死亡数是多少?
  4. 从 1 月 25 日到 7 月 22 日,一共增长了多少确诊病例?
  5. 每天新增确诊数和新恢复数的比例?平均比例,标准差各是多少?
  6. 画图展示新增确诊的变化曲线
  7. 画图展示死亡率的变化曲线

某日所有数据

  • 获取 2020 年 2 月 3 日的所有数据

​ 解决这个问题之前,我们需要搞懂使用Numpy获取到特定数据的时候,数据的索引是什么。在Numpy中,我们用来索引的大概率是数字,所以我们得搞清楚对应的数字标号是什么。因为我在为你准备的covid数据中,把日期和标题都用Python列表装起来了,所以你可以通过.index("xxx")功能来获取到它的索引。

​ 我们需要思考的是:找到这一天所对应的索引。还好我已经把日期都用列表给存储起来了。看看日期的存储方式。将日期转换成date_idx之后,我们就能用这个index来获取到那一天的全部数据了。

print("日期列表摘取:", covid["date"][:4])

date_idx = covid["date"].index("2020-02-03")
print("日期->索引转换:", date_idx)

import numpy as np
data = np.array(covid["data"])

for header, number in zip(covid["header"], data[date_idx]):
    print(header, ":", number)

​ 至于,这些人数为什么会是一个小数呢?因为 Numpy 在存储一批数据的时候,它会把数据都存成一个模式,在这套数据中,我们都是以小数(float64)的形式存储的, 所以你才会看到有小数点。

累计确诊

  • 2020 年 1 月 24 日之前的累积确诊病例有多少个?

​ 有了上一个任务的基础,这个任务我们就更加细致地去获取某个具体的数值,我们确定完日期(row)的 index 之后,再确定标题 (column)的 index。 在这个案例中,我们要确定累积确诊数(Conformed)的索引。

row_idx = covid["date"].index("2020-01-24")     # 获取日期索引
column_idx = covid["header"].index("Confirmed") # 获取标题的索引
confirmed0124 = data[row_idx, column_idx]
print("截止 1 月 24 日的累积确诊数:", confirmed0124)

新增死亡

  • 2020年7月23日的新增死亡数是多少?

​ 这还是一个在Numpy Array中选取数据的过程,我们要搞清楚具体的索引是什么。”New deaths”对应的就是新增死亡数,按照之前的流程把数据拿出来:

data = np.array(covid["data"])
row_idx = covid["date"].index("2020-07-23")
column_idx = covid["header"].index("New deaths")
result = data[row_idx,column_idx]
print("2020 年 7 月 23 日的新增死亡数是:",result)

总增长数

  • 从 1 月 25 日到 7 月 22 日,一共增长了多少确诊病例?

​ 获取数据都是小儿科,我们来点真正的数据分析。要基于原有的数据,进行多次加工,来获取新的结论和结果。在这个任务中,我们要进行一次累和的计算。

data = np.array(covid["data"])
row1_idx = covid["date"].index("2020-01-25")
row2_idx = covid["date"].index("2020-07-22")
column_idx = covid["header"].index("New cases")
# 注意要 row1_idx+1 得到从 01-25 这一天的新增
# row2_idx+1 来包含 7 月 22 的结果
new_cases = data[row1_idx:row2_idx+1,column_idx]
overall = new_cases.sum()
print("共新增:",overall)

​ 但这是通过将每日的新增进行求和,数据是不准确的,我们接下来按照累计确诊的个数计算

confirm_idx = covid["header"].index("Confirmed")
confirmed = data[:,confirm_idx]
overall2 = confirmed.sum()
print("另一版本的新增:",overall2)

​ 运行结果

共新增: 15247802.0
另一版本的新增: 15226291.0

​ 可以看到,两个数据不一致,这是因为有人感染了不止一次,因此导致新增的数据里重复计算了,所以用新增数据计算的结果比累计确诊的方式来计算的要多。

​ 具体分析看看,具体是哪天的数据对不上,详细输出一下。

data = np.array(covid["data"])
row1_idx = covid["date"].index("2020-01-25")
row2_idx = covid["date"].index("2020-07-22")
column_idx = covid["header"].index("New cases")
confirm_idx = covid["header"].index("Confirmed")
confirmed = data[:,confirm_idx]
new_cases = data[:,column_idx]
for i in range(row1_idx,row2_idx):
    diff = new_cases[i] - (confirmed[i] - confirmed[i-1])
    if diff != 0:
        print("data index:",i,"差异:",diff)

​ 运行结果:

data index: 62 差异: 15.0
data index: 81 差异: 21.0
...
data index: 176 差异: 3.0
data index: 181 差异: 110.0

确诊恢复比例

  • 每天新增确诊数和新恢复数的比例?平均比例,标准差各是多少?

​ 这一个任务,我们需要再计算计算,会要使用到 Numpy 的批量计算功能,首先确定要拿取到的数据是什么,然后再对这些数据进行计算。 按要求,我们要拿到新增确诊数(New cases),和新的恢复数(New recovered),然后再相除,最后再计算平均值和标准差。

data = np.array(covid["data"])
new_cases_idx = covid["header"].index("New cases")
new_recovered_idx = covid["header"].index("New recovered")

#ratio
ratio = data[:,new_cases_idx] / data[:,new_recovered_idx]
print("比例样本:",ratio[:5])
#比例样本: [         nan  49.5         47.83333333 164.33333333  52.61538462]

​ 我靠,为什么有一个nan啊,nan在Numpy中表示的是 Not a Number, 说明计算有问题。我们单独打印一下,看看为什么出现 nan

print(data[0,new_cases_idx])
print(data[0,new_recovered_idx])
# 0.0
# 0.0

​ 原来是因为 new_recovered_idx 的第一个位置数据为 0,任何数除以 0 是不成立的,所以才会把这个计算给出一个 nan 的结果。 你看做数据分析还是挺有意思吧,会出现各种意想不到的状况。然后我们把 new_recovered 为零的数都剔除掉。

not_zero_mask = data[:, new_recovered_idx] != 0
ratio = data[not_zero_mask, new_cases_idx] / data[not_zero_mask, new_recovered_idx]

# 平均比例, 标准差
ratio_mean = ratio.mean()
ratio_std = ratio.std()
print("比例样本:",ratio[:5])
print("平均比例:", ratio_mean, ";标准差:", ratio_std)
#比例样本: [ 49.5         47.83333333 164.33333333  52.61538462  89.88888889]
#平均比例: 7.049556348053241 ;标准差: 19.094025710450307

​ 得到计算结果后,我们还是能明显发现,被治好的人的确比新增的要多,这就说明,我们自己的存活率还是挺高的。

可视化数据

  • 画图展示新增确诊的变化曲线

​ 有时候,光秃秃的数字并不能生动表现这些数字背后的规律。我们还可以把它画出来。至于如何画,我给你做了一个 draw_line() 的函数,这个函数的背后是 Python 的画图工具 Matplotlib. 不过在这个教程中,并不是重点,我会在之后的画图教程中详细介绍。

​ 现在,我们就来做新增确诊的可视化数据吧。

new_cases_idx = covid["header"].index("New cases")
draw_line(data[:, new_cases_idx])

​ 画图部分省略

总结

​ 数据分析是一件非常有趣的事情。