!pip install -Uqq nixtla datasetsforecast分类变量
from nixtla.utils import in_colabIN_COLAB = in_colab()if not IN_COLAB:
from nixtla.utils import colab_badge
from dotenv import load_dotenv分类变量是可能影响预测的外部因素。这些变量取有限个固定值,并对观察值进行分组。
例如,如果你正在为一个零售商预测每日产品需求,你可以利用一个事件变量,它可以告诉你某天发生了什么类型的事件,例如’无’、‘体育’或’文化’。
要在TimeGPT中结合分类变量,你需要将时间序列数据中的每个点与相应的外部数据配对。
1. 导入包
首先,我们安装并导入所需的包,并初始化 Nixtla 客户端。
import pandas as pd
import os
from nixtla import NixtlaClient
from datasetsforecast.m5 import M5nixtla_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="你的 Azure AI 终端", api_key="你的 api_key")
if not IN_COLAB:
nixtla_client = NixtlaClient()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_id | ds | y | |
|---|---|---|---|
| 0 | FOODS_1_001_CA_1 | 2011-01-29 | 3.0 |
| 1 | FOODS_1_001_CA_1 | 2011-01-30 | 0.0 |
| 2 | FOODS_1_001_CA_1 | 2011-01-31 | 0.0 |
| 3 | FOODS_1_001_CA_1 | 2011-02-01 | 1.0 |
| 4 | FOODS_1_001_CA_1 | 2011-02-02 | 4.0 |
| 5 | FOODS_1_001_CA_1 | 2011-02-03 | 2.0 |
| 6 | FOODS_1_001_CA_1 | 2011-02-04 | 0.0 |
| 7 | FOODS_1_001_CA_1 | 2011-02-05 | 2.0 |
| 8 | FOODS_1_001_CA_1 | 2011-02-06 | 0.0 |
| 9 | FOODS_1_001_CA_1 | 2011-02-07 | 0.0 |
在这个例子中,我们将只保留来自列 event_type_1 的额外相关信息。该列是一个_类别变量_,指示某一日期是否发生可能影响产品销售的重要事件。
X_df = X_df[['unique_id', 'ds', 'event_type_1']]
X_df.head(10)| unique_id | ds | event_type_1 | |
|---|---|---|---|
| 0 | FOODS_1_001_CA_1 | 2011-01-29 | nan |
| 1 | FOODS_1_001_CA_1 | 2011-01-30 | nan |
| 2 | FOODS_1_001_CA_1 | 2011-01-31 | nan |
| 3 | FOODS_1_001_CA_1 | 2011-02-01 | nan |
| 4 | FOODS_1_001_CA_1 | 2011-02-02 | nan |
| 5 | FOODS_1_001_CA_1 | 2011-02-03 | nan |
| 6 | FOODS_1_001_CA_1 | 2011-02-04 | nan |
| 7 | FOODS_1_001_CA_1 | 2011-02-05 | nan |
| 8 | FOODS_1_001_CA_1 | 2011-02-06 | Sporting |
| 9 | FOODS_1_001_CA_1 | 2011-02-07 | nan |
正如您所见,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_id | ds | y | event_type_1 | |
|---|---|---|---|---|
| 0 | FOODS_3_090_CA_3 | 2011-01-29 | 108.0 | nan |
| 1 | FOODS_3_090_CA_3 | 2011-01-30 | 132.0 | nan |
| 2 | FOODS_3_090_CA_3 | 2011-01-31 | 102.0 | nan |
| 3 | FOODS_3_090_CA_3 | 2011-02-01 | 120.0 | nan |
| 4 | FOODS_3_090_CA_3 | 2011-02-02 | 106.0 | nan |
| 5 | FOODS_3_090_CA_3 | 2011-02-03 | 123.0 | nan |
| 6 | FOODS_3_090_CA_3 | 2011-02-04 | 279.0 | nan |
| 7 | FOODS_3_090_CA_3 | 2011-02-05 | 175.0 | nan |
| 8 | FOODS_3_090_CA_3 | 2011-02-06 | 186.0 | Sporting |
| 9 | FOODS_3_090_CA_3 | 2011-02-07 | 120.0 | nan |
if not IN_COLAB:
df = pd.read_parquet("../../assets/M5_categorical_variables_example.parquet")为了在 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_id | ds | y | Cultural | National | Religious | Sporting | nan | |
|---|---|---|---|---|---|---|---|---|
| 1959 | FOODS_3_090_CA_3 | 2016-06-10 | 140.0 | 0 | 0 | 0 | 0 | 1 |
| 1960 | FOODS_3_090_CA_3 | 2016-06-11 | 151.0 | 0 | 0 | 0 | 0 | 1 |
| 1961 | FOODS_3_090_CA_3 | 2016-06-12 | 87.0 | 0 | 0 | 0 | 0 | 1 |
| 1962 | FOODS_3_090_CA_3 | 2016-06-13 | 67.0 | 0 | 0 | 0 | 0 | 1 |
| 1963 | FOODS_3_090_CA_3 | 2016-06-14 | 50.0 | 0 | 0 | 0 | 0 | 1 |
| 1964 | FOODS_3_090_CA_3 | 2016-06-15 | 58.0 | 0 | 0 | 0 | 0 | 1 |
| 1965 | FOODS_3_090_CA_3 | 2016-06-16 | 116.0 | 0 | 0 | 0 | 0 | 1 |
| 1966 | FOODS_3_090_CA_3 | 2016-06-17 | 124.0 | 0 | 0 | 0 | 0 | 1 |
| 1967 | FOODS_3_090_CA_3 | 2016-06-18 | 167.0 | 0 | 0 | 0 | 0 | 1 |
| 1968 | FOODS_3_090_CA_3 | 2016-06-19 | 118.0 | 0 | 0 | 0 | 1 | 0 |
正如您所见,我们现在添加了5列,每列都有一个二元指示符(1或0),指示在特定日期是否有文化、国家、宗教、体育事件或没有事件(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_id | ds | Cultural | National | Religious | Sporting | nan | |
|---|---|---|---|---|---|---|---|
| 1829 | FOODS_3_090_CA_3 | 2016-02-01 | 0 | 0 | 0 | 0 | 1 |
| 1830 | FOODS_3_090_CA_3 | 2016-02-02 | 0 | 0 | 0 | 0 | 1 |
| 1831 | FOODS_3_090_CA_3 | 2016-02-03 | 0 | 0 | 0 | 0 | 1 |
| 1832 | FOODS_3_090_CA_3 | 2016-02-04 | 0 | 0 | 0 | 0 | 1 |
| 1833 | FOODS_3_090_CA_3 | 2016-02-05 | 0 | 0 | 0 | 0 | 1 |
| 1834 | FOODS_3_090_CA_3 | 2016-02-06 | 0 | 0 | 0 | 0 | 1 |
| 1835 | FOODS_3_090_CA_3 | 2016-02-07 | 0 | 0 | 0 | 1 | 0 |
接下来,我们将输入数据框限制为除7天预测日之外的所有数据:
df_train = df.query("ds < '2016-02-01'")
df_train.tail(10)| unique_id | ds | y | Cultural | National | Religious | Sporting | nan | |
|---|---|---|---|---|---|---|---|---|
| 1819 | FOODS_3_090_CA_3 | 2016-01-22 | 94.0 | 0 | 0 | 0 | 0 | 1 |
| 1820 | FOODS_3_090_CA_3 | 2016-01-23 | 144.0 | 0 | 0 | 0 | 0 | 1 |
| 1821 | FOODS_3_090_CA_3 | 2016-01-24 | 146.0 | 0 | 0 | 0 | 0 | 1 |
| 1822 | FOODS_3_090_CA_3 | 2016-01-25 | 87.0 | 0 | 0 | 0 | 0 | 1 |
| 1823 | FOODS_3_090_CA_3 | 2016-01-26 | 73.0 | 0 | 0 | 0 | 0 | 1 |
| 1824 | FOODS_3_090_CA_3 | 2016-01-27 | 62.0 | 0 | 0 | 0 | 0 | 1 |
| 1825 | FOODS_3_090_CA_3 | 2016-01-28 | 64.0 | 0 | 0 | 0 | 0 | 1 |
| 1826 | FOODS_3_090_CA_3 | 2016-01-29 | 102.0 | 0 | 0 | 0 | 0 | 1 |
| 1827 | FOODS_3_090_CA_3 | 2016-01-30 | 113.0 | 0 | 0 | 0 | 0 | 1 |
| 1828 | FOODS_3_090_CA_3 | 2016-01-31 | 98.0 | 0 | 0 | 0 | 0 | 1 |
让我们调用 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_id | ds | TimeGPT | TimeGPT-lo-90 | TimeGPT-lo-80 | TimeGPT-hi-80 | TimeGPT-hi-90 | |
|---|---|---|---|---|---|---|---|
| 0 | FOODS_3_090_CA_3 | 2016-02-01 | 73.304092 | 53.449049 | 54.795078 | 91.813107 | 93.159136 |
| 1 | FOODS_3_090_CA_3 | 2016-02-02 | 66.335518 | 47.510669 | 50.274136 | 82.396899 | 85.160367 |
| 2 | FOODS_3_090_CA_3 | 2016-02-03 | 65.881630 | 36.218617 | 41.388896 | 90.374364 | 95.544643 |
| 3 | FOODS_3_090_CA_3 | 2016-02-04 | 72.371864 | -26.683115 | 25.097362 | 119.646367 | 171.426844 |
| 4 | FOODS_3_090_CA_3 | 2016-02-05 | 95.141045 | -2.084882 | 34.027078 | 156.255011 | 192.366971 |
📘 Azure AI中的可用模型
如果您正在使用Azure AI端点,请确保设置
model="azureai":
nixtla_client.forecast(..., model="azureai")对于公共API,我们支持两种模型:
timegpt-1和timegpt-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_id | ds | TimeGPT | TimeGPT-lo-90 | TimeGPT-lo-80 | TimeGPT-hi-80 | TimeGPT-hi-90 | |
|---|---|---|---|---|---|---|---|
| 0 | FOODS_3_090_CA_3 | 2016-02-01 | 70.661271 | -0.204378 | 14.593348 | 126.729194 | 141.526919 |
| 1 | FOODS_3_090_CA_3 | 2016-02-02 | 65.566941 | -20.394326 | 11.654239 | 119.479643 | 151.528208 |
| 2 | FOODS_3_090_CA_3 | 2016-02-03 | 68.510010 | -33.713710 | 6.732952 | 130.287069 | 170.733731 |
| 3 | FOODS_3_090_CA_3 | 2016-02-04 | 75.417710 | -40.974649 | 4.751767 | 146.083653 | 191.810069 |
| 4 | FOODS_3_090_CA_3 | 2016-02-05 | 97.340302 | -57.385361 | 18.253812 | 176.426792 | 252.065965 |
📘 Azure AI 中可用的模型
如果您正在使用 Azure AI 端点,请确保设置
model="azureai":
nixtla_client.forecast(..., model="azureai")对于公共 API,我们支持两个模型:
timegpt-1和timegpt-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# 创建目标数据框
df_target = df[['unique_id', 'ds', 'y']].query("ds >= '2016-02-01' & ds <= '2016-02-07'")
# 重命名预测列
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'})
# 将预测结果与目标数据框合并
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']])
# 计算错误
mean_absolute_errors = mae(df_target, ['TimeGPT-without-cat-vars', 'TimeGPT-with-cat-vars'])mean_absolute_errors| unique_id | TimeGPT-without-cat-vars | TimeGPT-with-cat-vars | |
|---|---|---|---|
| 0 | FOODS_3_090_CA_3 | 24.285649 | 20.028514 |
实际上,我们发现使用TimeGPT时,包含分类变量的错误率比不包含分类变量时低约20%,这表明我们在包含分类变量时表现更好。
Give us a ⭐ on Github