预测模型概述

预测模型是能够在给定某个时间序列的历史数据的情况下,生成关于该序列未来值的预测的模型。Darts 中的预测模型 列在 README 中 。它们具有不同的能力和特性。例如,一些模型处理多维时间序列,返回概率预测,或接受其他类型的外部 协变量 数据作为输入。

下面,我们概述这些特性的含义。

概述

所有预测模型的工作方式相同:首先它们被构建(接受一些超参数作为参数),然后通过调用 fit() 函数在一系列数据上进行拟合,最后通过调用 predict() 函数来获取一个或多个预测结果。

示例:

from darts.models import NaiveSeasonal

naive_model = NaiveSeasonal(K=1)            # init
naive_model.fit(train)                      # fit
naive_forecast = naive_model.predict(n=36)  # predict

predict() 的参数 n 表示要预测的时间戳数量。当 fit() 只提供一个训练 TimeSeries 时,该序列将被存储,并且 predict() 将返回该序列的预测结果。另一方面,一些模型支持在多个时间序列(一个 Sequence[TimeSeries] )上调用 fit()。在这种情况下,必须向 predict() 提供一个或多个序列,模型将为这些时间序列生成预测结果。

示例:

from darts.models import NBEATSModel

model = NBEATSModel(input_chunk_length=24,                 # init
                    output_chunk_length=12)

model.fit([series1, series2])                              # fit on two series
forecast = model.predict(series=[series3, series4], n=36)  # predict potentially different series

此外,我们定义了以下由模型消耗的时间序列类型:

  • 目标系列: 我们感兴趣的预测系列。

  • 协变量序列: 我们不感兴趣预测的其他一些序列,但它们可以为预测模型提供有价值的输入。

保存和加载模型

如果你想保存一个特定的模型并在其他地方或稍后的时间使用它,darts 可以实现这一点。它利用了 pickle,并且在 Torch 模型的情况下依赖于保存 PyTorch Lightning 训练器检查点。所有预测模型都支持通过调用 save() 函数将模型保存到文件系统中,该函数保存该特定的 ForecastingModel 对象实例。当模型需要再次使用时,可以使用 load() 方法。请注意,save_model()load_model() 方法已被弃用。

示例:

from darts.models import RegressionModel

model = RegressionModel(lags=4)

model.save("my_model.pkl")
model_loaded = RegressionModel.load("my_model.pkl")

参数 path 指定一个路径或文件句柄,用于在其当前状态下保存模型。如果没有指定 path ,模型将自动保存在 "{ModelClass}_{YYYY-mm-dd_HH:MM:SS}.pkl" 下。例如, "RegressionModel_2020-01-01_12:00:00.pkl" 。可选地,还有 pickle 特定的关键字参数 protocolfix_importsbuffer_callback 。更多信息: pickle.dump()

使用 torch 模型时,模型参数和训练状态会被保存。我们使用训练器来保存模型检查点。

示例:

from darts.models import NBEATSModel

model = NBEATSModel(input_chunk_length=24,
                    output_chunk_length=12)

model.save("my_model.pt")
model_loaded = NBEATSModel.load("my_model.pt")

torch 模型在幕后使用的私有方法:

  • save_checkpoint: 此外,我们需要使用 PTL save_checkpoint() 来正确保存训练器和模型。它用于在训练过程中保存模型的快照,然后能够在以后检索模型。

  • load_from_checkpoint: 返回一个在训练期间被检查点保存的模型(默认是验证损失最低的那个)。

对多元序列的支持

一些模型支持多元时间序列。这意味着在拟合和预测阶段提供给模型的目标(以及潜在的协变量)序列可以有多个维度。模型随后将产生多元预测。

以下是一个示例,使用 KalmanForecaster 来预测由两个成分组成的一个多元时间序列:

import darts.utils.timeseries_generation as tg
from darts.models import KalmanForecaster
import matplotlib.pyplot as plt

series1 = tg.sine_timeseries(value_frequency=0.05, length=100) + 0.1 * tg.gaussian_timeseries(length=100)
series2 = tg.sine_timeseries(value_frequency=0.02, length=100) + 0.2 * tg.gaussian_timeseries(length=100)

multivariate_series = series1.stack(series2)

model = KalmanForecaster(dim_x=4)
model.fit(multivariate_series)
pred = model.predict(n=50, num_samples=100)

plt.figure(figsize=(8,6))
multivariate_series.plot(lw=3)
pred.plot(lw=3, label='forecast')
预测多变量序列

这些模型在 模型列表Multivariate 列下显示为“✅”。

