时间序列预测 - 评估指标

在使用 AutoML 框架时,选择正确的评估指标是最重要的决策之一。本页列出了 AutoGluon 中可用的预测评估指标,解释了何时使用不同的指标,并描述了如何定义自定义评估指标

使用 AutoGluon 时,您可以使用 TimeSeriesPredictoreval_metric 参数指定指标,例如

from autogluon.timeseries import TimeSeriesPredictor

predictor = TimeSeriesPredictor(eval_metric="MASE")

AutoGluon 将使用提供的指标来调整模型超参数、对模型进行排名并构建最终的集成模型进行预测。

注意

AutoGluon 始终以越大越好的格式报告所有指标。为此,某些指标会乘以 -1。例如,如果我们设置 eval_metric="MASE",预测器实际上会报告 -MASE(即 MASE 分数乘以 -1)。这意味着 test_score 将介于 0(最准确的预测)和 \(-\infty\)(最不准确的预测)之间。

目前,AutoGluon 支持以下评估指标:

SQL

缩放分位数损失。

WQL

加权分位数损失。

MAE

平均绝对误差。

MAPE

平均绝对百分比误差。

MASE

平均绝对缩放误差。

MSE

均方误差。

RMSE

均方根误差。

RMSLE

均方根对数误差。

RMSSE

均方根缩放误差。

SMAPE

对称平均绝对百分比误差。

WAPE

加权平均绝对百分比误差。

或者,您可以定义自定义预测评估指标

选择哪种评估指标?

如果您不确定选择哪种评估指标,以下三个问题可以帮助您为您的用例做出正确的选择。

1. 您是对点预测感兴趣还是对概率预测感兴趣?

如果您的目标是生成准确的概率预测,您应该使用 WQLSQL 指标。这些指标基于分位数损失,用于衡量分位数预测的准确性。默认情况下,AutoGluon 预测分位数水平 [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]。要预测不同的分位数集合,您可以使用 quantile_levels 参数。

predictor = TimeSeriesPredictor(eval_metric="WQL", quantile_levels=[0.1, 0.5, 0.75, 0.9])

本页描述的所有剩余预测指标都是预测指标。请注意,如果您在创建 TimeSeriesPredictor 时选择点预测指标作为 eval_metric,则最小化该指标的预测将始终在预测数据帧的 "mean" 列中提供。

2. 您是否更关注准确预测数值较大的时间序列?

如果答案是“是”(例如,如果准确预测畅销产品的销量很重要),您应该使用依赖于规模的指标,例如 WQLMAERMSEWAPE。这些指标也非常适合处理包含大量零的稀疏(间歇性)时间序列。

如果答案是“否”(您同样关心数据集中的所有时间序列),请考虑使用缩放指标,例如 SQLMASERMSSE。或者,也可以使用基于百分比的指标 MAPESMAPE 来平衡不同时间序列的规模。然而,这些基于百分比的指标有一些已知的局限性,因此我们不建议在实践中使用它们。请注意,缩放指标和基于百分比的指标都不太适合稀疏(间歇性)数据。

3. (仅限点预测)您想估计均值还是中位数?

要估计中位数,您需要使用 MAEMASEWAPE 等指标。如果您的目标是预测均值(期望值),您应该使用 MSERMSERMSSE 指标。

指标

概率性?

依赖于规模?

预测中位数还是均值?

SQL

WQL

MAE

中位数

MASE

中位数

WAPE

中位数

MSE

均值

RMSE

均值

RMSLE

RMSSE

均值

MAPE

SMAPE

点预测指标

