预测模型概述

预测模型是可以根据时间序列的历史数据,生成关于该系列未来值的预测模型。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 特定的关键字参数 protocol, fix_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 预测一个由 2 个分量组成的单一度量多变量时间序列

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')
Forecasting a multivariate series

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

处理多个时间序列

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

反过来,predict() 函数能够同时为多个时间序列提供预测结果的优势在于,计算通常可以在多个时间序列上进行批量处理和向量化,这比在孤立的时间序列上多次调用 predict() 的计算速度更快。

这些模型在模型列表Multiple-series training 列下以“✅”表示。

您还可以通过编程方式了解某个模型是否支持多个时间序列。

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 的模型在进行预测时将使用未来值(直至预测范围)。

covariates

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

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

支持历史协变量(或未来协变量)的模型在模型列表Past-observed covariates support(或 Future-known covariates support)列下以“✅”表示。

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

此外,您可以查阅本文,了解一些使用历史和未来协变量的示例。

概率预测

Darts 中的一些模型可以生成概率预测。对于这些模型,predict() 返回的 TimeSeries 将是概率性的,包含一定数量的 Monte Carlo 样本,描述时间和分量上的联合分布。样本数量可以直接由 predict() 函数的参数 num_samples 确定(设置为 num_samples=1 将返回确定性 TimeSeries)。

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

一些模型,如 ARIMA、Exponential Smoothing、(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')
Exponential Smoothing

概率神经网络

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

例如,下面的代码训练一个 TCNModel 来拟合 Laplace 分布。因此神经网络输出 Laplace 分布的 2 个参数(位置和尺度)。我们还指定尺度参数的先验值为 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.torch 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 Laplace regression

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

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.torch 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 quantile regression

使用 Monte Carlo Dropout 捕获模型不确定性

在 Darts 中,dropout 也可以用作捕获模型不确定性的额外方法,遵循 [1] 中描述的方法。这有时被称为认知不确定性,可以看作是通过所有不同的 dropout 激活函数表示的模型族进行边缘化的一种方式。

此功能适用于集成了一些 dropout 的所有深度学习模型(RNN 模型除外 - 对于支持此功能的模型,请参见 dropout API 参考文档)。它只需要在预测时指定 mc_dropout=True。例如,下面的代码训练一个 dropout 率为 10% 的 TCN 模型(使用默认的 MSE 损失),然后使用 Monte Carlo 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.torch 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 quantile regression

Monte Carlo Dropout 可以与 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')
quantile linear regression

[1] Yarin Gal, Zoubin Ghahramani, “Dropout as a Bayesian Approximation: Representing Model Uncertainty in Deep Learning”