处理多个系列

一些模型支持在多个时间序列上进行拟合。要做到这一点,只需简单地向 fit() 提供一个 TimeSeries 的 Python Sequence``(例如一个 ``TimeSeries 列表)。当模型以这种方式拟合时,predict() 函数将期望设置 series 参数,其中包含一个或多个需要预测的 TimeSeries``(即单个或 ``TimeSeriesSequence)。在多个序列上训练的优势在于,单个模型可以接触到训练数据集中所有序列中出现的更多模式。这通常是有益的,特别是对于容量更大的模型。

反过来,predict() 一次为多个潜在的序列提供预测的优势在于,计算通常可以在多个序列之间批处理和矢量化,这比在孤立的序列上调用 predict() 多次在计算上更快。

这些模型在 模型列表多系列训练 列下显示为“✅”。

你也可以通过编程方式来确定一个模型是否支持多个系列。

from darts.models import RegressionModel
from darts.models.forecasting.forecasting_model import GlobalForecastingModel

# when True, multiple time series are supported
supports_multi_ts = issubclass(RegressionModel, GlobalForecastingModel)

这篇文章 提供了关于在多个时间序列上训练模型的更多解释。

协变量支持

一些模型支持 协变量序列 。协变量序列是模型可以作为输入的时间序列,但不会进行预测。我们区分 过去协变量未来协变量

  • 过去的协变量是协变量时间序列,其值在预测时**不**知道未来的情况。例如,这些可以表示必须测量且事先未知的信号。模型在做出预测时不使用 past_covariates 的未来值。

  • 未来协变量是协变量时间序列,其在预测时(直到预测范围)的未来值是已知的。这些可以代表日历信息、假期、天气预报等信号。接受 future_covariates 的模型在做出预测时将使用未来的值(直到预测范围)。

协变量

过去和未来的协变量可以通过分别提供 past_covariatesfuture_covariates 参数给 fit()predict() 来使用。当模型在多个目标序列上训练时,每个目标序列必须提供一个协变量。协变量序列本身可以是多元的,并且包含多个“协变量维度”;请参阅 TimeSeries 指南 了解如何构建多元序列。

不必担心协变量序列具有完全正确的时间跨度(例如,使得未来协变量的最后一个时间戳与预测范围匹配)。Darts 会在幕后根据目标和协变量的时间轴来处理协变量的切片。

支持过去(对应未来)协变量的模型在 模型列表过去观测协变量支持``(对应 ``未来已知协变量支持)列中用“✅”表示。

要了解更多关于协变量的信息,请参阅用户指南中的 协变量部分

此外,你可以查看 这篇文章 以了解如何使用过去和未来协变量的一些示例。

概率预报

Darts 中的一些模型可以生成概率性预测。对于这些模型,predict() 返回的 TimeSeries 将是概率性的,并包含一定数量的蒙特卡罗样本,描述时间和组件上的联合分布。样本数量可以直接通过 predict() 函数的 num_samples 参数确定(将 num_samples=1 将返回一个确定性的 TimeSeries)。

支持概率预测的模型在 模型列表Probabilistic 列中用“✅”表示。预测的实际概率分布取决于模型。

一些模型,如ARIMA、指数平滑、(T)BATS或KalmanForecaster,会做出正态性假设,并且结果分布是具有时间依赖参数的高斯分布。例如:

from darts.datasets import AirPassengersDataset
from darts import TimeSeries
from darts.models import ExponentialSmoothing

series = AirPassengersDataset().load()
train, val = series[:-36], series[-36:]

model = ExponentialSmoothing()
model.fit(train)
pred = model.predict(n=36, num_samples=500)

series.plot()
pred.plot(label='forecast')
指数平滑

概率神经网络

Darts 中的所有神经网络(基于 torch 的模型)都支持估计多种概率分布。在创建模型时,可以提供 darts.utils.likelihood_models 中可用的 似然模型 之一,该模型决定了模型将估计的分布。在这种情况下,模型将输出分布的参数,并通过最小化训练样本的负对数似然来进行训练。大多数似然模型还支持分布参数的先验值,在这种情况下,训练损失通过 Kullback-Leibler 散度项进行正则化,该项将结果分布推向由先验参数指定的分布方向。在创建似然模型对象时,也可以指定此正则化项的强度。

例如,下面的代码训练一个 TCNModel 以拟合拉普拉斯分布。因此,神经网络输出拉普拉斯分布的两个参数(位置和尺度)。我们还为尺度参数指定了一个先验值 0.1。

