作者简介
Yiwen,携程数据分析师,专注用户增长、因果推断、数据科学等领域。
团队热招岗位:、、
一、背景
二、现有方法及潜在问题
三、模型介绍
3.1 多元序列生成过程
3.2 结构分解
3.3 结构预测
3.4 结构融合
3.5 损失函数&残差项处理
四、模型应用与代码实现
4.1 代码实现
4.2 最佳模型选取
4.3 模型参数
4.4 模型对比
五、业务场景实践
5.1 数据选取&模型训练
5.2 代码实现&结果解读
5.3 落地应用&未来改进
六、方法拓展
七、总结
多元时间序列(MTS)预测一直是业务中的一个重要问题,科学地预测下单量或用户数能够协助财务制定预算、协助客服安排人员、帮助业务方更好地评估某个活动上线的效果。在预定类业务,例如电商平台、OTA行业等,一段时间内的下单人数或是订单量背后其实蕴藏着一定的时间规律或者某种特定的时空结构,也就是其本身近似于一个有着较复杂结构的时间序列。如何对未来一定时间内的下单用户或是业务量进行预测,其核心问题就是如何有效地对这类复杂的时空结构建模,最大程度地模拟出数据背后的结构特征,进而得到对于未来有效的预测。
本文主要将介绍SCNN模型及其代码的具体实现,以及如何将其应用在预测业务量上的实际操作过程,旨在面对一些拥有复杂时空结构的多元变量数据时能更准确地进行预测。下文将首先对模型原理进行简要阐释,随后展示代码逻辑,最后介绍在具体业务场景上的实践应用。
二、现有方法及潜在问题
目前针对时序数据的预测一般是通过同比或者环比的方式加上业务方自己对业务增长的理解进行,或是使用ARIMA等较简单的时序模型进行预测,并没有使用非常贴合数据结构规律的模型。因此较难对一些复杂的时序数据有较精准科学的刻画。
之前介绍过的BSTS结构模型也是一种针对结构化时序数据的模型,能够拆解出数据背后的结构因子。但是因为融入了贝叶斯的思想,考虑的都是参数的分布形式,最终给出的预测结果也都是包含置信区间的“区间估计”,不能满足业务方想要一个“具体预测值”的需求。且BSTS模型普遍情况下适合单维变量的预测情况,不能很好地捕捉到不同变量之间的相关性。而实际上,大多数的变量都会受到外界各种其他变量的影响,因此使用多元时序的预测模型是一个更好地选择。
同时,为了满足业务方想要一个更具体的预测结果,我们需要一类“点估计”的预测模型。结合上述两点要求,SCNN模型是一个不错的选择。下文中我们将详细介绍这一模型的思想原理以及其具体使用的场景和方法。
三、模型介绍
结构化时间序列数据在日常生活中并不少见,尤其像携程这样的OTA行业,平台的下单情况其实就具有一定时间规律,例如周末往往是一周内的下单高峰期;节假日是一年内的下单高峰期等等。
SCNN模型(Structured Components-based Neural Network)全称为“基于结构化组件的神经网络模型”,正如其名,它的主要特点体现在:(1)将数据分解为多个结构;(2)适用于多元序列数据;(3)应用了神经网络的建模思想。
在时间序列预测中,基于分解的建模思路也并不少见,常见地,将序列分为周期项;季节项等等。SCNN模型也类似这样的思路:将时序数据分为4个模块:长周期项(long-term);短周期项(short-term);季节性项(seasonal-component)以及序列间相关性项(co-evolving component),随后对各个结构模块进行解耦再分别建模,分别预测;最终将结果通过卷积方式融合在一起,进而输出对未来数据的预测。多元时间序列可以表示为一簇{Yn,t}n∈N,t∈T,其中{Yn,t}表示在t时间的第n个变量的数值。那基于现有数据,对未来序列的预测即可表示为如下概率公式:
简答来说,SCNN模型的主要思想就是将一个多元时序数据分解成4个模块,每个模块可以从不同的角度提供数据信息,以此让模型能够更好地“学习”到原序列内在的结构规律,并更好地作出对未来的预测。
图3-1展示了某一个时序数据通过SCNN拆解后得到的4个模块,最上方的蓝线表示原有的数据,下方的四种曲线分别表示一种结构。可以看出一个表面有着某种规律的数据背后其实可以细分拆解出多个不同的结构模块。
3.1 多元序列生成过程
基于上述的分解思想,原始的序列数据被有序地拆分为了4个模块,分别是长周期项、季节项、短周期项以及序列间相关性项。具体过程可以表示为以下的公式:
其中,表示原始的序列数据;表示经过一层层分解之后的数据。相应的表示针对于long-term;short-term;seasonal-term;co-evolving-term状态下的均值和标准差;最后的Rn,t 表示原数据经过4层分解后的剩余项。
更具象地,可以用“交通密度数据“来模拟这一过程,不同的模块可以反映出影响交通数据的不同方面:长周期项能够体现一个城市的交通总体趋势,例如人口的增长导致的拥堵或整个城市经济发展导致的交通变化,是一个较长时间范围内的影响;季节性项体现在某固定周期内的交通变化,例如每天上下班的高峰时段会带来交通的拥堵或是周末带来的拥堵;短周期项则能够捕捉由一些突发事件导致的短暂瞬时变化,例如突发的交通事故或是突然的恶劣天气等导致短时间内的交通变化;序列间相关性项则反应不同交通道路之间的相互影响程度,例如突然的交通事故可能会加大邻近道路的拥堵情况;最终的剩余项(残差项)则会保留一些随机效应或是系统误差等等。
需要注意的是,不同项之间会存在互相流动的情况,例如突发的交通事故如果一直持续,可能会发展成“短周期项”,如果持续的时间更长,则可能会转移成长周期项,这种流动性就要求模型能够更加灵活,从而准确地把握每一个结构的流动情况。
3.2 结构分解
本节将介绍如何对4个模块进行分解建模以及预测:
1)长周期项:如前文所示,长周期反映的是序列数据在较长时间范围内的变化。因此选择构建一个较大的滑动窗口,取每个窗口内的均值与标准差作为长周期项的两个参数。
其中表示长周期项的均值与标准差;表示将原数据进行长周期化后的数据(提取出长周期项)。
2)季节性项:与长周期项的滑动窗口类似,在基于 “序列的周期长度是一致的”假设前提下,对季节性项也采取一个窗口统计的方法。
其中表示季节性项的均值与标准差;表示将再进行季节性化后的数据(提取出季节性项)。
3)短周期项:和长周期项相同,这里取一个较短的滑动窗口来进行计算;较短的窗口能够防止一些短期内的信息平滑掉,从而能够体现出数据在短时间内的变化,提供更全面的信息。
其中表示短周期项的均值与标准差;表示将进行短周期化后的数据(提取短周期项)。
4)序列间相关性项:相较于单元序列,多元序列需要考虑到不同变量之间的相关性,如上述的交通案例中某一道路的突发情况会对邻近道路造成影响,这一过程就体现了序列间相关性。作者认为不同序列间会共享某一个相关性值(例如道路A邻近的两条道路B和C,如果都发生了交通事故,他们对于道路A的影响程度可能是同一个相关性结构),因此我们需要识别出哪些序列间会共享同一个相关性结构,换句话说我们需要知道每一对序列之间的相关性结构。
我们可以采取通过一些先验知识计算两两序列之间的相关性权重矩阵;也可以通过让模型自己学习,SCNN模型选择了后者,采用注意力计算的方法,给每一对序列之间设置一个注意力分数并通过softmax方式进行标准化以确保注意力分数总和为1;最终每一对序列之间的分数可以表示如下:
其中分别表示第n个变量与第个变量在标准化后和标准化前的注意力分数;表示将注意力分数分配到每两个变量后的的均值与标准差;Rn,t 表示被抽取序列间相关性之后。最终无法被分解的剩余项。
下图展示了一个多元时间序列经过4道分解的过程:先抽取长周期项;再抽取季节性项;再抽取短周期项最后抽取序列间的相关性项。在进行4道分解之后会得到4个模块各自的模型,随后会分别进行预测,最终将4个模块预测的结果经过一维卷积融合得到最终输出的预测序列。
图3-2展示SCNN模型对于4个模块分解的过程。过程中会分别计算出每个模块的均值与标准差值作为模型参数,将4个模块分别抽取之后分别进行建模、预测;最后将各模块的预测结果进行融合得到最终的序列预测结果。
3.3 结构预测
上述内容介绍了如何将序列的4个模块分别抽取并建模的过程,下面将介绍如何对这4个模块分别进行预测。
长周期和季节性项因为统一采用了滑动窗口的形式并且其周期较长、较平滑,如果预测较近的未来,这两项的趋势不会有太大的波动,因此可以直接用参数估计的方式进行预测,即直接用当前窗口的均值作为下一个窗口的估计,公示如下:
短周期项、相关性项以及残差项因为会在短时间内有较大的变动因此无法使用长周期的方法进行推测。作者认为可以对这三种模块各自建立一个自回归的模型,能够基于过去的信息来预测未来的情况。为了简便作者统一用下面的表达式来表示这三项结构的自回归模型:
其中是模型中的权重矩阵,bi表示预测偏差。,表示囊括了短周期、序列间相关性以及残差项这三个结构,其中我们主要需要训练以及bi。
图3-3表示对于不同模块的预测方法。长周期直接使用上一个窗口的均值当做下一个窗口的预测值;季节性与长周期方法类似,使用上一个季节的均值当做下一个季节窗口的预测。短周期与序列间相关性项是利用自回归模型进行推测。
3.4 结构融合
通过上述方式可以分别得到四种模块在要求范围内的预测结果,之后作者提出用神经网络的方式对预测的结果进行融合。具体来说,引入一个神经模块,分为两个分支:一个专门用于特征学习(通过神经网络自动学习输入数据中的特征结构),另一个用于参数学习(通过训练过程调整网络中的权重和偏差等参数,提升网络的拟合程度),最后这两个分支的输出将通过卷积方式整合成最终的预测结果。
3.5 损失函数&残差项处理
传统对于预测模型的评估指标即为MAE或者MSE,通过预测值与真实值之间的差距来评估模型预测的好坏,但是这样的评估方法有一个内在的假设:所有变量的方差量纲相同。但由于时序数据在不同时间点下的波动程度并不相同,如果基于这样的假设进行预测,那最终融合后的数据可能并不是最佳的预测结果。于是作者考虑将MLE纳入损失函数定义中,将损失函数重新定义为:
其中第一项用来控制预测结果的波动不要太大;第二项则同时控制预测结果与真实结果的差距与预测结果的波动性均不要太大。
但作者认为仅仅依靠改变上述目标函数仍存在一定风险,他认为经过4层拆解之后的剩余项Rn,t中仍可能包含没有分解干净的结构特征,最后导致模型给残差部分分配一个较高的权重,而这些权重本应被分配到相应的结构项上。如果残差项拥有了不恰当的高权重,那一旦时序数据后续受到高频的随机噪声的干扰,那模型的有效性就会大幅下降。
为了解决这个问题,作者额外再引入了一个正则化项来控制残差项中的结构权重,以此促使模型更多地聚焦在分解出的4个结构项上,同时保证模型如果在仅使用4个分解项结构而没有残差项的情况下也能做出相对合理的预测结果。具体来说,在训练模型的过程中,SCNN在分解模块之后,会有两个分支。一个分支保留了残差项,和4个模块一起用来训练模型;另一个分支则将残差项全部置零,只传递结构成分来进行后续模型训练。最后分别用这两种方法得到预测结果并进行加权求和,构建最终的目标函数:
其中就是通过置零残差项得到的模型预测结果;是保留残差项的模型预测结果。最终我们会使用这个目标函数来训练模型。
图3-4展示了目标函数不同的构建方式。第一张图表示传统的MSE损失函数;第二张图是考虑了时序结构特点的损失函数纳入了MLE;第三张图表示在第二张图的目标函数构建的基础上,参照公式(21)将残差项置零后得到的预测结果与普通预测结果加权后得到最终的目标函数。
四、模型应用与代码实现
以上我们介绍了SCNN模型的基本思想以及理论步骤,下面我们将介绍作者在git上开源的代码逻辑,以及我们如何在实际业务过程中使用该模型对业务量进行预测。具体代码实现可以参考文献[2]。
图4-1展示了训练模型的具体执行过程,从输入数据训练、选取最佳模型、使用模型进行预测到最后对模型进行定期更新迭代。
4.1 代码实现
下面通过部分代码来展示实现过程,这里主要介绍4个模块的抽取与预测部分:
# 进行季节性归一化处理,input:数据集+周期长度;output:季节性结构的均值与方差以及标准化后结果
def SeasonalNorm(x, period_length):
mean = F.pad(mean.reshape(b * c, n, -1), mode='circular', pad=(t % period_length, 0)).reshape(b, c, n, -1)
var = F.pad(var.reshape(b * c, n, -1), mode='circular', pad=(t % period_length, 0)).reshape(b, c, n, -1)
out = (x - mean) / (var + epsilon) ** 0.5
return out, mean, var ** 0.5
# 序列间相关性项
class AdaSpatialNorm(nn.Module):
def forward(self, x):
mean_f = torch.matmul(adj_mat, x_f)
var_f = torch.matmul(adj_mat, x_f ** 2) - mean_f ** 2 + 0.00001
mean = mean_f.view(b, t, n, c).permute(0, 3, 2, 1)
var = var_f.view(b, t, n, c).permute(0, 3, 2, 1)
out = (x - mean) / (var + epsilon) ** 0.5
return out, mean, var ** 0.5
# 进行长短周期的归一化处理,input:数据集与滑动窗口的长度;output:经过长/短周期归一化后的值以及各自结构的均值方差
def TermNorm(x, term_length):
mean = F.pad(mean.reshape(b * c, n, -1), mode='replicate', pad=(term_length-1, 0)).reshape(b, c, n, -1)
var = F.pad(var.reshape(b * c, n, -1), mode='replicate', pad=(term_length-1, 0)).reshape(b, c, n, -1)
out = (x - mean) / (var + epsilon) ** 0.5
return out, mean, var ** 0.5
#对四个模块进行卷积融合,input:原数据集,output:预测后的数值
class SCNN(nn.Module):
def forward(self, input):
pred_distr_args = self.proj_distr_args(out) # 不mask残差项得到的预测结果
pred_distr_args = (pred_distr_args[0], pred_distr_args[1], F.threshold(pred_distr_args[2], 0.2, 0.2))
pred_distr = self.distr_output.distribution(pred_distr_args)
pred_distr_args_aux = self.proj_distr_args(out_aux) # mask残差项后得到的预测结果
pred_distr_args_aux = (pred_distr_args_aux[0], pred_distr_args_aux[1], F.threshold(pred_distr_args_aux[2], 0.2, 0.2))
pred_distr_aux = self.distr_output.distribution(pred_distr_args_aux)
pred_mean = pred_distr_args[1].reshape(b, n, self.num_pred, 1).permute(0, 2, 1, 3)
if self.training:
return pred_distr, pred_distr_aux
else:
return pred_mean
4.2 最佳模型选取
通过构建训练集、验证集与测试集(*不是无序打乱,会满足时间连贯性,例如训练集是1~80天的数据,验证集是81~120天的数据,测试集是121~150天的数据*),以RMSE与MAE等指标为标准选取效果最好的模型并保存。
4.3 模型参数
模型包含大量参数,可以归纳为4个部分(如下图所示),不同版块的参数将通过不同方式获取。
图4-2展示了不同类型的模型参数,可以分为与SCNN结构相关的参数值;与神经网络相关的模型参数值;模型训练的指标值以及训练预测时的步长设置等。
数据集自身结构参数:长/短周期及季节项等参数可以直接通过对历史数据的分析得到。
神经网络相关参数:可以通过提前设置或是对比不同参数下的模型效果来得到最优的那个。原文中作者尝试了多个参数包括网络层数;hidden channel;kernal size等等来对比不同组合下模型的效果(如图4-3所示)。这种通过不同参数组合对比模型结果的方式能直观反映出参数的优劣但也会消耗较大的资源,实际应用中可以视资源条件而定。
图4-3展示了在不同的网络超参设置下模型表现的结果对比,可以看出并不是网络层数越多或核数越多就一定会得到更好的训练效果。
模型训练相关参数:这部分参数主要涉及训练模型时对训练集、验证集、测试集的划分,更推荐各个子集的长度是周期项的倍数,例如如果以每小时作为步长,周期项为一天,则周期值为24,那训练集、验证集与测试集最好都能够是24的倍数,这样模型训练的时候能够更好的学到周期项的影响。当然具体情况视数据集本身结构而定。其余的迭代次数与模型指标也视具体情况和资源条件而定。
训练&预测步长参数:事先需要定好使用多长时间内的数据对未来多久范围内的数据进行预测。SCNN模型更擅长对于短时间内的未来进行预测,能够很好地捕捉到短时间内的数据波动情况。
4.4 模型对比
作者使用了BikeNYC、PeMSD7及Electricity三个数据集进行测试,将SCNN的预测效果与其他一些时序预测模型进行对比。从结果看,SCNN模型在对未来短时间的预测上,效果优于其他模型。此处展示了在BikeNYC数据集上部分模型与SCNN模型的预测效果,作者进行了3次横向实验,此处取3次指标值的平均值进行展示:
五、业务场景实践
我们希望对业务量进行合理地预测,来协助财务、产品等多方调整评估自身业务。通过对历史数据的分析发现,每日业务量的数值可以看作一个时间序列,它会受到一个地区长期人口增长或是旅游业发展带来的长期影响;每个周末的出行小高峰会体现出季节性的特点;每天上下班的小高峰类似是一个短周期项;且业务量与当下的站内活跃人数、下单人数等等其他变量之间会存在相关性,符合SCNN模型的适用数据对象。
于是我们尝试使用SCNN模型来进行结构拆解及预测,以此给出更科学的预测结果。另一方面,我们发现平峰时期的业务量结构与节假日高峰时期的业务量结构并不完全相同,因此我们选择分开训练适用平峰期业务与高峰期业务的模型。
5.1 数据选取&模型训练
数据预备:从数据图像上我们可以看出,在一天之内业务量呈现某种固定的波动趋势,因此我们取1小时为1步长,以一天(24H)为季节性周期。同时也可以发现每周的业务量也呈现相似的波动规律,例如周中是一周中的“淡季”,周四~周日是一周中的“旺季”,于是我们取一周(168H)为一个长周期。综上,确定了模型中所有的结构参数。
图5-1展示了每小时业务量的波动趋势,体现出一定的周期性和规律性。
数据选取:考虑到疫情对出行业务的影响,我们选取了2019年与2023年全年的所有数据进行模型训练,变量包括业务量、下单人数、访问人数等多列变量;
模型训练:将上述数据代入SCNN模型中,选取若干不同的hidden channel, kernel size训练模型,以RMSE为指标得到最佳的SCNN模型及其参数。
方法改进:针对节假日,我们发现不同节假日的业务量趋势结构各不相同,且都与平峰期不同,例如端午期间就不是以一周为长周期的趋势。因此针对节假日我们单独训练了模型,考虑到节假日有提前开售以及人们不同的返程习惯,这里使用的是每个节假日前30天起到节假日结束后7天的数据,同样通过调试不同的模型参数来确定最佳的节假日SCNN模型。而针对平峰期,我们即使用2019年与2023年全年的数据进行训练,得到最佳模型。
模型应用:根据上述方法分别得到了适用于平峰期与节假日高峰期的两个模型。随后我们将模型应用在2024年的数据上进行准确性的验证。
5.2 代码实现&结果解读
考虑到春节的特殊性,我们选择从2024年3月1日起进行模型的验证:用每168H的数据来预测下一个24H的业务量(例如用3/1~3/7的数据预测3/8的数据),并采取rolling prediction的方式对3~6月的每日业务量数据进行预测(用3/1~3/7的数据预测3/8的数据,随后用3/2~3/8的数据预测3/9的数据)。过程中并未用到任何实际真实的数据,完全是通过模型预测完成了对3个月内每天业务量的预测任务。整个预测期间会涉及清明、五一与端午三个节假日,我们会在平峰期时使用平峰期SCNN模型;在节假日适用高峰期SCNN模型。下方展示了部分训练及预测使用的代码模块:
# 设置规定指标阈值与迭代次数,训练模型得到最佳模型
for epoch in range(nb_epoch):
model.train()
running_loss = []
for j, x_batch in enumerate(gen_batch(dataset.get_data('train'), batch_size, dynamic_batch=False, shuffle=True)):
xh = torch.tensor(xh, dtype=torch.float32).to(device)
y = torch.tensor(y, dtype=torch.float32).to(device)
pred_distr, pred_distr_aux = model(xh)
model.zero_grad()
loss = - pred_distr.log_prob(y.permute(0, 2, 1, 3).reshape(-1, n_pred)).mean() - 0 * pred_distr_aux.log_prob(y.permute(0, 2, 1, 3).reshape(-1, n_pred)).mean()
loss.backward()
nn.utils.clip_grad_norm_(model.parameters(), 10)
optimizer.step()
running_loss.append(loss.data.cpu().numpy())
if epoch % 10 == 0:
model.eval()
min_va_val, min_val, min_ta_val = model_inference(device, model, dataset, test_batch_size, n_his, n_pred, min_va_val, min_val, n)
for i in range(n_pred):
print(f'MAPE {va[i*3]:7.3%}, {te[i*3]:7.3%}, {ta[i*3]:7.3%};'
f'MAE {va[i*3+1]:4.3f}, {te[i*3+1]:4.3f}, {ta[i*3+1]:4.3f};'
f'RMSE {va[i*3+2]:6.3f}, {te[i*3+2]:6.3f}, {ta[i*3+2]:6.3f}.')
if va_mean_rmse < min_rmse:
torch.save(model.state_dict(), best_model_path)
min_rmse = va_mean_rmse
stop = 0
else:
stop += 1
if stop == 10:
break
model.load_my_state_dict(torch.load(best_model_path))
print('Best Results:')
#调用之前的最佳模型进行预测
model.load_my_state_dict(torch.load('MODEL/best_model.h5'))
model.eval()
#使用该模型对未来给定步长进行预测
norm_data = scaler.fit_transform(hist_data)
zz = torch.tensor(norm_data, dtype=torch.float32).to(device)
pred = model(zz)
preds.append(pred.data.cpu().numpy())
图5-2展示了某一天SCNN模型的预测结果与真实数据的对比情况,横坐标是当天的小时数。当天预测的总业务量的相对误差为1.43%。
图5-3展示了3-6月模型对于每天业务量的预测结果和真实结果的对比情况。整体预测值与实际值相对误差为1.34%。
从上图可以看出,平峰期模型的预测结果与实际情况相差不大,表现相对稳定。但是在五一、端午等节假日期间,模型预测与实际业务量的趋势大体相同但是在一些峰值表现上存在差距。
推测存在三方面原因:
1)模型目前是根据历史19年与23年的数据进行训练的,是基于这两年数据的表现结构进行的预测,24年存在一些额外的营销活动、以及24年与23年用户的出行需求也有所不同(23年因疫情放开导致用户“报复性”出游带来的出行需求增大,24年则可能趋于平稳)。
2)目前针对高峰期的模型,采用的训练数据只有19年与23年的12个节假日(因特殊性未使用春节数据),不充足的数据量会导致模型学到的结构规律不够稳定。
3)目前针对各个节假日使用的是同一个高峰期的SCNN模型,但其实各个节假日因放假时长不同,结构规律也不同,并不能完全用一个模型来进行预测,因此会导致预测结果的偏差。
5.3 落地应用&未来改进
将模型在2024年3-6月上的预测结果同步业务并获得接受之后,目前已将模型使用的训练数据更新到2024年6月,同时将此方法应用在对未来两个季度的每日业务量预测上,持续更新并以看板的形式呈现。后续考虑可以在以下四点上进行优化:
1)将每天预测的结果与真实结果之间的GAP作为模型目标函数的一部分,让模型更好地进行自我更新调整,得到更准确的预测结果。
2)将方法平台化、工具化,能够支持业务方自行选择想要预测的时间周期及变量,模型将根据该变量的历史表现判定是否适用SCNN模型,如果适用则进行训练并得到最佳模型,最终基于此模型输出预测结果。
3)目前模型对于节假日的预测表现并不十分稳定,主要原因也是训练的数据集过少且每年的节假日的营销手段不完全一致,并不能很好地固化每个节假日的结构特点。后续只有不断积累数据,同时也扩充一些“场外因素”,例如通过外部的用户搜索量、社媒上的出行讨论度、营销活动力度等等来及时反映出当前节假日的出行热度,从而更好地帮助模型预测此次节假日的业务量情况。
4)目前针对不同的节假日采用的是同一个节假日的SCNN模型,但其实各个节假日的结构特征不完全一致,最理想的状态是每个节假日有自己专属的SCNN模型来学习并预测,但现在的数据量暂不能达到训练的要求,只能等数据量的扩充或是在同一个节假日模型中加入参数区分不同的节假日来提升模型对不同节假日结构特点的适配性。
六、方法拓展
本文介绍的SCNN模型通过拆解长短周期项、季节性项以及序列间相关性项,对时序数据输出“点估计型”的预测结果。这可以和之前介绍过的CausalImpact相结合,在CausalImpact中也是先对时序数据进行拟合预测得到反事实值,然后得到预测值与真实值之间的差距来评估策略的提升效应。在CausalImpact中默认使用的时序模型是BSTS,但也可以自定义时序模型,例如我们可以自己训练SCNN模型,然后将此模型当做时序模型放到CausalImpact中计算策略的效应值。
from causalimpact.misc import standardize
normed_data, _ = standardize(data.astype(np.float32)) #标准化数据
obs_data = normed_data.iloc[:70, 0]
# 使用其他时序模型来进行拟合得到反事实值
linear_level = tfp.sts.LocalLinearTrend(observed_time_series=obs_data)
linear_reg = tfp.sts.LinearRegression(design_matrix=normed_data.iloc[:, 1:].values.reshape(-1, normed_data.shape[1] -1))
model = model.load_my_state_dict(torch.load('MODEL/best_SCNN_model.h5'))
# 将自义定时序模型代入CausalImpact包中
ci = CausalImpact(data, pre_period, post_period, model=model)
本文介绍了一种多元时间序列数据的预测模型,通过将数据拆解为长周期、季节性、短周期及序列间相关性四种结构,对数据进行解耦、分块预测、通过神经网络对预测结果进行融合来得到最终的输出结果;通过重构损失函数、置零残差项等方式提升了模型的鲁棒性与准确性,能够最大程度上学习到序列背后的结构特点并做出尽可能准确的预测结果。
本文进一步介绍了该方法的实现方式以及如何将该方法应用在实际的业务量预测上,结合具体的业务场景介绍了SCNN模型的具体使用步骤以及注意事项,同时就实践结果分析了该方法目前在应用上的优点与不足,以及后续的优化方向。
未来随着数据量的扩充以及模型的完善,有望针对不同类型的时序数据进行特定的结构学习与预测,另一方面,也可以通过使用SCNN模型进行反事实预测,将该方法拓展到CausalImpact等一些因果推断的评估场景中,更好地发挥其捕捉数据结构进行合理预测的优势。
参考文献
1. J. Deng *et al*., "Disentangling Structured Components: Towards Adaptive, Interpretable and Scalable Time Series Forecasting," in *IEEE Transactions on Knowledge and Data Engineering*, vol. 36, no. 8, pp. 3783-3800, Aug. 2024
2. SCNN在Python中的具体代码逻辑:
3. Qiu, J., Jammalamadaka, S. rao, & Ning, N. (2018). Multivariate Bayesian Structural Time Series Model. Journal of Machine Learning Research, 2018(19).
4. Brodersen, K. H., Gallusser, F., Koehler, J., Remy, N., & Scott, S. L. (2015). INFERRING CAUSAL IMPACT USING BAYESIAN STRUCTURAL TIME-SERIES MODELS. The Annals of Applied Statistics, 2015(9), 247–274.
5. CausalImpact:
【推荐阅读】
“携程技术”公众号
分享,交流,成长
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……
还没有评论,来说两句吧...