预测模型概述¶
预测模型是可以根据时间序列的历史数据,生成关于该系列未来值的预测模型。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_imports
和 buffer_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')

这些模型在模型列表的 Multivariate
列下以“✅”表示。
处理多个时间序列¶
有些模型支持在多个时间序列上进行拟合。为此,只需向 fit()
提供一个 TimeSeries
的 Python Sequence
(例如一个 TimeSeries
列表)即可。当模型以这种方式拟合后,predict()
函数将期望设置参数 series
,其中包含需要预测的一个或多个 TimeSeries
(即单个 TimeSeries
或 TimeSeries
的 Sequence
)。在多个时间序列上训练的优势在于,单个模型可以接触到训练数据集中所有时间序列中出现的更多模式。这通常是有益的,特别是对于容量更大的模型。
反过来,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
的模型在进行预测时将使用未来值(直至预测范围)。

可以通过分别向 fit()
和 predict()
提供 past_covariates
和 future_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')

概率神经网络¶
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')

也可以通过使用 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')

使用 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')

Monte Carlo Dropout 可以与 Darts 中的其他似然估计方法结合使用,这可以解释为一种同时捕获认知不确定性和偶然不确定性的方法。
概率回归模型¶
一些回归模型也可以配置为生成概率预测。截至本文撰写时,LinearRegressionModel、LightGBMModel 和 XGBModel 支持 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 as a Bayesian Approximation: Representing Model Uncertainty in Deep Learning”