分类变量是可能影响预测的外部因素。这些变量取有限的、固定数量的可能值之一,并对观测数据进行分组。

例如,如果您正在预测零售商的每日产品需求,您可以从一个事件变量中受益,该变量可能告诉您在特定日期发生了什么样的事件,例如“无”、“体育”或“文化”事件。

要在 TimeGPT 中整合分类变量,您需要将时间序列数据中的每个点与相应的外部数据配对。

1. 导入包

首先,我们安装并导入所需的包并初始化 Nixtla 客户端。

import pandas as pd
import os

from nixtla import NixtlaClient
from datasetsforecast.m5 import M5
nixtla_client = NixtlaClient(
    # defaults to os.environ.get("NIXTLA_API_KEY")
    api_key = 'my_api_key_provided_by_nixtla'   
)

👍 使用 Azure AI 端点

要使用 Azure AI 端点,请记住也要设置 base_url 参数

nixtla_client = NixtlaClient(base_url="you azure ai endpoint", api_key="your api_key")

2. 加载 M5 数据

我们来看一个预测 M5 数据集 中产品销售的例子。M5 数据集包含美国 10 家零售店的每日产品需求(销售额)。

首先,我们使用 datasetsforecast 加载数据。这将返回

  • Y_df,包含每个唯一产品(unique_id 列)在每个时间戳(ds 列)的销售额(y 列)。
  • X_df,包含每个唯一产品(unique_id 列)在每个时间戳(ds 列)的额外相关信息。
Y_df, X_df, _ = M5.load(directory=os.getcwd())
Y_df['ds'] = pd.to_datetime(Y_df['ds'])
X_df['ds'] = pd.to_datetime(X_df['ds'])
Y_df.head(10)
unique_iddsy
0FOODS_1_001_CA_12011-01-293.0
1FOODS_1_001_CA_12011-01-300.0
2FOODS_1_001_CA_12011-01-310.0
3FOODS_1_001_CA_12011-02-011.0
4FOODS_1_001_CA_12011-02-024.0
5FOODS_1_001_CA_12011-02-032.0
6FOODS_1_001_CA_12011-02-040.0
7FOODS_1_001_CA_12011-02-052.0
8FOODS_1_001_CA_12011-02-060.0
9FOODS_1_001_CA_12011-02-070.0

对于此示例,我们将只保留 event_type_1 列中的额外相关信息。此列是一个分类变量,指示在某个日期是否发生了可能影响产品销售的重要事件。

X_df = X_df[['unique_id', 'ds', 'event_type_1']]

X_df.head(10)
unique_iddsevent_type_1
0FOODS_1_001_CA_12011-01-29nan
1FOODS_1_001_CA_12011-01-30nan
2FOODS_1_001_CA_12011-01-31nan
3FOODS_1_001_CA_12011-02-01nan
4FOODS_1_001_CA_12011-02-02nan
5FOODS_1_001_CA_12011-02-03nan
6FOODS_1_001_CA_12011-02-04nan
7FOODS_1_001_CA_12011-02-05nan
8FOODS_1_001_CA_12011-02-06体育
9FOODS_1_001_CA_12011-02-07nan

正如您所见,在 2011 年 2 月 6 日,有一个体育赛事。

3. 使用分类变量预测产品需求

我们将只预测单个产品的需求。我们选择一个由 FOODS_3_090_CA_3 标识的高销量食品产品。

product = 'FOODS_3_090_CA_3'
Y_df_product = Y_df.query('unique_id == @product')
X_df_product = X_df.query('unique_id == @product')

我们合并两个数据框以创建将在 TimeGPT 中使用的数据集。

df = Y_df_product.merge(X_df_product)

df.head(10)
unique_iddsyevent_type_1
0FOODS_3_090_CA_32011-01-29108.0nan
1FOODS_3_090_CA_32011-01-30132.0nan
2FOODS_3_090_CA_32011-01-31102.0nan
3FOODS_3_090_CA_32011-02-01120.0nan
4FOODS_3_090_CA_32011-02-02106.0nan
5FOODS_3_090_CA_32011-02-03123.0nan
6FOODS_3_090_CA_32011-02-04279.0nan
7FOODS_3_090_CA_32011-02-05175.0nan
8FOODS_3_090_CA_32011-02-06186.0体育
9FOODS_3_090_CA_32011-02-07120.0nan

为了在 TimeGPT 中使用分类变量,需要对变量进行数值编码。在本教程中,我们将使用独热编码

