一致性预测对使用点损失函数训练的模型进行交叉验证,以生成预测区间。无需额外训练,模型被视为黑盒。此方法兼容任何模型。

在本 notebook 中,我们将演示如何使用一致性预测来获得预测区间。

加载库

import logging

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.models import NHITS
from neuralforecast.utils import AirPassengersPanel
from neuralforecast.utils import PredictionIntervals
from neuralforecast.losses.pytorch import DistributionLoss, MAE
logging.getLogger('pytorch_lightning').setLevel(logging.ERROR)

数据

我们使用 AirPassengers 数据集来演示一致性预测。

AirPassengersPanel_train = AirPassengersPanel[AirPassengersPanel['ds'] < AirPassengersPanel['ds'].values[-12]].reset_index(drop=True)
AirPassengersPanel_test = AirPassengersPanel[AirPassengersPanel['ds'] >= AirPassengersPanel['ds'].values[-12]].reset_index(drop=True)
AirPassengersPanel_test['y'] = np.nan
AirPassengersPanel_test['y_[lag12]'] = np.nan

模型训练

我们现在在上述数据集上训练一个 NHITS 模型。为了支持一致性预测,我们必须首先实例化 PredictionIntervals 类,并将其传递给 fit 方法。默认情况下,PredictionIntervals 类在计算一致性分数时,会使用 n_windows=2 进行交叉验证。我们还使用 DistributionLoss 训练了一个 MLP 模型,以演示一致性预测与分位数输出之间的差异。

默认情况下,PredictionIntervals 类对一致性预测使用 method=conformal_distribution 方法,但也支持 method=conformal_error 方法。conformal_distribution 方法使用绝对误差计算预测路径,并基于此计算分位数。conformal_error 方法直接根据误差计算分位数。

我们考虑以下两种模型

  1. 使用点损失函数 (MAE) 训练的模型,我们使用一致性预测量化不确定性。此情况标记为 NHITS
  2. 使用 DistributionLoss('Normal') 训练的模型,我们通过训练模型以拟合正态分布的参数来量化不确定性。此情况标记为 NHITS1
horizon = 12
input_size = 24

prediction_intervals = PredictionIntervals()

models = [NHITS(h=horizon, input_size=input_size, max_steps=100, loss=MAE(), scaler_type="robust"), 
          NHITS(h=horizon, input_size=input_size, max_steps=100, loss=DistributionLoss("Normal", level=[90]), scaler_type="robust")]
nf = NeuralForecast(models=models, freq='ME')
nf.fit(AirPassengersPanel_train, prediction_intervals=prediction_intervals)

预测

要生成一致性区间,我们在 predict 方法中指定所需的水平。

preds = nf.predict(futr_df=AirPassengersPanel_test, level=[90])
fig, (ax1, ax2) = plt.subplots(2, 1, figsize = (20, 7))
plot_df = pd.concat([AirPassengersPanel_train, preds])

plot_df = plot_df[plot_df['unique_id']=='Airline1'].drop(['unique_id','trend','y_[lag12]'], axis=1).iloc[-50:]

ax1.plot(plot_df['ds'], plot_df['y'], c='black', label='True')
ax1.plot(plot_df['ds'], plot_df['NHITS'], c='blue', label='median')
ax1.fill_between(x=plot_df['ds'][-12:], 
                 y1=plot_df['NHITS-lo-90'][-12:].values,
                 y2=plot_df['NHITS-hi-90'][-12:].values,
                 alpha=0.4, label='level 90')
ax1.set_title('AirPassengers Forecast - Uncertainty quantification using Conformal Prediction', fontsize=18)
ax1.set_ylabel('Monthly Passengers', fontsize=15)
ax1.set_xticklabels([])
ax1.legend(prop={'size': 10})
ax1.grid()

ax2.plot(plot_df['ds'], plot_df['y'], c='black', label='True')
ax2.plot(plot_df['ds'], plot_df['NHITS1'], c='blue', label='median')
ax2.fill_between(x=plot_df['ds'][-12:], 
                 y1=plot_df['NHITS1-lo-90'][-12:].values,
                 y2=plot_df['NHITS1-hi-90'][-12:].values,
                 alpha=0.4, label='level 90')
ax2.set_title('AirPassengers Forecast - Uncertainty quantification using Normal distribution', fontsize=18)
ax2.set_ylabel('Monthly Passengers', fontsize=15)
ax2.set_xlabel('Timestamp [t]', fontsize=15)
ax2.legend(prop={'size': 10})
ax2.grid()