from darts.datasets import AirPassengersDataset
from darts import TimeSeries
from darts.models import TCNModel
from darts.dataprocessing.transformers import Scaler
from darts.utils.likelihood_models import LaplaceLikelihood

series = AirPassengersDataset().load()
train, val = series[:-36], series[-36:]

scaler = Scaler()
train = scaler.fit_transform(train)
val = scaler.transform(val)
series = scaler.transform(series)

model = TCNModel(input_chunk_length=30,
                 output_chunk_length=12,
                 likelihood=LaplaceLikelihood(prior_b=0.1))
model.fit(train, epochs=400)
pred = model.predict(n=36, num_samples=500)

series.plot()
pred.plot(label='forecast')
TCN 拉普拉斯回归

也可以使用神经网络进行分位数回归(使用任意分位数),通过使用 darts.utils.likelihood_models.QuantileRegression,在这种情况下,网络将使用平滑损失进行训练。这将生成一个经验性的非参数分布,并且在实践中通常是一个很好的选择,当不确定“真实”分布时,或者当拟合参数似然性结果不佳时。例如,下面的代码片段与前面的代码片段几乎完全相同;唯一的区别是它现在使用了一个 QuantileRegression 似然性,这意味着神经网络将使用平滑损失进行训练,并且其输出数量将动态配置以匹配分位数的数量。

from darts.datasets import AirPassengersDataset
from darts import TimeSeries
from darts.models import TCNModel
from darts.dataprocessing.transformers import Scaler
from darts.utils.likelihood_models import QuantileRegression

series = AirPassengersDataset().load()
train, val = series[:-36], series[-36:]

scaler = Scaler()
train = scaler.fit_transform(train)
val = scaler.transform(val)
series = scaler.transform(series)

model = TCNModel(input_chunk_length=30,
                 output_chunk_length=12,
                 likelihood=QuantileRegression(quantiles=[0.01, 0.05, 0.2, 0.5, 0.8, 0.95, 0.99]))
model.fit(train, epochs=400)
pred = model.predict(n=36, num_samples=500)

series.plot()
pred.plot(label='forecast')
TCN 分位数回归

使用蒙特卡洛辍学捕捉模型不确定性

在Darts中,辍学也可以作为一种捕捉模型不确定性的附加方式,遵循[1]中描述的方法。这有时被称为*认知不确定性*,可以看作是对由所有不同辍学激活函数表示的模型族进行边缘化的方式。

此功能适用于所有集成某些 dropout 的深度学习模型(RNN 模型除外 - 我们参考 dropout API 参考文档以了解支持此功能的模型)。它仅需要在预测时指定 mc_dropout=True。例如,以下代码训练一个 TCN 模型(使用默认的 MSE 损失),dropout 率为 10%,然后使用蒙特卡罗 dropout 生成概率预测:

from darts.datasets import AirPassengersDataset
from darts import TimeSeries
from darts.models import TCNModel
from darts.dataprocessing.transformers import Scaler
from darts.utils.likelihood_models import QuantileRegression

series = AirPassengersDataset().load()
train, val = series[:-36], series[-36:]

scaler = Scaler()
train = scaler.fit_transform(train)
val = scaler.transform(val)
series = scaler.transform(series)

model = TCNModel(input_chunk_length=30,
                 output_chunk_length=12,
                 dropout=0.1)
model.fit(train, epochs=400)
pred = model.predict(n=36, mc_dropout=True, num_samples=500)

series.plot()
pred.plot(label='forecast')
TCN 分位数回归

蒙特卡罗辍学可以与Darts中的其他似然估计结合使用,这可以被解释为一种捕捉认知不确定性和偶然不确定性的方法。

概率回归模型

一些回归模型也可以配置为生成概率预测。在撰写本文时,LinearRegressionModelLightGBMModelXGBModel 支持 likelihood 参数。当设置为 "poisson" 时,模型将拟合泊松分布,当设置为 "quantile" 时,模型将使用 pinball 损失进行分位数回归(分位数本身可以使用 quantiles 参数指定)。

示例:

from darts.datasets import AirPassengersDataset
from darts import TimeSeries
from darts.models import LinearRegressionModel

series = AirPassengersDataset().load()
train, val = series[:-36], series[-36:]

model = LinearRegressionModel(lags=30,
                              likelihood="quantile",
                              quantiles=[0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95])
model.fit(train)
pred = model.predict(n=36, num_samples=500)

series.plot()
pred.plot(label='forecast')
分位数线性回归

[1] Yarin Gal, Zoubin Ghahramani, “Dropout作为贝叶斯近似:在深度学习中表示模型不确定性”