Hello大家好,今天老DC给大家介绍一个咱们DC的忠实用户,也是数据科学竞赛大佬——嘴爷。嘴爷多次参加我们DC平台的数据科学竞赛,都取得了非常理想的成绩。
所以呢,嘴爷专门写了一篇“时间序列预测”的相关内容分享给大家。下面就是嘴爷的想给大家分享的全文。
这次是笔者第一次相对系统的介绍一个领域的知识,请多多拍砖。因为篇幅有限,本文主要从概念和思路上进行介绍,所以题目为理论篇,如果后面有机会,考虑会再出一个实践篇。文本内容干货十足,如果你是一名还没入门或者刚入门的新手,耐心读完本文相信你一定会有收获。
时间序列预测(Time Series Prediction),就是给出某个量历史一段时间中的变化情况,以预测未来一段时间内(或未来一个时刻)的变化情况。按照给出的历史数据变量可以进行进一步划分:一种只提供需要预测量自己的历史数据,也可称为自回归预测;另一种则同时给出其他变量,例如要预测未来几天温度,在给出历史几天温度的同时还给出历史几天的湿度变化,湿度数据也可称为协变量。
时间序列问题并不局限于预测未来,时间序列分类(给出一段时间信号,输出其归属类别)、时序异常检测(是否出现故障)等都是常见研究方向。本系列仅对时序预测这一小分支进行分享,但一些分析思路是可以通用的。
首先要介绍简单一下时间序列分解(Time Series Decomposition),一般有两种分解方式,加法模型和乘法模型:
-
加法模型,y(t) = S(t) + T(t) + R(t)
-
乘法模型,y(t) = S(t) * T(t) * R(t)
其中S为周期项,T为趋势项,R为残差项。说人话,一个时间序列可以(以加法或者乘法的方式)分解为三部分:其本身的周期性变化,长期的趋势以及其他外界因素造成的扰动。当然,可能有些时序问题没有明显的周期性;也可能有些时序问题没有明显的趋势,即平时口头上说的“平稳”。需要特别注意的是数学意义上的平稳有着严格的定义,可以通过Adfuller检验等方法进行判断,如果想更清晰地弄懂这个概念,有必要查阅更多资料,这里不做展开。
图1:利用prophet进行时序分解:趋势项及周期项
在本节提到时序分解这个概念,是为了强化大家对时间序列的认识,在进行时序分析时,一定要把这三部分记住:
-
如何去表征序列的周期性,例如取历史值,这部分将在构造时序特征部分做更多展开
-
-
以及如何去表征外界因素,一般通过对其他外界特征量进行分析
这里建模方法的含义为,给定训练集输入输出,给出一种输入输出的映射方式,使得在给出新输入时能对应地给出输出。对于时序预测,通常需要输出未来多个时间点的预测值,即是个多输出问题。对应的,可以将建模方式以同时输出的预测值个数分为单输出建模和多输出建模。其中细分的每一种都有其对应的训练和预测方法,也需要和固定的模型类型相结合。
单输出建模还可以有两种方式,一种是多模型建模,一种是单模型建模。
对于多模型建模,针对每一个需要预测的y,都建立一个预测模型,这样y1~y4就需要构造4个模型。
而对于单模型建模,通过滑窗的方式来构造不同样本以预测不同的y。
另外提一句,多模型建模可以迭代往后预测转换为单模型建模,但是一般不推荐迭代预测。
一次性输出y1~y4,这种建模方式模型看起来简洁不少,但性能需要实际测试才知道。
这里特别提一下人工规则,老一辈的数据挖掘高手能够在人工规则上玩出花来,但是感觉现在这种方法在逐渐没落了。
最简单的规则,直接取历史同期的均值或中位数。稍微复杂点的周期因子法,在直接历史同期值上引入一个周期的均值(中位数),在更鲁棒的基础上进行预测。再复杂一些,进行手工时序分解,即利用前文时序分解思路将序列拆分,分别预测之后再重组成为最后的结果。周期因子法和时序分解法可以网上介绍的也很多,有兴趣可以查一查。同时后文介绍的fbprophet也是基于时间序列分解。
-
人工规则通常作为最初的尝试,代码写起来简单,不需要复杂处理(当然你也可以构造非常复杂的规则);
-
多模型建模和多输出建模在预测时,对于所有的标签都可以使用最近的历史数据;而单模型建模(由于需要滑窗)在预测时,对于靠前的标签,无法使用最近的历史数据;
-
单模型的模型训练数据是多模型建模每个模型(或多输出建模)的n倍,n等于标签的个数;
-
多模型建模的多个标签预测质量可能差距较大,较近的预测质量好,较远的差,相比而言单模型会相对均匀;
-
多输出模型训练相对困难,虽然可以利用label之间关系,但也可能因此互相干扰;
-
对于需要预测长期的时间序列,多模型建模需要建立非常多模型,完全不实际。(不过实际长期预测本来就不太靠谱,都是瞎搞。)
在前述建模方式的基础上,下面介绍几种常用模型。其中传统时序模型常为多输出模型,树模型和线性回归为单输出模型,神经网络模型则几种建模方式都可以。
传统时序模型主要考虑Arima及FaceBook Prophet,这两个应该算是专职时序预测模型,下面分别简单介绍。
Arima(Autoregressive Integrated Moving Average model),其中ar为自回归,ma为移动平均,此外还有个差分(笔者也不清楚Integrated是否跟差分有关),这就是模型中的三个超参数(自回归p,差分d,移动平均q)。
自回归p代表采用多少历史数据进行拟合,移动平均q代表采用多少时间的历史外界扰动,差分d则是在序列不平稳时使用,要求进行d阶差分后序列变得平稳。
在实际使用时可以考虑手动定阶,autoarima自动定阶或者暴力搜索也可以。此外,Arima还有一些加强版,比如加上季节性的SARIMA以及再加上外部变量的SARIMAX。
Fbprophet为Facebook开发的基于时序分解的预测模型,由于前文已经对时序分解进行了介绍,再此不再赘述。在时序分解的基础上,fbprophet还引入了节假日效应,手动拐点等,可调参数相对多,拟合性远强于arima。
在实际小数据集时序预测竞赛中,也常常能看见fbprophet的身影。
树模型是一类模型,从简单的决策树到随机森林,再到现在的GBDT及其改进版本LigthGBM、Xgboost及Catboost,其中机器学习面试题都可以出一大堆,这里不多说,实际时序预测常用的是lgb及xgb。两个典型的万金油模型,回归与分类任务只有你想不到,没有他用不了,而且效果还不错,相比而言catboost使用相对较少。笔者个人偏向lgb,毕竟效果跟xgb各有好坏,但是速度确实快很多。
lgb等模型仅能进行单目标预测进行时序预测,所以对于多时刻预测,需要根据前述单输出的建模方式构造输入输出样本。要想使用lgb获得较好的预测效果,一个非常关键的点是特征构造。
除了结构化数据常用的一系列特征构造,时序预测有其特有的特征构造思路。参考前述时间序列的基本特性,需要构造特征来表征这些时序特性,这里介绍一些最常用的:
-
当前时刻值特征,比如年,月,日,小时,季度,星期,是否为节假日等,时刻值本身隐含有一些特性,比如交通流量有早高峰晚高峰,水力发电量有汛期季节性;
-
滞后特征,即历史时刻值如上一个时刻,上两个时刻,一小时前,一天前等;
-
根据滞后特征,同时可构造当前值与历史值的比值差值,不同周期的同期值比为同比,同周期的不同期值比为环比;
-
滑窗特征,体现一段连续时间内变化特性,对于单个时间窗,可做窗内统计(均值,中位数,标准差,分位数,偏度,丰度等),及窗内值与统计值交叉(如某时刻值除以一段时间内均值);
-
对于多个时间窗,可分别对各个窗进行统计并交叉,从而对整个时间段的变化进行刻画 ,等长窗如1/2/3/4号,2/3/4/5号。不等长窗如1/2/3号,1/2/3/4号,1/2/3/4/5号。
当然除了时序特征之外,还有些结构化数据通用的特征,如根据类别交叉,类别对连续值聚合统计,类别特征编码等,不在文本讨论范围内。
需要特别注意的是,树模型的外推能力十分有限,这意味着预测得到的结果基本不会超出训练集目标值范围内,也就是说,对于有显著趋势性的时间序列,树模型无法直接预测出后续持续的趋势性。那么需要先去趋势,使目标变平稳,常用有两种方法,其实都可以归结为目标变换:
-
差分,将目标值与一个固定值做差,可以是一个周期前的同期值,也可以是前一个周期内的均值、中位数等,需要根据不同问题进行尝试;
-
首先用线性回归拟合趋势,然后将目标值减去线性拟合得到的目标作为新的目标值,类似于残差预测。
线性回归LinearRregression可以说是平时常用的最简单的机器学习模型(感觉没有之一),其也有一些变种,比如采用不同正则方式的岭回归与lasso回归,这里又可以出一波面试题。
从实际操作角度来讲,Lr跟树模型十分相似,都非常需要构造特征来增强模型的表达能力,同时都为单目标输出模型。但有两者一个本质差别,Lr可以很方便的拟合趋势,外推能力强。
另外,使用Lr时,类别特征最好做onehot,或者如果onehot维度太高可以考虑各种方式embedding(嵌入)。
这年头什么东西都能跟神经网络融合一下,什么DeepAR,NeuralProphet的,个人不怎么感兴趣,所以也没有去尝试,从比赛来讲目前是没怎么见过,估计实际也不咋滴。
除去各种花里胡哨的网络,目前最常见的大概是基于LSTM的魔改网络和基于Transformer的魔改网络。说到这不能不为LSTM表示下遗憾,本来在序列预测里混得好好的,结果横空出世一个Transformer,先是在NLP被Bert锤了,完了又在时序预测上被锤。
不过实际上LSTM并没有输得那么惨,论文里的sota实际用起来并没有那么顺手。Transformer的大参数量在提高拟合能力的同时,无疑也是增加了训练难度和对训练数据量的需求。
另外,用神经网络的极致大概是完全不需要手动特征,但是实际应用时,如果有手工构造的强特,加入网络的输入有助于网络学习。更多要做的则是模型结构设计,超参数调整,学习策略调整,loss改进等。炼丹术很需要经验。
可以尝试但不要沉迷于新模型,毕竟很多论文都有灌水成分,真正好使的是少数。笔者最喜欢的还是lgb。
客观的讲,不同模型各有其适用场景。两个传统时序模型常用于数据量较小的自回归,无额外变量,在小数据比赛中作为融模附模型。神经网络则适用于数据量交大,且数据质量相对较好的场景,毕竟网络权值数量多,大规模数据缺失也是神经网络难以处理的。万金油树模型,哪里都能用且效果都不差(当然是建立在构造特征的能力还不错的基础上),可以自动处理缺失值(实际场景非常常见特别是工业数据)且较为鲁棒。硬要说的话,可能缺点是在很大规模数据集上效果树会弱于神经网络。树模型和神经网络模型,一个需要特征一个需要调参,时序原理上的东西则类似。线性回归可以看作一个简化版神经网络,作为使用树模型之前的基线模型,或者是用于明显有趋势的数据。
以上对比是对模型在时间序列应用场景进行的比较,且仅从算法效果而言,关于模型的落地部署,因为笔者不懂就不多说。
虽然本篇的定义是理论篇,但是在实际操作中还有一些需要注意的,放在这里作为补充,想到多少说多少:
-
在对数据集进行训练集和验证集划分时,标准做法为Sklearn的TimeSeriesSplit以避免产生信息泄露(通俗的说法就是避免在训练模型时预测过去值时使用到了未来的信息),但实际操作中很多时候(数据量较小)都使用随机多折交叉验证,效果会更好。
-
做特征时一定要避免各种形式的泄露,不要用到未来信息。
-
在比赛中,目标变换不仅可以减弱序列的不平稳,不同的目标变换方法还可作为多个模型进行融模。
-
多尝试多尝试多尝试,重要的事情说三次,不同建模方式不同模型都试试,一切以实验结果为准。