我们可以使用 pandas 内置的 get_dummies 功能对 event_type_1 列进行独热编码。对 event_type_1 变量进行独热编码后,我们可以将其添加到数据框中并删除原始列。

event_type_1_ohe = pd.get_dummies(df['event_type_1'], dtype=int)
df = pd.concat([df, event_type_1_ohe], axis=1)
df = df.drop(columns = 'event_type_1')

df.tail(10)
unique_iddsy文化国家宗教体育nan
1959FOODS_3_090_CA_32016-06-10140.000001
1960FOODS_3_090_CA_32016-06-11151.000001
1961FOODS_3_090_CA_32016-06-1287.000001
1962FOODS_3_090_CA_32016-06-1367.000001
1963FOODS_3_090_CA_32016-06-1450.000001
1964FOODS_3_090_CA_32016-06-1558.000001
1965FOODS_3_090_CA_32016-06-16116.000001
1966FOODS_3_090_CA_32016-06-17124.000001
1967FOODS_3_090_CA_32016-06-18167.000001
1968FOODS_3_090_CA_32016-06-19118.000010

正如您所见,我们现在添加了 5 列,每列都有一个二进制指标(10),指示当天是否存在文化国家宗教体育或无(nan)事件。例如,在 2016 年 6 月 19 日,有一个体育赛事。

接下来我们进行预测任务。我们将预测 2016 年 2 月的前 7 天。这包括 2016 年 2 月 7 日——第 50 届超级碗 举办的日期。此类大型全国性事件通常会影响零售产品的销售。

要在 TimeGPT 中使用编码后的分类变量,我们需要将它们作为未来值添加。因此,我们创建一个未来值数据框,其中包含 unique_id、时间戳 ds 和编码后的分类变量。

当然,我们删除了目标列,因为这通常是不可用的——这是我们寻求预测的数量!

future_ex_vars_df = df.drop(columns = ['y'])
future_ex_vars_df = future_ex_vars_df.query("ds >= '2016-02-01' & ds <= '2016-02-07'")

future_ex_vars_df.head(10)
unique_idds文化国家宗教体育nan
1829FOODS_3_090_CA_32016-02-0100001
1830FOODS_3_090_CA_32016-02-0200001
1831FOODS_3_090_CA_32016-02-0300001
1832FOODS_3_090_CA_32016-02-0400001
1833FOODS_3_090_CA_32016-02-0500001
1834FOODS_3_090_CA_32016-02-0600001
1835FOODS_3_090_CA_32016-02-0700010

接下来,我们将输入数据框限制为除这 7 个预测日之外的所有数据

df_train = df.query("ds < '2016-02-01'")

df_train.tail(10)
unique_iddsy文化国家宗教体育nan
1819FOODS_3_090_CA_32016-01-2294.000001
1820FOODS_3_090_CA_32016-01-23144.000001
1821FOODS_3_090_CA_32016-01-24146.000001
1822FOODS_3_090_CA_32016-01-2587.000001
1823FOODS_3_090_CA_32016-01-2673.000001
1824FOODS_3_090_CA_32016-01-2762.000001
1825FOODS_3_090_CA_32016-01-2864.000001
1826FOODS_3_090_CA_32016-01-29102.000001
1827FOODS_3_090_CA_32016-01-30113.000001
1828FOODS_3_090_CA_32016-01-3198.000001

我们首先调用 forecast 方法,包含分类变量。

timegpt_fcst_without_cat_vars_df = nixtla_client.forecast(df=df_train, h=7, level=[80, 90])
timegpt_fcst_without_cat_vars_df.head()
INFO:nixtla.nixtla_client:Validating inputs...
INFO:nixtla.nixtla_client:Preprocessing dataframes...
INFO:nixtla.nixtla_client:Inferred freq: D
INFO:nixtla.nixtla_client:Restricting input...
INFO:nixtla.nixtla_client:Calling Forecast Endpoint...
unique_iddsTimeGPTTimeGPT-lo-90TimeGPT-lo-80TimeGPT-hi-80TimeGPT-hi-90
0FOODS_3_090_CA_32016-02-0173.30409253.44904954.79507891.81310793.159136
1FOODS_3_090_CA_32016-02-0266.33551847.51066950.27413682.39689985.160367
2FOODS_3_090_CA_32016-02-0365.88163036.21861741.38889690.37436495.544643
3FOODS_3_090_CA_32016-02-0472.371864-26.68311525.097362119.646367171.426844
4FOODS_3_090_CA_32016-02-0595.141045-2.08488234.027078156.255011192.366971