我们在点预测指标的数学定义中使用以下符号:

  • \(y_{i,t}\) - 时间序列 \(i\) 在时间 \(t\) 的观测值

  • \(f_{i,t}\) - 时间序列 \(i\) 在时间 \(t\) 的预测值

  • \(N\) - 数据集中的时间序列数量(项目数量)

  • \(T\) - 观测到的时间序列长度

  • \(H\) - 预测范围的长度(prediction_length

class autogluon.timeseries.metrics.MAE(prediction_length: int = 1, seasonal_period: int | None = None, horizon_weight: Sequence[float] | None = None)[source]

平均绝对误差。

(1)\[\operatorname{MAE} = \frac{1}{N} \frac{1}{H} \sum_{i=1}^{N}\sum_{t=T+1}^{T+H} |y_{i,t} - f_{i,t}|\]

特性

  • 依赖于规模(绝对值较大的时间序列对损失贡献更大)

  • 对异常值不敏感

  • 偏好能准确估计中位数的模型

参考资料

class autogluon.timeseries.metrics.MAPE(prediction_length: int = 1, seasonal_period: int | None = None, horizon_weight: Sequence[float] | None = None)[source]

平均绝对百分比误差。

(2)\[\operatorname{MAPE} = \frac{1}{N} \frac{1}{H} \sum_{i=1}^{N} \sum_{t=T+1}^{T+H} \frac{ |y_{i,t} - f_{i,t}|}{|y_{i,t}|}\]

特性

  • 仅当所有时间序列都包含正值时才应使用

  • 对包含零值的时间序列未定义

  • 对过度预测的惩罚比对不足预测的惩罚更重

参考资料

class autogluon.timeseries.metrics.MASE(prediction_length: int = 1, seasonal_period: int | None = None, horizon_weight: Sequence[float] | None = None)[source]

平均绝对缩放误差。

通过该时间序列的历史季节误差对每个时间序列的绝对误差进行归一化。

(3)\[\operatorname{MASE} = \frac{1}{N} \frac{1}{H} \sum_{i=1}^{N} \frac{1}{a_i} \sum_{t=T+1}^{T+H} |y_{i,t} - f_{i,t}|\]

其中 \(a_i\) 是定义为以下的历史绝对季节误差:

(4)\[a_i = \frac{1}{T-m} \sum_{t=m+1}^T |y_{i,t} - y_{i,t-m}|\]

\(m\) 是时间序列的季节周期(eval_metric_seasonal_period)。

特性

  • 缩放指标(通过该时间序列的规模来归一化每个时间序列的误差)

  • 对常数时间序列未定义

  • 对异常值不敏感

  • 偏好能准确估计中位数的模型

参考资料

class autogluon.timeseries.metrics.MSE(prediction_length: int = 1, seasonal_period: int | None = None, horizon_weight: Sequence[float] | None = None)[source]

均方误差。

使用此指标将导致预测均值。

(5)\[\operatorname{MSE} = \frac{1}{N} \frac{1}{H} \sum_{i=1}^{N}\sum_{t=T+1}^{T+H} (y_{i,t} - f_{i,t})^2\]

特性

  • 依赖于规模(绝对值较大的时间序列对损失贡献更大)

  • 严重惩罚无法快速适应时间序列突变的模型

  • 对异常值敏感

  • 偏好能准确估计均值(期望值)的模型

参考资料

class autogluon.timeseries.metrics.RMSE(prediction_length: int = 1, seasonal_period: int | None = None, horizon_weight: Sequence[float] | None = None)[source]

均方根误差。

(6)\[\operatorname{RMSE} = \sqrt{\frac{1}{N} \frac{1}{H} \sum_{i=1}^{N}\sum_{t=T+1}^{T+H} (y_{i,t} - f_{i,t})^2}\]

特性

  • 依赖于规模(绝对值较大的时间序列对损失贡献更大)

  • 严重惩罚无法快速适应时间序列突变的模型

  • 对异常值敏感

  • 偏好能准确估计均值(期望值)的模型

参考资料

class autogluon.timeseries.metrics.RMSLE(prediction_length: int = 1, seasonal_period: int | None = None, horizon_weight: Sequence[float] | None = None)[source]

均方根对数误差。

在计算均方根误差之前,对预测值应用对数变换。假设真实值和预测值都为正。如果给出负预测值,则将其截断为零。

(7)\[\operatorname{RMSLE} = \sqrt{\frac{1}{N} \frac{1}{H} \sum_{i=1}^{N} \sum_{t=T+1}^{T+H} (\ln(1 + y_{i,t}) - \ln(1 + f_{i,t}))^2}\]

特性

  • 对包含负值的时间序列未定义

  • 对预测不足的模型惩罚比对预测过度的模型更重

  • 对异常值和规模的影响不敏感,最适合目标值可能呈指数变化或趋势的时间序列

参考资料

class autogluon.timeseries.metrics.RMSSE(prediction_length: int = 1, seasonal_period: int | None = None, horizon_weight: Sequence[float] | None = None)[source]

均方根缩放误差。

通过该时间序列的历史季节误差对每个时间序列的绝对误差进行归一化。

(8)\[\operatorname{RMSSE} = \sqrt{\frac{1}{N} \frac{1}{H} \sum_{i=1}^{N} \frac{1}{s_i} \sum_{t=T+1}^{T+H} (y_{i,t} - f_{i,t})^2}\]

其中 \(s_i\) 是定义为以下的历史平方季节误差:

(9)\[s_i = \frac{1}{T-m} \sum_{t=m+1}^T (y_{i,t} - y_{i,t-m})^2\]

\(m\) 是时间序列的季节周期(eval_metric_seasonal_period)。

特性

  • 缩放指标(通过该时间序列的规模来归一化每个时间序列的误差)

  • 对常数时间序列未定义

  • 严重惩罚无法快速适应时间序列突变的模型

  • 对异常值敏感

  • 偏好能准确估计均值(期望值)的模型

参考资料

class autogluon.timeseries.metrics.SMAPE(prediction_length: int = 1, seasonal_period: int | None = None, horizon_weight: Sequence[float] | None = None)[source]

对称平均绝对百分比误差。

(10)\[\operatorname{SMAPE} = 2 \frac{1}{N} \frac{1}{H} \sum_{i=1}^{N} \sum_{t=T+1}^{T+H} \frac{ |y_{i,t} - f_{i,t}|}{|y_{i,t}| + |f_{i,t}|}\]

特性

  • 仅当所有时间序列都包含正值时才应使用

  • 不适合包含零值的稀疏和间歇性时间序列

  • 对过度预测的惩罚比对不足预测的惩罚更重

参考资料

class autogluon.timeseries.metrics.WAPE(prediction_length: int = 1, seasonal_period: int | None = None, horizon_weight: Sequence[float] | None = None)[source]

加权平均绝对百分比误差。

定义为绝对误差之和除以预测范围内的绝对时间序列值之和。

(11)\[\operatorname{WAPE} = \frac{1}{\sum_{i=1}^{N} \sum_{t=T+1}^{T+H} |y_{i, t}|} \sum_{i=1}^{N} \sum_{t=T+1}^{T+H} |y_{i,t} - f_{i,t}|\]

特性

  • 依赖于规模(绝对值较大的时间序列对损失贡献更大)

  • 对异常值不敏感

  • 偏好能准确估计中位数的模型

如果提供了 self.horizon_weight,则分母中的误差和目标时间序列都将被重新加权。

参考资料

概率预测指标

除了上面列出的符号外,我们使用以下符号定义概率预测指标:

  • \(f_{i,t}^q\) - 时间序列 \(i\) 在时间 \(t\) 的预测分位数 \(q\)

  • \(\rho_q(y, f) \) - 水平 \(q\) 的分位数损失定义为:

\[\begin{split} \rho_q(y_{i,t}, f_{i,t}^q) = \begin{cases} 2 \cdot (1 - q) \cdot (f^q_{i,t} - y_{i,t}), & \text{ if } y_{i,t} < f_{i,t}^q\\ 2 \cdot q \cdot (y_{i,t} - f^q_{i,t} ), & \text{ if } y_{i,t} \ge f_{i,t}^q\\ \end{cases} \end{split}\]
class autogluon.timeseries.metrics.SQL(prediction_length: int = 1, seasonal_period: int | None = None, horizon_weight: Sequence[float] | None = None)[source]

缩放分位数损失。

也称为缩放弹珠损失(scaled pinball loss)。

通过该时间序列的历史季节误差对每个时间序列的分位数损失进行归一化。

(12)\[\operatorname{SQL} = \frac{1}{N} \frac{1}{H} \sum_{i=1}^{N} \frac{1}{a_i} \sum_{t=T+1}^{T+H} \sum_{q} \rho_q(y_{i,t}, f^q_{i,t})\]

其中 \(a_i\) 是定义为以下的历史绝对季节误差:

(13)\[a_i = \frac{1}{T-m} \sum_{t=m+1}^T |y_{i,t} - y_{i,t-m}|\]

\(m\) 是时间序列的季节周期(eval_metric_seasonal_period)。

特性

  • 缩放指标(通过该时间序列的规模来归一化每个时间序列的误差)

  • 对常数时间序列未定义

  • 如果 quantile_levels = [0.5] 则等同于 MASE

参考资料

class autogluon.timeseries.metrics.WQL(prediction_length: int = 1, seasonal_period: int | None = None, horizon_weight: Sequence[float] | None = None)[source]

加权分位数损失。

也称为加权弹珠损失(weighted pinball loss)。

定义为总分位数损失除以预测范围内的绝对时间序列值之和。

(14)\[\operatorname{WQL} = \frac{1}{\sum_{i=1}^{N} \sum_{t=T+1}^{T+H} |y_{i, t}|} \sum_{i=1}^{N} \sum_{t=T+1}^{T+H} \sum_{q} \rho_q(y_{i,t}, f^q_{i,t})\]

特性

  • 依赖于规模(绝对值较大的时间序列对损失贡献更大)

  • 如果 quantile_levels = [0.5] 则等同于 WAPE

如果提供了 horizon_weight,则分母中的误差和目标时间序列都将被重新加权。

参考资料

自定义预测指标

如果内置指标均不符合您的要求,您可以向 AutoGluon 提供自定义评估指标。要定义自定义指标,您需要创建一个继承自 TimeSeriesScorer 并按照以下 API 规范实现 compute_metric 方法的类:

TimeSeriesScorer.compute_metric(data_future: TimeSeriesDataFrame, predictions: TimeSeriesDataFrame, target: str = 'target', **kwargs) float[source]

计算给定预测和实际数据的指标的内部方法。

所有自定义指标都应实现此方法。

参数:
  • data_future (TimeSeriesDataFrame) – 预测范围内(数据集中的每个时间序列有 prediction_length 个值)时间序列的实际值。必须与 predictions 具有相同的索引。

  • predictions (TimeSeriesDataFrame) – 包含预测范围内预测值的数据帧。包含“mean”(点预测)列以及与每个分位数水平对应的列。必须与 data_future 具有相同的索引。

  • target (str, default = "target") – data_future 中包含目标时间序列的列的名称。

返回值:

score – 给定预测和数据的指标值。如果 self.greater_is_better_internal 为 True,则以“越大越好”格式返回分数,否则以“越小越好”格式返回。

返回类型:

float

自定义均方误差指标

以下是使用 TimeSeriesScorer 定义自定义均方误差 (MSE) 指标的示例。

import sklearn.metrics
from autogluon.timeseries.metrics import TimeSeriesScorer

class MeanSquaredError(TimeSeriesScorer):
   greater_is_better_internal = False
   optimum = 0.0

   def compute_metric(self, data_future, predictions, target, **kwargs):
      return sklearn.metrics.mean_squared_error(y_true=data_future[target], y_pred=predictions["mean"])

内部方法 compute_metric 返回“越小越好”格式的指标,因此我们需要将 greater_is_better_internal 设置为 False。这将告诉 AutoGluon 指标值必须乘以 -1 才能将其转换为“越大越好”格式。

注意

自定义指标必须在单独的 Python 文件中定义并导入,以便可以对其进行 pickle (Python 的序列化协议)。如果自定义指标不可 pickle,则在启用超参数调优时 AutoGluon 可能会在拟合过程中崩溃。在上面的示例中,您需要创建一个新的 python 文件,例如 my_metrics.py,并在其中定义 MeanSquaredError 类,然后通过 from my_metrics import MeanSquaredError 来使用它。

我们可以使用自定义指标来衡量预测器生成的预测的准确性。

import pandas as pd
from autogluon.timeseries import TimeSeriesPredictor, TimeSeriesDataFrame

# Create dummy dataset
data = TimeSeriesDataFrame.from_iterable_dataset(
   [
       {"start": pd.Period("2023-01-01", freq="D"), "target": list(range(15))},
       {"start": pd.Period("2023-01-01", freq="D"), "target": list(range(30, 45))},
    ]
)
prediction_length = 3
train_data, test_data = data.train_test_split(prediction_length=prediction_length)
predictor = TimeSeriesPredictor(prediction_length=prediction_length, verbosity=0).fit(train_data, hyperparameters={"Naive": {}})
predictions = predictor.predict(train_data)

mse = MeanSquaredError(prediction_length=predictor.prediction_length)
mse_score = mse(
  data=test_data,
  predictions=predictions,
  target=predictor.target,
)
print(f"{mse.name_with_sign} = {mse_score}")
-MeanSquaredError = -4.666666666666667

请注意,指标值已乘以 -1,因为我们在定义指标时将 greater_is_better_internal 设置为 False

当我们调用指标时,TimeSeriesScorer 会负责将 test_data 分割成过去和未来两部分,验证 predictions 具有正确的时间戳,并确保分数以“越大越好”格式报告。

在调用指标期间,我们实现的 compute_metric 方法接收以下参数作为输入:

  • 与预测范围相对应的测试数据

data_future = test_data.slice_by_timestep(-prediction_length, None)
data_future
target
item_id timestamp
0 2023-01-13 12
2023-01-14 13
2023-01-15 14
1 2023-01-13 42
2023-01-14 43
2023-01-15 44
  • 预测范围内的预测值

predictions.round(2)
均值 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9
item_id timestamp
0 2023-01-13 11.0 9.72 10.16 10.48 10.75 11.0 11.25 11.52 11.84 12.28
2023-01-14 11.0 9.19 9.81 10.26 10.64 11.0 11.36 11.74 12.19 12.81
2023-01-15 11.0 8.78 9.54 10.09 10.56 11.0 11.44 11.91 12.46 13.22
1 2023-01-13 41.0 39.72 40.16 40.48 40.75 41.0 41.25 41.52 41.84 42.28
2023-01-14 41.0 39.19 39.81 40.26 40.64 41.0 41.36 41.74 42.19 42.81
2023-01-15 41.0 38.78 39.54 40.09 40.56 41.0 41.44 41.91 42.46 43.22

请注意,data_futurepredictions 都涵盖相同的时间范围。

自定义分位数损失指标

该指标可以在 predictions DataFrame 的任何列上计算。例如,以下是我们如何定义衡量分位数预测准确性的平均分位数损失指标。

class MeanQuantileLoss(TimeSeriesScorer):
   needs_quantile = True
   greater_is_better_internal = False
   optimum = 0.0

   def compute_metric(self, data_future, predictions, target, **kwargs):
      quantile_columns = [col for col in predictions if col != "mean"]
      total_quantile_loss = 0.0
      for q in quantile_columns:
        total_quantile_loss += sklearn.metrics.mean_pinball_loss(y_true=data_future[target], y_pred=predictions[q], alpha=float(q))
      return total_quantile_loss / len(quantile_columns)

在这里,我们将 needs_quantile 设置为 True,以告诉 AutoGluon 该指标是在分位数预测上评估的。在这种情况下,DirectTabularModel 等模型将在底层训练一个 TabularPredictor,其 problem_type"quantile"。如果 needs_quantile 设置为 False,这些模型将使用 "regression" 作为 problem_type>

自定义平均绝对缩放误差指标

最后,以下是我们如何定义衡量分位数预测准确性的平均绝对缩放误差 (MASE) 指标。与之前讨论的指标不同,MASE 是使用过去未来时间序列值计算的。过去的值用于计算我们在预测范围内归一化误差的规模。

class MeanAbsoluteScaledError(TimeSeriesScorer):
  greater_is_better_internal = False
  optimum = 0.0
  optimized_by_median = True
  equivalent_tabular_regression_metric = "mean_absolute_error"

  def save_past_metrics(
      self, data_past: TimeSeriesDataFrame, target: str = "target", seasonal_period: int = 1, **kwargs
  ) -> None:
      seasonal_diffs = data_past[target].groupby(level="item_id").diff(seasonal_period).abs()
      self._abs_seasonal_error_per_item = seasonal_diffs.groupby(level="item_id").mean().fillna(1.0)

  def clear_past_metrics(self):
      self._abs_seasonal_error_per_item = None

  def compute_metric(
      self, data_future: TimeSeriesDataFrame, predictions: TimeSeriesDataFrame, target: str = "target", **kwargs
  ) -> float:
      mae_per_item = (data_future[target] - predictions["mean"]).abs().groupby(level="item_id").mean()
      return (mae_per_item / self._abs_seasonal_error_per_item).mean()

我们使用 save_past_metrics 方法计算过去数据的指标。在单独的方法中执行此操作可以使 AutoGluon 在拟合加权集成模型时避免冗余计算,这需要数千次指标评估。

因为我们将 optimized_by_median 设置为 True,AutoGluon 会自动将中位数预测粘贴到预测的 "mean" 列中。这样做是为了保持一致性:如果 TimeSeriesPredictor 使用点预测指标进行训练,则最佳点预测将始终存储在 "mean" 列中。最后,equivalent_tabular_regression_metric 被在底层拟合 TabularPredictor 的预测模型使用。

在 TimeSeriesPredictor 中使用自定义指标

现在我们已经创建了几个自定义指标,让我们使用它们来训练和评估模型。

predictor = TimeSeriesPredictor(eval_metric=MeanQuantileLoss()).fit(train_data, hyperparameters={"Naive": {}, "SeasonalNaive": {}, "Theta": {}})
Beginning AutoGluon training...
AutoGluon will save models to '/home/ci/autogluon/docs/tutorials/timeseries/AutogluonModels/ag-20250508_205158'
=================== System Info ===================
AutoGluon Version:  1.3.1b20250508
Python Version:     3.11.9
Operating System:   Linux
Platform Machine:   x86_64
Platform Version:   #1 SMP Wed Mar 12 14:53:59 UTC 2025
CPU Count:          8
GPU Count:          1
Memory Avail:       28.05 GB / 30.95 GB (90.6%)
Disk Space Avail:   211.69 GB / 255.99 GB (82.7%)
===================================================

Fitting with arguments:
{'enable_ensemble': True,
 'eval_metric': MeanQuantileLoss,
 'hyperparameters': {'Naive': {}, 'SeasonalNaive': {}, 'Theta': {}},
 'known_covariates_names': [],
 'num_val_windows': 1,
 'prediction_length': 1,
 'quantile_levels': [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9],
 'random_seed': 123,
 'refit_every_n_windows': 1,
 'refit_full': False,
 'skip_model_selection': False,
 'target': 'target',
 'verbosity': 2}
Inferred time series frequency: 'D'
Provided train_data has 24 rows, 2 time series. Median time series length is 12 (min=12, max=12).

Provided data contains following columns:
	target: 'target'

AutoGluon will gauge predictive performance using evaluation metric: 'MeanQuantileLoss'
	This metric's sign has been flipped to adhere to being higher_is_better. The metric score can be multiplied by -1 to get the metric value.
===================================================

Starting training. Start time is 2025-05-08 20:51:58
Models that will be trained: ['Naive', 'SeasonalNaive', 'Theta']
Training timeseries model Naive.
	-0.3323       = Validation score (-MeanQuantileLoss)
	0.02    s     = Training runtime
	0.02    s     = Validation (prediction) runtime
Training timeseries model SeasonalNaive.
	-2.3263       = Validation score (-MeanQuantileLoss)
	0.02    s     = Training runtime
	0.02    s     = Validation (prediction) runtime
Training timeseries model Theta.
	-0.2525       = Validation score (-MeanQuantileLoss)
	0.02    s     = Training runtime
	0.59    s     = Validation (prediction) runtime
Fitting simple weighted ensemble.
	Ensemble weights: {'Theta': np.float64(1.0)}
/home/ci/autogluon/timeseries/src/autogluon/timeseries/metrics/abstract.py:101: FutureWarning: Passing `prediction_length` to `TimeSeriesScorer.__call__` is deprecated and will be removed in v2.0. Please set the `eval_metric.prediction_length` attribute instead.
  warnings.warn(
	-0.2525       = Validation score (-MeanQuantileLoss)
	1.48    s     = Training runtime
	0.59    s     = Validation (prediction) runtime
Training complete. Models trained: ['Naive', 'SeasonalNaive', 'Theta', 'WeightedEnsemble']
Total runtime: 2.18 s
Best model: Theta
Best model score: -0.2525

我们也可以使用这些自定义指标来评估训练好的预测器。

predictor.evaluate(test_data, metrics=[MeanAbsoluteScaledError(), MeanQuantileLoss(), MeanSquaredError()])
Model not specified in predict, will default to the model with the best validation score: Theta
/home/ci/autogluon/timeseries/src/autogluon/timeseries/metrics/abstract.py:101: FutureWarning: Passing `prediction_length` to `TimeSeriesScorer.__call__` is deprecated and will be removed in v2.0. Please set the `eval_metric.prediction_length` attribute instead.
  warnings.warn(
/home/ci/autogluon/timeseries/src/autogluon/timeseries/metrics/abstract.py:101: FutureWarning: Passing `prediction_length` to `TimeSeriesScorer.__call__` is deprecated and will be removed in v2.0. Please set the `eval_metric.prediction_length` attribute instead.
  warnings.warn(
/home/ci/autogluon/timeseries/src/autogluon/timeseries/metrics/abstract.py:101: FutureWarning: Passing `prediction_length` to `TimeSeriesScorer.__call__` is deprecated and will be removed in v2.0. Please set the `eval_metric.prediction_length` attribute instead.
  warnings.warn(
{'MeanAbsoluteScaledError': np.float64(-0.07215007215007217),
 'MeanQuantileLoss': np.float64(-0.2525248845418294),
 'MeanSquaredError': -0.2550760126517704}

这就是在 AutoGluon 中创建和使用自定义预测指标的全部内容!

您可以查看 AutoGluon 源代码,了解分位数预测指标的示例实现。

如果您创建了自定义指标,请考虑提交一个 PR,以便我们可以将其正式添加到 AutoGluon 中。

如需更多教程,请参阅时间序列预测 - 快速入门时间序列预测 - 深入探讨

为单个模型自定义训练损失

虽然 eval_metric 用于模型选择和加权集成模型的构建,但它通常对单个预测模型的训练损失没有影响。

在某些模型中,例如 AutoETSAutoARIMA,训练损失是固定的,无法更改。相反,对于基于 GluonTS 的深度学习模型,可以通过修改 distr_output 超参数来更改训练损失。默认情况下,大多数 GluonTS 模型将 distr_output 设置为重尾的 StudentTOutput 分布,以增强对异常值的鲁棒性。

您可以将默认的 StudentTOutput 替换为 gluonts.torch.distributions 模块中的任何内置 Output。例如,在这里我们训练两个不同输出和损失的 PatchTST 版本:

  • NormalOutput - 模型输出高斯分布的参数,并使用负对数似然损失进行训练。

  • QuantileOutput - 模型输出分位数预测,并使用分位数损失进行训练。

from autogluon.timeseries import TimeSeriesPredictor
from gluonts.torch.distributions import NormalOutput, QuantileOutput

predictor = TimeSeriesPredictor(...)
predictor.fit(
    train_data,
    hyperparameters={
        "PatchTST": [
            {"distr_output": NormalOutput()},
            {"distr_output": QuantileOutput(quantiles=predictor.quantile_levels)},
        ]
    }
)

您可以通过定义 gluonts.torch.distributions.Output 的子类并将其作为 distr_output 提供给模型来为 GluonTS 模型定义自定义损失函数。

from gluonts.torch.distributions import Output

class MyCustomOutput(Output):
    # implement methods of gluonts.torch.distributions.Output
    ...

predictor.fit(train_data, hyperparameters={"PatchTST": {"distr_output": MyCustomOutput()}})

您可以在 GluonTS 代码库中找到 Output 实现的示例(例如,QuantileOutputNormalOutput)。