前言:
大家好。由于最近冠状病毒肆虐,大家都被迫困在家里,今天晚上闲来无事,就突然想做个冠状病毒确诊人数的预测。这里面有三个主要内容:1、数据获取 2、画出来图看看数据的走势 3、建立模型进行未来数据的预测。大家可以分段看一下,完整的代码在我的GitHub上面,可以直接下载:GitHub地址
数据获取:
这个在网上找了一个数据获取的实时接口(url地址),返回的是json数据
然后用python从这个url中读取实时数据即可。代码如下:
import urllib.request
import json
from pandas.io.json import json_normalize
def get_data(url):
resp = urllib.request.urlopen(url)
json_data = json.loads(resp.read())
with open("data.json", 'w', encoding='utf-8') as json_file:
json.dump(json_data, json_file, indent=4, ensure_ascii=False)
return json_data
if __name__ == '__main__':
test_json = get_data('https://www.tianqiapi.com/api?version=epidemic&appid=23035354&appsecret=8YvlPNrz')
history_json = test_json["data"]["history"]
data = json_normalize(history_json)
data.sort_index(ascending=False, inplace=True)
data.reset_index(drop=True, inplace=True)
print(data)
得到的数据如下所示:
画出来图看看数据的走势:
画图很简单没啥说的,参照下面的代码即可:
def plot_data(df_data):
plt.figure()
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.subplot(1, 2, 1)
plt.title("全国冠状病毒疫情趋势(一)", fontsize=20)
df_data["date"] = pd.to_datetime(df_data["date"])
df_data.set_index('date', inplace=True)
df_data['confirmedNum'].plot()
df_data['suspectedNum'].plot()
plt.legend(["确诊", "疑似"], loc="lower right", fontsize=18)
for a, b in zip(df_data.index, df_data['confirmedNum']):
plt.text(a, b, '%d' % b, ha='center', va='bottom', fontsize=12)
for a, b in zip(df_data.index, df_data['suspectedNum']):
plt.text(a, b, '%d' % b, ha='center', va='bottom', fontsize=12)
plt.ylabel("数量", fontsize=18) # 设置纵轴单位
plt.xlabel("时间", fontsize=18) # 设置横轴单位
plt.subplot(1, 2, 2)
plt.title("全国冠状病毒疫情趋势(二)", fontsize=20)
df_data['curesNum'].plot()
df_data['deathsNum'].plot()
plt.legend(["治愈", "死亡"], loc="lower right", fontsize=18)
for a, b in zip(df_data.index, df_data['curesNum']):
plt.text(a, b, '%d' % b, ha='center', va='bottom', fontsize=12)
for a, b in zip(df_data.index, df_data['deathsNum']):
plt.text(a, b, '%d' % b, ha='center', va='bottom', fontsize=12)
plt.ylabel("数量", fontsize=18) # 设置纵轴单位
plt.xlabel("时间", fontsize=18) # 设置横轴单位
plt.show()
建立模型进行未来数据的预测:
# 自定义函数 e指数形式
def func(x, a, b, c):
return a * np.sqrt(x) * (b * np.square(x) + c)
# 拟合数据
def fit_data(df_data):
# 定义x、y散点坐标
x = range(len(df_data))
x = np.array(x)
print('xxxxxx', x)
num = df_data["confirmedNum"].to_list()
y = np.array(num)
# 非线性最小二乘法拟合
popt, pcov = curve_fit(func, x, y)
# 获取popt里面是拟合系数
print(popt)
a = popt[0]
b = popt[1]
c = popt[2]
yvals = func(x, a, b, c) # 拟合y值
print('popt:', popt)
print('系数a:', a)
print('系数b:', b)
print('系数c:', c)
print('系数pcov:', pcov)
print('系数yvals:', yvals)
# 绘图
plt.plot(x, y, 's', label='原始数据')
plt.plot(x, yvals, 'r', label='拟合数据')
plt.xlabel('时间')
plt.ylabel('数量')
plt.legend(loc=4) # 指定legend的位置右下角
plt.title('非线形最小二乘法拟合')
x_next = len(df_data) + 1
y_next = func(x_next, a, b, c)
print("预计明天全国总确诊人数:%d" % y_next)
plt.show()
当然还可以用其他拟合方法,也可用RNN、LSTM等深度学习的方法或随机森林等机器学习方法,当使用这些方法的时候就要将其他三种数据(疑似人数、死亡人数、治愈人数)也加入到模型的特征数据中进行训练了。
本文只是用最简单的非线性最小二乘方法进行拟合的。
这里存在一个问题,就是历史数据中没有拐点信息,所以当出现拐点时通过拟合数据得到的预测结果有可能会不准确,
这个要有心里准备的哦。
2月2号24点确诊人数:17238人,2月3号24点模型预测确诊人数:21236,2月3号24点实际确诊人数:20471,2月4号晚24点模型预测确诊人数:29309,实际结果等今天晚上24点才知道(这个数据会偏高)