📘 Azure AI 中可用的模型

如果您使用 Azure AI 端点,请务必设置 model="azureai"

nixtla_client.forecast(..., model="azureai")

对于公共 API,我们支持两个模型:timegpt-1timegpt-1-long-horizon

默认情况下使用 timegpt-1。关于何时以及如何使用 timegpt-1-long-horizon,请参阅本教程

我们绘制了预测结果和预测期前的最后 28 天数据

nixtla_client.plot(
    df[['unique_id', 'ds', 'y']].query("ds <= '2016-02-07'"), 
    timegpt_fcst_without_cat_vars_df, 
    max_insample_length=28, 
)

TimeGPT 已经提供了合理的预测,但似乎对 2016 年 2 月 6 日的峰值(超级碗前一天)有所低估。

我们再次调用 forecast 方法,这次是包含分类变量的。

timegpt_fcst_with_cat_vars_df = nixtla_client.forecast(df=df_train, X_df=future_ex_vars_df, h=7, level=[80, 90])
timegpt_fcst_with_cat_vars_df.head()
INFO:nixtla.nixtla_client:Validating inputs...
INFO:nixtla.nixtla_client:Preprocessing dataframes...
INFO:nixtla.nixtla_client:Inferred freq: D
INFO:nixtla.nixtla_client:Using the following exogenous variables: Cultural, National, Religious, Sporting, nan
INFO:nixtla.nixtla_client:Calling Forecast Endpoint...
unique_iddsTimeGPTTimeGPT-lo-90TimeGPT-lo-80TimeGPT-hi-80TimeGPT-hi-90
0FOODS_3_090_CA_32016-02-0170.661271-0.20437814.593348126.729194141.526919
1FOODS_3_090_CA_32016-02-0265.566941-20.39432611.654239119.479643151.528208
2FOODS_3_090_CA_32016-02-0368.510010-33.7137106.732952130.287069170.733731
3FOODS_3_090_CA_32016-02-0475.417710-40.9746494.751767146.083653191.810069
4FOODS_3_090_CA_32016-02-0597.340302-57.38536118.253812176.426792252.065965

📘 Azure AI 中可用的模型

如果您使用 Azure AI 端点,请务必设置 model="azureai"

nixtla_client.forecast(..., model="azureai")

对于公共 API,我们支持两个模型:timegpt-1timegpt-1-long-horizon

默认情况下使用 timegpt-1。关于何时以及如何使用 timegpt-1-long-horizon,请参阅本教程

我们绘制了预测结果和预测期前的最后 28 天数据

nixtla_client.plot(
    df[['unique_id', 'ds', 'y']].query("ds <= '2016-02-07'"), 
    timegpt_fcst_with_cat_vars_df, 
    max_insample_length=28, 
)

我们可以通过视觉验证,预测结果更接近实际观测值,这是在预测中包含分类变量的结果。

我们通过计算我们创建的预测的平均绝对误差来验证这一结论。

from utilsforecast.losses import mae
# Create target dataframe
df_target = df[['unique_id', 'ds', 'y']].query("ds >= '2016-02-01' & ds <= '2016-02-07'")

# Rename forecast columns
timegpt_fcst_without_cat_vars_df = timegpt_fcst_without_cat_vars_df.rename(columns={'TimeGPT': 'TimeGPT-without-cat-vars'})
timegpt_fcst_with_cat_vars_df = timegpt_fcst_with_cat_vars_df.rename(columns={'TimeGPT': 'TimeGPT-with-cat-vars'})

# Merge forecasts with target dataframe
df_target = df_target.merge(timegpt_fcst_without_cat_vars_df[['unique_id', 'ds', 'TimeGPT-without-cat-vars']])
df_target = df_target.merge(timegpt_fcst_with_cat_vars_df[['unique_id', 'ds', 'TimeGPT-with-cat-vars']])

# Compute errors
mean_absolute_errors = mae(df_target, ['TimeGPT-without-cat-vars', 'TimeGPT-with-cat-vars'])
mean_absolute_errors
unique_idTimeGPT-无分类变量TimeGPT-有分类变量
0FOODS_3_090_CA_324.28564920.028514

确实,我们发现使用包含分类变量的 TimeGPT 时,误差比不包含分类变量的 TimeGPT 低约 20%,这表明包含分类变量时性能更佳。