在时间序列预测领域,将序列分解为趋势和周期等成分是一种经典的分析方法。Facebook 开发的开源时序模型 Prophet 在此基础上进行了扩展,不仅涵盖了年度、周度和日度等多粒度的周期,还加入了对节假日和外生因子的考量,以增强对时间序列成分的表达能力。由于其简单易用、可解释性强以及良好的性能,Prophet 受到广泛欢迎。然而,该模型存在一些局限性,使其在处理复杂时间序列数据时难以进一步提升表现。为了解决这一问题,斯坦福大学的学生 Oskar Triebe 和他的团队开发了一个名为 Neural Prophet 的深度学习版本。Neural Prophet 能够弥补 Prophet 的一些不足,在保留高可解释性的同时,拓展了应用上限。
前世:Prophet
Prophet 方法基于传统的 STL(Seansonal and Trend decomposition using Losses)分解思路,基本想法是一组时间序列可以被拆解为趋势项、季节项和残差项这三个部分。其中,可预测的是趋势项和季节项,而残差项类似白噪声,是无法预测的。Prophet 则是在此基础上,叠加了曲线拟合的思想,Prophet 默认采用的加法模型为:
模型说明:
- 将观测值 看做是时间 (一般用整数表示)的函数,并将该函数分解成四个部分:
- : 趋势(trend),用线性函数或逻辑斯蒂(logistic)函数拟合
- : 季节性(seasonality),用傅里叶级数拟合。可以叠加多个周期性,如周性、年性
- : 回归量(regressor),用线性函数拟合。可以叠加多个外部变量,如节假日、温度、活动
- : 残差
以上方程也可以写成乘法形式: 。乘法模型更适用于时间序列的季节性振幅随时间序列总水平而变化的情况。例如,销量数据往往在高峰期(如节假日)有更大的波动,这种情况下乘法模型能更好地捕捉季节性模式。
-
拟合:将各历史时间点的数据作为样本,input 是时间和外部变量的取值,output 是观测值,拟合函数的参数。
-
预测:将未来的时间和外部变量的取值作为输入,用第 2 步中拟合好的模型计算出未来的观测值。
Prophet的优点
- 参数少,易上手
- 模型简单,可解释性强
- 灵活性强,易扩展
Prophet的缺陷
- 无法利用到未来不可知的协变量
- 没有考虑到残差的自回归
- 其参数基于MCMC推断无法规模化处理大数据
- 不支持非高斯分布的数据,相关讨论: github.com/facebook/pr…
- 没有考虑随机的趋势(stochastic trend)
- 不支持多时序
今生:Neural Prophet
结构
Neural Prophet 在 Prophet 的基础上新增了一个 AR(自回归)项,AR 只对历史可知,但未来不可知的数据进行计算。
所谓历史可知,未来不可知的数据,指的就是一些未来拿不到的数据特征。举例来说,假设我们要预测未来 7 天的气温,除了历史上的气温之外,我们还可以知道每天的风速,气温可能和风速有一定关系,所以把风速纳入模型来预测气温。这个风速数据就是过去可知,但未来不可知的特征。
说回到 Neural Prophet,和 Prophet 一样,它也是一个加性的模型,分成不同的成分,每一个成分都有相应的参数化计算方法,所有的成分加在一起即为最终的预测结果,结构如下面图所示(其中绿色部分为历史数据,红色部分为未来需要预测的部分):
其中:
- 为趋势,由一个线性回归来表达
- 为周期,由傅里叶级数表达
- 为假日/事件,由一个独热向量(one hot vector)与一个系数向量相乘得到
- 为未来可知的回归因子,是未来可以知道的信息,由一个线性回归来表达
- 为未来不可知的因子(包括预测目标 本身),由一个自回归网络来表达
这些成分分为加性和乘性,加性表示其影响量是通过加法作用在趋势(trend)上,乘性表示其影响量通过乘法作用在趋势(trend)上。我们通过源码中所谓的表达式也可以了解这些成分的组合方式:
# forward
out = trend + additive_components + trend.detach() * multiplicative_components
趋势
分段线性模型的数学表达,用于描述时间序列中的趋势成分 。这个模型通过线性分段函数来捕捉趋势的变化。
-
和 是线性趋势的初始斜率和截距。
-
是一个步骤函数向量,决定了在时间 时哪些分段函数生效。
-
和 是表示趋势变化的系数组,通过控制不同分段的斜率和截距。
-
的定义为:
其中, 表示第 个变化点的时间。
这意味着,对于每个时间段 ,如果当前时间 已经过了该时间点,则 ,否则为 0。这个表达允许模型的斜率和截距在经过特定时间点后发生变化,从而建模更复杂的趋势结构。它能够捕捉到分段线性变化,通过这些变化点来调整趋势的斜率和位置。
周期
季节性成分 。该表达式通过傅里叶级数展开来表示季节性变化。
- 是傅里叶级数的阶数,表示使用多少个谐波项来捕捉季节性。
- 和 分别是傅里叶级数中每个谐波项的系数。
- 表示时间。
- 表示季节性周期的长度。
- 和 函数分别捕捉季节性成分的余弦和正弦波动。
- 是包含所有傅里叶基函数的矩阵。
- 是包含所有系数( 和 )的向量。
以一年(365.25天)为周期的季节性:
这表示 包含从第一阶到第十阶的傅里叶基函数,每个函数都以周期 365.25 天(即一年)来进行正弦和余弦变换。
节日事件 Events / Holidays
未来可知回归因子 (Future-Known) Regressors
未来不可知协变量 (Lagged) Covariates
- 默认使用 AR-Net(0) ,目标变量为
- 深度可定制为 AR-Net(n)
- 可以通过稀疏化进行自动滞后处理
AR-Net(n) 用于非线性建模。
自回归 Auto-Regression
- 默认使用 AR-Net(0)
- 深度可定制为 AR-Net(n)
- 可以通过稀疏化进行自回归自动化
AR-Net(0) 是解释性强的模型。
问题
看到这里,大家可能会有一个疑问:看起来 Neural Prophet 和 Prophet 比起来就只多了一个 AR 项,那我们自己单独用一个 AR,或者其他任何模型,预测出那些未来不可知的特征的未来值,再把这些值加到 Prophet 里面,是不是也可以?
答案是做是可以这么做,事实上在 Neural Prophet 出现之前,我们确实也是用这样的方法来利用那些未来不可知的协变量(特征)。但 Neural Prophet 胜在它将这个 AR 和其他所有成分放到一个网络中去训练,通过反向传播统一更新参数,这样各个成分的参数就会互相影响,这样训练出来的各个分量在逻辑上更符合时序分解的思想,同时分解或预测效果一般也是更好的。
我们可以看到 Neural Prophet 是一个模块化的神经网络,这意味着你可以很方便地对它进行扩展。你可以对其中任意一种成分的表达式进行改变,也可以新增成分,只要表达式是可导的。