来自 BSTS 模型(在 R 中)的预测完全失败

机器算法验证 r 时间序列 贝叶斯 马尔可夫链蒙特卡罗 bsts
2022-01-21 00:55:35

在阅读了这篇关于贝叶斯结构时间序列模型的博文后,我想看看在我之前使用 ARIMA 解决的问题的背景下实现这一点。

我有一些数据,其中包含一些已知的(但嘈杂的)季节性成分——这肯定有每年、每月和每周的成分,还有一些特殊日子(如联邦或宗教节日)的影响。

我已经使用该bsts包来实现这一点,据我所知,我没有做错任何事情,尽管组件和预测看起来不像我期望的那样。我不清楚我的实现是错误的、不完整的还是有其他问题。

完整的时间序列如下所示:

完整数据

我可以在数据的某些子集上训练模型,并且模型在拟合方面通常看起来不错(图如下)。我用来执行此操作的代码在这里:

library(bsts)

predict_length = 90
training_cut_date <- '2015-05-01'
test_cut_date <- as.Date(training_cut_date) + predict_length

df = read.csv('input.tsv', sep ='\t')

df$date <- as.Date(as.character(df$date),format="%Y-%m-%d")
df_train = df[df$date < training_cut_date,]

yts <- xts(log10(df_train$count), order.by=df_train$date)

ss <- AddLocalLinearTrend(list(), yts)
ss <- AddSeasonal(ss, yts, nseasons = 7)
ss <- AddSeasonal(ss, yts, nseasons = 12)
ss <- AddNamedHolidays(ss, named.holidays = NamedHolidays(), yts)

model <- bsts(yts, state.specification = ss, niter = 500, seed=2016)

该模型看起来很合理:

模型图

但是,如果我绘制预测,那么首先趋势是完全错误的,其次不确定性增长得非常快 - 以至于我无法在与预测相同的图上显示不确定性带而不在日志上制作 y 轴 -规模。这部分的代码在这里:

burn <- SuggestBurn(0.1, model)
pred <- predict(model, horizon = predict_length, burn = burn, quantiles = c(.025, .975))

纯粹的预测如下所示:

纯粹的预测

然后当缩小到初始分布时(虚线显示从训练到预测的过渡,问题很明显:

完整发行版

我尝试添加更多季节性趋势、删除季节性趋势、添加 AR 术语、将 AddLocalLinearModel 更改为 AddGeneralizedLocalLinearTrend 以及其他一些关于调整模型的事情,但没有任何事情能够解决问题并使预测更有意义。在某些情况下,方向会发生变化,因此预测不会下降到 0,而是随着时间的推移而继续增加。我绝对不明白为什么模型会以这种方式崩溃。任何建议都会非常受欢迎。

2个回答

史蒂夫斯科特在这里。我写了 bsts 包。我有几个建议给你。首先,您的季节性组件并没有像您认为的那样做。我认为您有每日数据,因为您正在尝试添加一个 7 季的组件,该组件应该可以正常工作。但是您已经告诉您的年度季节性组件每 12 天重复一次。获取包含每日数据的每月季节性组件有点困难,但您可以通过 AddSeasonal(..., nseasons = 52, season.duration = 7).

seasonal.duration参数告诉模型每个季节应该持续多少时间点。nseasons参数告诉它一个周期中有多少个季节。一个周期内的时间点总数为season.duration * nseasons

第二个建议是您可能想考虑一个不同的趋势模型。LocalLinearTrend模型非常灵活,但这种灵活性可能会在长期预测中显示为不希望出现的差异。还有一些其他趋势模型包含更多结构。 GeneralizedLocalLinearTrend(对非描述性名称感到抱歉)假设趋势的“斜率”分量是 AR1 过程而不是随机游走。如果我想预测很远的未来,这是我的默认选项。您的大部分时间序列变化似乎来自季节性,因此您可以尝试AddLocalLevel甚至AddAr代替AddLocalLinearTrend.

最后,一般来说,如果你得到奇怪的预测,并且你想弄清楚模型的哪一部分是罪魁祸首,试着plot(model, "components")看看模型分解成你要求的各个部分。

我认为您也可以更改默认刻录。由于我使用了 bsts,因此我创建了一个燃烧值和硝化值网格,并使用 MAPE 作为我对保留期的统计数据。如果您的数据有很大的变化,也可以尝试使用 AddStudentLocalLinearTrend 来让模型预期这种变化