1、应用场景 绝大部分行业场景,尤其是互联网行业,每天都会产生大量的数据。游戏中每时每刻都会产生大量的玩家日志信息;旅游应用中每天有各类酒店各种交通工具的实时价格;涉及供应链和日销量的零售电商,每月都为生产(购进)多少货而发愁;就连生产电子元器件、供电箱等传统生产企业,这些零件每时每刻都会产生大量的数据。而我们称这种不同时间收到的,描述一个或多种特征随着时间发生变化的数据,为时间序列数据(Time Series Data)。 结合上文中的时间序列数据,我们能够做什么?最显而易见的是,我们可以通过过去产生的时间序列数据,来预测未来。我们可以通过游戏历史的玩家消费时间序列数据,预测该玩家在接下来一周的付费意愿和付费大致金额,从而定制化的推送相关游戏礼包和活动,这通常和传统的用户画像是互补的。 旅游应用中,利用历史数据对未来酒店、机票的价格进行预测,从而为用户推荐最低价的购买点(例如:提示用户五天后购买会更便宜),这一个小功能就足够获取大量忠实用户并实现变现,而北美已经有网站实现了这个功能来预测机票价格。有了每日销量的历史数据,我们可以预测接下来每天的销量范围,从而更有针对性的进货或者推出折扣促销政策,保证商品的供需平衡。 某大型供电箱生产销售企业常常头疼于电箱的维修难,维修贵,如果能利用传感器收集上来的历史数据训练出模型,在电箱故障前提前预警,那不论是维修还是提前更换,成本总比电箱彻底不工作后再去维修要少。 一言以蔽之,时间序列预测就是通过多种维度的数据本身内在与时间的关联特性,其中可能包含季节性、趋势性等等特征,利用历史的数据预测未来的场景,细分场景除了上述所介绍的之外,还有很多很多,由于篇幅关系,这里不做过多的展开介绍。 2、DeepAR简介 DeepAR 是一个自回归循环神经网络,使用递归神经网络 (RNN) 结合自回归 AR 来预测标量(一维)时间序列。在很多应用中,会有跨一组具有代表性单元的多个相似时间序列。DeepAR 会结合多个相似的时间序列,例如是不同方便面口味的销量数据,通过深度递归神经网络学习不同时间序列内部的关联特性,使用多元或多重的目标个数来提升整体的预测准确度。 DeepAR 最后产生一个可选时间跨度的多步预测结果,单时间节点的预测为概率预测,默认输出P10,P50和P90三个值。这里的P10指的是概率分布,即10%的可能性会小于P10这个值。通过给出概率预测,我们既可以综合三个值给出一个值预测,也可以使用P10 – P90的区间做出相应的决策。有关 DeepAR 数学运算背景的更多信息,请参阅DeepAR:概率性预测与自回归递归网络。 3、应用实例 3.1、先安装必要的python依赖(我用的清华源) pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ openpyxl,gluonts==0.9.6,mxnet,sqlalchemy,mxnet-mkl,pandas==1.5.3 3.2、完整实现代码 import matplotlib.pyplot as plt import json import pickle import baostock as bs import os from gluonts.mx.trainer import Trainer from gluonts.evaluation.backtest import make_evaluation_predictions from tqdm.autonotebook import tqdm from gluonts.dataset.common import ListDataset from gluonts.evaluation import Evaluator from gluonts.model.deepar import DeepAREstimator from pathlib import Path from gluonts.model.predictor import Predictor from params import predict_len from utils.data_dir import root_dir os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" def mygetstockdata(code): rs = bs.query_history_k_data_plus(code, "date,close,volume,turn", start_date='2023-01-01', frequency="d", adjustflag="2") # frequency="d"取日k线,adjustflag="3"默认不复权 return rs.get_data() if __name__ == '__main__': liststock = ["sz.300570", "sz.300399", "sz.002162", "sh.600621", "sh.603220", "sh.603161", "sz.002401", "sh.605577"] cache_listtrandic_path = f"{root_dir}/data/listtrandic.pkl" cache_listtestdic_path = f"{root_dir}/data/listtestdic.pkl" if os.path.exists(cache_listtrandic_path): with open(cache_listtrandic_path, 'rb') as f: listtrandic = pickle.load(f) with open(cache_listtestdic_path, 'rb') as f: listtestdic = pickle.load(f) else: listtrandic = [] listtestdic = [] lg = bs.login() for ite in liststock: dd = mygetstockdata(ite) trandic = {"start": dd.date[0], "target": list(dd.close), "cat": int(ite.split('.')[1]) } testdic = {"start": dd.date[0], "target": (dd.close)[:-predict_len], "cat": int(ite.split('.')[1]) } listtrandic.append(trandic) listtestdic.append(testdic) os.makedirs(f"{root_dir}/data", exist_ok=True) with open(cache_listtrandic_path, 'wb') as f: pickle.dump(listtrandic, f) with open(cache_listtestdic_path, 'wb') as f: pickle.dump(listtestdic, f) traindata = ListDataset(listtrandic, freq="1d") testdata = ListDataset(listtestdic, freq="1d") estimator = DeepAREstimator(prediction_length=predict_len, context_length=60, freq="1d", trainer=Trainer(epochs=20, learning_rate=1e-2, num_batches_per_epoch=300) ) model_path = Path(f"{root_dir}/data/output_model") if os.path.exists(model_path): predictor = Predictor.deserialize(model_path) # 导入训练好的模型 else: predictor = estimator.train(traindata) predictor.serialize(model_path) # 保存训练好的模型 forecast_it, ts_it = make_evaluation_predictions( dataset=testdata, predictor=predictor, num_samples=100 ) print("Obtaining time series conditioning values ...") tss = list(tqdm(ts_it, total=len(testdata))) print("Obtaining time series predictions ...") forecasts = list(tqdm(forecast_it, total=len(testdata))) def plot_prob_forecasts(ts_entry, forecast_entry, code, save_image=True): plot_length = 200 prob_intervals = (50.0, 95.0) legend = ["True values", "median prediction"] + [f"{k}% prob interval" for k in prob_intervals][::-1] ax = plt.gca() ts_entry[-plot_length:].plot(ax=ax) forecast_entry.plot(prediction_intervals=prob_intervals, color='g') ax.axvline(ts_entry.index[-predict_len], color='r', linestyle="dashed") plt.legend(legend) if save_image: plt.savefig(f"{root_dir}/data/output/forecast_{code}.png") plt.close() else: plt.show() for i in range(len(tss)): plot_prob_forecasts(tss[i], forecasts[i], liststock[i]) # 输出预测结果 testdata_predict = predictor.predict(testdata) prediction = next(testdata_predict) print(prediction.mean) prediction.plot(output_file=f'{root_dir}/data/output/graph.png') # 评价指标 evaluator = Evaluator(quantiles=[0.5, 0.90]) agg_metrics, item_metrics = evaluator(iter(tss), iter(forecasts), num_series=8) print(json.dumps(agg_metrics, indent=4)) # 未来预测 # insert_into_daily_predict(day, code, name, price)
最新代码放到gitee上了,感兴趣的可以直接用,stock_predict: 股票预测、推荐、量化等
参考资料:
教程 | 如何使用 DeepAR 进行时间序列预测?
Deepar - 知乎
【时序】DeepAR 概率预测模型论文笔记