原文:
towardsdatascience.com/convenient-time-series-forecasting-with-sktime-bb82375e846c
啊,时间序列预测。这是许多数据科学家最核心的任务,在各个行业中都有一定的普遍性。这个领域之所以有价值,是因为如果你有一个水晶球可以提前看到一些关键数字,你可以利用这些信息先发制人,为即将到来的事情做好准备。
作者提供的图片。
考虑一个呼叫中心:预测呼叫量可以优化人员配置,确保高效处理客户咨询。在零售业,预测某个商品何时会缺货,可以及时补货,防止销售损失并最大化收入。当然,股市预测的圣杯:如果你能做这件事,你就会变得富有。
在这篇文章中,我想向你展示如何使用令人惊叹的库sktime,时间序列预测的 scikit-learn,轻松地做到这一点。
为什么不直接使用 scikit-learn?
这是一个公平的问题!这有点像问,“为什么我要用高级的食品加工机,而不是一把刀和一块切菜板?”。当然,你可以用手切一切,但食品加工机是专门为这项任务设计的,可以使它更容易、更快。让我们看看我们的食品加工机 sktime 如何帮助我们。
作者提供的图片。
假设我们被给定了数据点的历史y = (y(1),y(2),…,y(T))。我们想使用它们来预测下一个时间步长y(T + 1)。T可能是今天,而T + 1 是明天。
通过回归建模
我们可以使用标准的机器学习技术来创建预测,但我们必须首先将预测问题重新表述为回归问题。我们已经看到,在时间序列预测中,我们只使用一个向量y来预测另一个值,而在监督机器学习中,我们需要特征和标签来训练模型。幸运的是,这种转换相当简单:
作者提供的动画。
在这里,我们使用滑动窗口方法,使用前三个y值作为特征,第四个作为标签。这些特征和标签的数量是你可以稍后调整的超参数。
手动实现
实现上述逻辑非常简单:
import numpy as np
def reduce(time_series: np.ndarray, n_lags: int):
X = []
y = []
for window_start in range(len(time_series) - n_lags):
X.append(time_series[window_start : window_start + n_lags])
y.append(time_series[window_start + n_lags])
return np.array(X), np.array(y)
在这里,我只是实现了具有单个标签的特殊情况。你可以这样使用它:
ts = np.array([1, 2, 3, 4, 5, 6, 7, 8])
X, y = reduce(ts, n_lags=3)
print(X)
print(y)
# Output:
# [[1 2 3]
# [2 3 4]
# [3 4 5]
# [4 5 6]
# [5 6 7]]
#
# [4 5 6 7 8]
现在,你可以使用任何你喜欢的监督模型,并在(X,y)上对其进行训练。那么,我们为什么还需要另一个库呢?嗯,在这个简单的例子中,我们的自定义代码一切正常,但如果我们想:
-
使用特殊逻辑预测几个时间步长,
-
预处理时间序列,或
-
使用不依赖于 scikit-learn 模型的时序方法
我们将感激 sktime 的灵活性。让我们看看我指的是什么。
sktime 简介
我已经告诉你 sktime 是多么的棒,但我仍然欠你一个证明。所以,让我们用 sktime 的语法表达滑动窗口逻辑和模型训练。
第一个例子
让我们导入一些功能和数据。我们将使用 sktime 附带的传统航空****数据集,由 Box & Jenkins 创建(BSD-3 许可证)。它包含从 1949 年 1 月开始的时间序列中每月的航空乘客数量。我们想要将乘客数量外推到未来,因此作为一家航空公司,我们可以部署足够的飞机。
from sklearn.linear_model import LinearRegression
from sktime.datasets import load_airline
from sktime.forecasting.compose import make_reduction
y = load_airline()
图片由作者提供。
现在,我们可以使用滑动窗口方法像这样训练模型:
ml_model = make_reduction(LinearRegression(), window_length=12)
ml_model.fit(y)
就这样。我们使用一个窗口长度为 12——这意味着我们使用过去 12 个月来预测下一个月——因为我们能够观察到年度季节性。我们也可以调整这个数字,但 12 已经足够好了。现在,sktime 让我们可以使用plot_series函数创建漂亮的图表:
from sktime.utils.plotting import plot_series
plot_series(
y, # plot the history
ml_model.predict(fh=np.arange(1, 13)), # plot the prediction
labels=["History", "Forecast"]
)
图片由作者提供。
这里有一些需要提到的事情。首先,看看预测是多么容易。我们只需调用.predict并给出我们感兴趣的(相对)时间步即可。fh代表预测范围,为了预测下 12 个月,我们可以将其设置为[1, 2, …, 11, 12]。
.predict方法返回一个具有一致时间索引的 pandas 系列,这使得绘图函数能够正确地对齐原始时间序列和预测。
内部机制
我们已经开发了一个线性回归模型,专门用于预测后续的时间步。那么,我们是如何预测 12 步之远的呢?有多种方法可以实现这一点,但 sktime 的默认方法是递归预测。这是它的工作方式:最初,我们预测下一个时间步,这是直截了当的。
图片由作者提供。
为了预测第二个,我们将我们创建的第一个预测视为实际输入。
图片由作者提供。
重复这个过程,直到你创建了所需的预测数量!
注意:我不会深入探讨递归方法。只需记住,最终模型开始仅基于其之前的预测进行预测,这可能会随着预测时间的延长而降低准确性。sktime 还提供其他方法,如直接预测,它为每个时间步使用一个单独的模型,以及多步预测,其中单个模型一次预测多个时间步。
经典时间序列模型
如果你想要尝试经典模型,如 ARIMA、指数平滑(ETS)或 TBATS,sktime 同样为你提供了支持。例如,如果你想训练一个具有乘法趋势和季节性的三重指数平滑(Holt-Winters),你可以这样做:
from sktime.forecasting.exp_smoothing import ExponentialSmoothing
classical_model = ExponentialSmoothing(trend="mul", seasonal="mul")
classical_model.fit(y)
你也可以在同一张图像中绘制两个预测结果,以便直观地判断哪个看起来更好。
plot_series(
y,
ml_model.predict(fh=np.arange(1, 37)),
classical_model.predict(fh=np.arange(1, 37)),
labels=["History", "ML Forecast", "ETS Forecast"]
)
图片由作者提供。
我们观察到,两个预测开始时有些相似,但指数平滑(ETS)版本中的峰值似乎上升得更快。在我看来,两个预测似乎都是合理的;然而,为了确定哪个是客观上更好的,我们需要使用性能指标进行更彻底的分析。让我们来做吧!
交叉验证
我们可以导入更多函数和类来正确地衡量性能。
from sktime.forecasting.model_evaluation import evaluate
from sktime.performance_metrics.forecasting import MeanSquaredError, MeanAbsolutePercentageError, MeanAbsoluteError
from sktime.split import ExpandingWindowSplitter
cv = ExpandingWindowSplitter(
initial_window=36,
step_length=12,
fh=np.arange(1, 13)
)
metrics = [
MeanAbsolutePercentageError(), # MAPE
MeanSquaredError(square_root=True), # RMSE by setting square_root = True, otherwise MSE
MeanAbsoluteError() # MAE
]
ml_evaluation = evaluate(ml_model, cv, y, scoring=metrics)
classical_evaluation = evaluate(classical_model, cv, y, scoring=metrics)
我们使用扩展窗口来评估它。它从 36 个月长度开始,我们总是将其移动 12 个月,并且总是预测 12 个月前。直观地看:
蓝色是训练期,橙色是测试期。图片由作者提供。
对于这 9 个不同的训练-测试分割,我们得到以下线性回归模型的结果:
图片由作者提供。
对于每个 9 个分割,我们可以在测试集上看到 MAPE、RMSE 和 MAE。此外,sktime 还提供了拟合和预测时间持续时间以及一些关于训练数据集的信息。同样,对于指数平滑模型,我们得到:
图片由作者提供。
由于解析起来有点困难,我们只需按 dataframe 取平均值来简化信息。如果我们可视化 RMSE 和 MAE,我们得到:
图片由作者提供。
因此,在这种情况下,ETS 获胜。然而,请记住,线性回归模型尚未调整。一个基本的超参数可以调整的是窗口长度。你还可以使用 sktime 进行特征工程,例如,创建移动平均值或标准差。
结论
在这篇文章中,我展示了如何简单地使用 sktime 进行每日预测任务。它就像 scikit-learn 一样用户友好,你甚至可以将你喜欢的 scikit-learn 模型集成进来进行预测!
然而,我们只探索了 sktime 的基本功能。在未来的文章中,我们将解决:
-
转换目标变量,
-
利用管道,
-
进行超参数调整,
-
特征工程,
-
以及更多。
此外,sktime 还提供了用于协调预测的工具,这在处理层次时间序列时非常有用。了解更多信息请点击此处:
希望您今天学到了一些新、有趣且有价值的东西。感谢阅读!
如果您有任何问题,请通过LinkedIn联系我!
如果你想更深入地探索算法的世界,不妨试试我的新书《算法全解析》!我仍在寻找作者!
54

被折叠的 条评论
为什么被折叠?



