prophet模型描述
y(t)=g(t)+s(s)+h(t)+ϵt
g(t)表示增长函数,用来拟合非周期性变化的。
s(t)用来表示周期性变化,比如说每周,每年,季节等。
h(t)表示假期,节日等特殊原因等造成的变化。
ϵt为噪声项,用他来表示随机无法预测的波动,我们假设ϵt是高斯的。
数据采取的是美国2020-1-21到2021-11-8的累计确诊人数和累计死亡人数,首先我们先展示一下数据的格式和具体情况
数据是csv格式存储的,列名为date、cases、deaths
上图是累计确诊人数和死亡人数的可视化
数据处理
因为Prophet模型对数据异常值的忍耐度比较高,所以我们这里只进行简单的检查是否有无空值(其实我也做过中值滤波和平滑处理,但是结果不太理想,还不如不处理)。
path="D:\\疫情预测\\USA.csv"
data=pd.read_csv(path,parse_dates=["date"])
data.isnull().values.any()
结果是False,也就是没有空值,那我们接下进行建模
建立模型
#分割数据集
def train_test_data_split(data,start,end):#658条
train_data = data[start:end]
test_data = data[end:]
return train_data,test_data
#初步建立模型
def model(trainData):
pm=Prophet(changepoint_prior_scale=0.95,interval_width=1)
# changepoint_prior_scale:增长趋势模型的灵活度,值越大,历史数据的拟合程度越强
#interval_width:衡量未来时间内趋势改变的程度。值越大,趋势间隔出现的频率和幅度与历史数据越相似,
pm.fit(trainData)
return pm
#预测
def predict(pm,periods):
future = pm.make_future_dataframe(periods)
pm_forecast = pm.predict(future)
return pm_forecast
#模型评估,采用与测试集的MAPE进行评估
def MAPE(data_true, data_pre):#平均百分比误差率评估
data_true, data_pre = np.array(data_true), np.array(data_pre)
return np.mean(np.abs((data_true - data_pre) / data_true)) * 100
#主函数
def work(start,end,data,title):
train_data,test_data = train_test_data_split(data,start,end)
pm = model(train_data)
predictions_data = predict(pm,40)
results_data = predictions_data[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].merge(test_data[["ds","y"]])
print(results_data)
fig1 = pm.plot(predictions_data)
fig1.suptitle(title,verticalalignment='center')
fig2 = pm.plot_components(predictions_data)
fig2.suptitle(title,verticalalignment='center')
print(title+' MAPE: '+str(MAPE(results_data['yhat'].iloc[0], results_data['y'].iloc[0])))
return results_data,predictions_data[['ds', 'yhat', 'yhat_lower', 'yhat_upper']]
#选择函数
def select(data,title):
data_new=data.rename(columns={"date":"ds",title:"y"})
return data_new,title
这里我们采用前3个月的数据进行训练,然后预测后一个月的数据,采用MAPE对模型进行评估。
预测
确诊人数
#对10月10日~11月8日的确诊人数进行预测
title="cases"
data_new,title=select(data,title)
rec1,rec2=work(-90,-30,data_new,title)
MAPE为0.026,感觉还不粗,再看看死亡人数的预测
#对10月10日~11月8日死亡人数进行预测
title="deaths"
data_new,title=select(data,title)
red1,red2=work(-90,-30,data_new,title)
MAPE为0.014,感觉也不错,接下来我们将预测值和真实值进行可视化。
上图为确诊人数
上图为死亡人数
结论:
前七天的预测值非常接近,但是随着时间的增大,误差变大,虽然是时间序列预测的通病但是此模型明显是预测值偏大,后续或许再次进行调参,可以得到更好的结果。
——墨涯