简单指数平滑优化模型
使用 Statsforecast
调用 SimpleExponentialSmoothingOptimized Model
的逐步指南。
目录
- 介绍
- 简单指数平滑优化模型
- 加载库和数据
- 使用 plot 方法探索数据
- 将数据分割为训练集和测试集
- 使用 StatsForecast 实现 SimpleExponentialSmoothingOptimized
- 交叉验证
- 模型评估
- 参考
介绍
简单指数平滑优化 (SES Optimized) 是一种用于预测单变量时间序列未来值的预测模型。它是简单指数平滑 (SES) 方法的一种变体,使用优化方法来更准确地估计模型参数。
SES Optimized 方法使用单个平滑参数来估计时间序列数据中的趋势和季节性。该模型尝试使用优化算法最小化训练样本中预测值与实际值之间的均方误差 (MSE)。
SES Optimized 方法对于具有强烈趋势和季节性模式的时间序列或具有噪声数据的时间序列特别有用。然而,重要的是要注意,该模型假设时间序列是平稳的,并且数据中的变化是随机的,数据中不存在非随机模式。如果这些假设不满足,SES Optimized 模型可能表现不佳,可能需要采用其他预测方法。
简单指数平滑模型
指数平滑方法中最简单的方法自然称为简单指数平滑 (SES)。此方法适用于预测没有明显趋势或季节性模式的数据。
使用朴素方法,未来的所有预测都等于序列的最后一个观测值,
对于 。因此,朴素方法假设最近的观测值是唯一重要的,所有先前的观测值都不能提供未来信息。这可以视为一种加权平均,其中所有权重都赋予了最后一个观测值。
使用平均方法,未来的所有预测都等于观测数据的简单平均值,
对于 因此,平均方法假设所有观测值具有同等重要性,并在生成预测时给予它们相等的权重。
我们通常希望介于这两个极端之间的方法。例如,为较近的观测值赋予比遥远过去的观测值更大的权重可能是有意义的。这正是简单指数平滑背后的概念。预测值是使用加权平均计算的,其中权重随着观测值来自更远的过去而呈指数级下降——最小的权重与最旧的观测值相关。
其中 是平滑参数。时间点 的一步预测是序列 中所有观测值的加权平均值。权重下降的速度由参数 控制。
对于 0 到 1 之间的任意 ,赋予观测值的权重随着我们回溯时间呈指数级下降,因此得名“指数平滑”。如果 小(即接近 0),则更多权重赋予来自更遥远过去的观测值。如果 大(即接近 1),则更多权重赋予较近的观测值。在 的极端情况下,,预测值等于朴素预测值。
优化
应用每种指数平滑方法都需要选择平滑参数和初始值。特别是对于简单指数平滑,我们需要选择 和 的值。一旦知道这些值,就可以从数据计算所有预测。对于后续方法,通常需要选择多个平滑参数和多个初始分量。
在某些情况下,平滑参数可以主观选择——预测者根据先前的经验指定平滑参数的值。然而,一种更可靠和客观的方法来获取未知参数的值是从观测数据中估计它们。
从回归模型中,我们通过最小化残差平方和(通常称为 SSE 或“平方误差和”)来估计回归模型的系数。类似地,任何指数平滑方法的未知参数和初始值可以通过最小化 SSE 来估计。残差指定为 ,对于 。因此,我们找到最小化未知参数和初始值的值。
与回归情况(我们有公式可以返回最小化 SSE 的回归系数的值)不同,这涉及一个非线性最小化问题,我们需要使用优化工具来解决它。
加载库和数据
提示
需要 Statsforecast。要安装,请参见 说明。
接下来,我们导入绘图库并配置绘图样式。
读取数据
时间 | 广告 | |
---|---|---|
0 | 2017-09-13T00:00:00 | 80115 |
1 | 2017-09-13T01:00:00 | 79885 |
2 | 2017-09-13T02:00:00 | 89325 |
3 | 2017-09-13T03:00:00 | 101930 |
4 | 2017-09-13T04:00:00 | 121630 |
StatsForecast 的输入始终是具有三列的长格式数据框:unique_id、ds 和 y
-
unique_id
(字符串、整数或类别)表示序列的标识符。 -
ds
(时间戳)列应采用 Pandas 预期的格式,日期理想格式为 YYYY-MM-DD,时间戳理想格式为 YYYY-MM-DD HH:MM:SS。 -
y
(数值)表示我们希望预测的度量值。
ds | y | unique_id | |
---|---|---|---|
0 | 2017-09-13T00:00:00 | 80115 | 1 |
1 | 2017-09-13T01:00:00 | 79885 | 1 |
2 | 2017-09-13T02:00:00 | 89325 | 1 |
3 | 2017-09-13T03:00:00 | 101930 | 1 |
4 | 2017-09-13T04:00:00 | 121630 | 1 |
我们可以看到我们的时间变量 (ds)
是对象格式,我们需要将其转换为日期格式。
使用 plot 方法探索数据
使用 StatsForecast 类中的 plot 方法绘制一些序列。此方法会从数据集中随机打印一个序列,对于基本探索性数据分析 (EDA) 很有用。
自相关图
将数据分割为训练集和测试集
让我们将数据分成几个集合
- 用于训练我们的
Simple Exponential Smoothing Optimized Model
的数据 - 用于测试我们的模型的数据
对于测试数据,我们将使用最后 30 小时的数据来测试和评估我们模型的性能。
使用 StatsForecast 实现 SimpleExponentialSmoothingOptimized
加载库
实例化模型
我们通过实例化一个新的 StatsForecast 对象并传入以下参数来拟合模型
models:模型列表。从 models 中选择您想要的模型并导入它们。
-
freq:
表示数据频率的字符串。(参见 pandas 可用频率。) -
n_jobs:
n_jobs: int,并行处理中使用的作业数,使用 -1 表示所有核心。 -
fallback_model:
如果某个模型失败,则使用的后备模型。
任何设置都会传递给构造函数。然后调用其 fit 方法并传入历史数据框。
拟合模型
让我们看看 Simple Exponential Smoothing Optimized model
的结果。我们可以使用以下指令观察它
现在让我们可视化模型的残差。
如我们所见,上面获得的结果是一个字典输出,要从字典中提取每个元素,我们将使用 .get()
函数来提取元素,然后将其保存在 pd.DataFrame()
中。
fitted | ds | |
---|---|---|
0 | NaN | 2017-09-13 00:00:00 |
1 | 80115.000000 | 2017-09-13 01:00:00 |
2 | 79887.296875 | 2017-09-13 02:00:00 |
… | … | … |
183 | 141519.406250 | 2017-09-20 15:00:00 |
184 | 141589.296875 | 2017-09-20 16:00:00 |
185 | 140619.796875 | 2017-09-20 17:00:00 |
预测方法
如果您希望在具有多个序列或模型的生产环境中提高速度,我们建议使用 StatsForecast.forecast
方法,而不是 .fit
和 .predict
。
主要区别在于 .forecast
不存储拟合值,并且在分布式环境中具有很高的可伸缩性。
forecast 方法接受两个参数:预测接下来的 h
(预测范围)和 level
。
h (int):
表示预测未来 h 步。在本例中,预测未来 30 小时。
这里的 forecast 对象是一个新的数据框,其中包含模型名称和 y hat 值列,以及不确定性区间列。根据您的计算机性能,此步骤大约需要 1 分钟。
unique_id | ds | SESOpt | |
---|---|---|---|
0 | 1 | 2017-09-20 18:00:00 | 139526.046875 |
1 | 1 | 2017-09-20 19:00:00 | 139526.046875 |
2 | 1 | 2017-09-20 20:00:00 | 139526.046875 |
… | … | … | … |
27 | 1 | 2017-09-21 21:00:00 | 139526.046875 |
28 | 1 | 2017-09-21 22:00:00 | 139526.046875 |
29 | 1 | 2017-09-21 23:00:00 | 139526.046875 |
让我们可视化拟合值
unique_id | ds | y | SESOpt | |
---|---|---|---|---|
0 | 1 | 2017-09-13 00:00:00 | 80115.0 | NaN |
1 | 1 | 2017-09-13 01:00:00 | 79885.0 | 80115.000000 |
2 | 1 | 2017-09-13 02:00:00 | 89325.0 | 79887.296875 |
3 | 1 | 2017-09-13 03:00:00 | 101930.0 | 89230.625000 |
4 | 1 | 2017-09-13 04:00:00 | 121630.0 | 101803.007812 |
带置信区间的预测方法
要生成预测,请使用 predict 方法。
predict 方法接受两个参数:预测接下来的 h
(表示预测范围)和 level
。
h (int):
表示预测未来 h 步。在本例中,预测未来 30 小时。
这里的 forecast 对象是一个新的数据框,其中包含模型名称和 y hat 值列,以及不确定性区间列。
此步骤应花费不到 1 秒。
unique_id | ds | SESOpt | |
---|---|---|---|
0 | 1 | 2017-09-20 18:00:00 | 139526.046875 |
1 | 1 | 2017-09-20 19:00:00 | 139526.046875 |
2 | 1 | 2017-09-20 20:00:00 | 139526.046875 |
… | … | … | … |
27 | 1 | 2017-09-21 21:00:00 | 139526.046875 |
28 | 1 | 2017-09-21 22:00:00 | 139526.046875 |
29 | 1 | 2017-09-21 23:00:00 | 139526.046875 |
交叉验证
在之前的步骤中,我们使用了历史数据来预测未来。然而,为了评估其准确性,我们也想知道模型在过去的表现如何。为了评估您的模型在数据上的准确性和鲁棒性,请执行交叉验证。
对于时间序列数据,交叉验证通过在历史数据上定义一个滑动窗口并预测其后续周期来完成。这种形式的交叉验证使我们能够在更广泛的时间实例范围内更好地估计模型的预测能力,同时保持训练集中的数据连续,这是我们的模型所要求的。
下图描述了这种交叉验证策略
执行时间序列交叉验证
时间序列模型的交叉验证被认为是一种最佳实践,但大多数实现都非常慢。statsforecast 库将交叉验证实现为分布式操作,从而减少了执行过程的时间消耗。如果您有大型数据集,还可以使用 Ray、Dask 或 Spark 在分布式集群中执行交叉验证。
在本例中,我们想评估每个模型在过去 5 个月 (n_windows=)
内的表现,每隔一个月 (step_size=12)
进行预测。根据您的计算机性能,此步骤大约需要 1 分钟。
StatsForecast 类中的 cross_validation 方法接受以下参数。
-
df:
训练数据框 -
h (int):
表示预测未来的 h 步。在本例中,预测未来 30 小时。 -
step_size (int):
每个窗口之间的步长。换句话说:您希望多久运行一次预测过程。 -
n_windows(int):
用于交叉验证的窗口数量。换句话说:您想评估过去多少个预测过程。
crossvalidation_df 对象是一个新的数据框,包含以下列
unique_id:
索引。如果您不喜欢使用索引,只需运行crossvalidation_df.reset_index()
。ds:
时间戳或时间索引cutoff:
n_windows
的最后一个时间戳或时间索引。y:
真实值model:
包含模型名称和拟合值的列。
unique_id | ds | cutoff | y | SESOpt | |
---|---|---|---|---|---|
0 | 1 | 2017-09-18 06:00:00 | 2017-09-18 05:00:00 | 99440.0 | 111447.140625 |
1 | 1 | 2017-09-18 07:00:00 | 2017-09-18 05:00:00 | 97655.0 | 111447.140625 |
2 | 1 | 2017-09-18 08:00:00 | 2017-09-18 05:00:00 | 97655.0 | 111447.140625 |
… | … | … | … | … | … |
87 | 1 | 2017-09-21 21:00:00 | 2017-09-20 17:00:00 | 103080.0 | 139526.046875 |
88 | 1 | 2017-09-21 22:00:00 | 2017-09-20 17:00:00 | 95155.0 | 139526.046875 |
89 | 1 | 2017-09-21 23:00:00 | 2017-09-20 17:00:00 | 80285.0 | 139526.046875 |
模型评估
现在我们将使用预测结果来评估我们的模型,我们将使用不同类型的指标 MAE、MAPE、MASE、RMSE、SMAPE 来评估准确性。
unique_id | metric | SESOpt | |
---|---|---|---|
0 | 1 | mae | 29230.182292 |
1 | 1 | mape | 0.314203 |
2 | 1 | mase | 3.611444 |
3 | 1 | rmse | 35866.963426 |
4 | 1 | smape | 0.124271 |
参考
- Changquan Huang • Alla Petukhina. Springer 系列 (2022)。Applied Time Series Analysis and Forecasting with Python。
- Ivan Svetunkov. 使用增强动态自适应模型 (ADAM) 进行预测和分析
- James D. Hamilton. 时间序列分析 Princeton University Press, Princeton, New Jersey, 1st Edition, 1994。
- Nixtla 参数.
- Pandas 可用频率.
- Rob J. Hyndman and George Athanasopoulos (2018)。“Forecasting Principles and Practice (3rd ed)”.
- 季节周期 - Rob J Hyndman.