Exogenous variables

Exogenous variables or external factors are crucial in time series forecasting as they provide additional information that might influence the prediction. These variables could include holiday markers, marketing spending, weather data, or any other external data that correlate with the time series data you are forecasting. For example, if you’re forecasting ice cream sales, temperature data could serve as a useful exogenous variable. On hotter days, ice cream sales may increase. To incorporate exogenous variables in TimeGPT, you’ll need to pair each point in your time series data with the corresponding external data.

1. Import packages

First, we import the required packages and initialize the Nixtla client.


import pandas as pd
from nixtla import NixtlaClient


nixtla_client = NixtlaClient(
    # defaults to os.environ.get("NIXTLA_API_KEY")
    api_key = 'my_api_key_provided_by_nixtla'
)

2. Load data

Let’s see an example on predicting day-ahead electricity prices. The following dataset contains the hourly electricity price (y column) for five markets in Europe and US, identified by the unique_id column. The columns from Exogenous1 to day_6 are exogenous variables that TimeGPT will use to predict the prices.


df = pd.read_csv('https://raw.githubusercontent.com/Nixtla/transfer-learning-time-series/main/datasets/electricity-short-with-ex-vars.csv')
df.head()

unique_iddsyExogenous1Exogenous2day_0day_1day_2day_3day_4day_5day_6
0BE2016-10-22 00:00:0070.0049593.057253.00.00.00.00.00.01.00.0
1BE2016-10-22 01:00:0037.1046073.051887.00.00.00.00.00.01.00.0
2BE2016-10-22 02:00:0037.1044927.051896.00.00.00.00.00.01.00.0
3BE2016-10-22 03:00:0044.7544483.048428.00.00.00.00.00.01.00.0
4BE2016-10-22 04:00:0037.1044338.046721.00.00.00.00.00.01.00.0
## 3. Forecasting electricity prices using exogenous variables To produce forecasts we also have to add the future values of the exogenous variables. Let’s read this dataset. In this case, we want to predict 24 steps ahead, therefore each `unique_id` will have 24 observations. > **Important** > > If you want to use exogenous variables when forecasting with TimeGPT, > you need to have the future values of those exogenous variables too.

future_ex_vars_df = pd.read_csv('https://raw.githubusercontent.com/Nixtla/transfer-learning-time-series/main/datasets/electricity-short-future-ex-vars.csv')
future_ex_vars_df.head()

unique_iddsExogenous1Exogenous2day_0day_1day_2day_3day_4day_5day_6
0BE2016-12-31 00:00:0064108.070318.00.00.00.00.00.01.00.0
1BE2016-12-31 01:00:0062492.067898.00.00.00.00.00.01.00.0
2BE2016-12-31 02:00:0061571.068379.00.00.00.00.00.01.00.0
3BE2016-12-31 03:00:0060381.064972.00.00.00.00.00.01.00.0
4BE2016-12-31 04:00:0060298.062900.00.00.00.00.00.01.00.0
Let’s call the `forecast` method, adding this information:

timegpt_fcst_ex_vars_df = nixtla_client.forecast(df=df, X_df=future_ex_vars_df, h=24, level=[80, 90])
timegpt_fcst_ex_vars_df.head()

INFO:nixtla.nixtla_client:Validating inputs...
INFO:nixtla.nixtla_client:Preprocessing dataframes...
INFO:nixtla.nixtla_client:Inferred freq: H
INFO:nixtla.nixtla_client:Using the following exogenous variables: Exogenous1, Exogenous2, day_0, day_1, day_2, day_3, day_4, day_5, day_6
INFO:nixtla.nixtla_client:Calling Forecast Endpoint...
unique_iddsTimeGPTTimeGPT-lo-90TimeGPT-lo-80TimeGPT-hi-80TimeGPT-hi-90
0BE2016-12-31 00:00:0076.95290167.40045171.95329981.95250386.505352
1BE2016-12-31 01:00:0042.96375831.93901136.31401549.61350153.988505
2BE2016-12-31 02:00:0042.52631630.15936134.81385550.23877754.893270
3BE2016-12-31 03:00:0036.96086724.80058830.26697943.65475649.121146
4BE2016-12-31 04:00:0037.10427523.46180528.79644145.41210950.746745

nixtla_client.plot(
    df[['unique_id', 'ds', 'y']], 
    timegpt_fcst_ex_vars_df, 
    max_insample_length=365, 
    level=[80, 90], 
)


We can also show the importance of the features.


nixtla_client.weights_x.plot.barh(x='features', y='weights')


This plot shows that Exogenous1 and Exogenous2 are the most important for this forecasting task, as they have the largest weight.

4. How to generate future exogenous variables?

In the example above, we just loaded the future exogenous variables. Often, these are not available because these variables are unknown. Hence, we need to forecast these too.

Important

If you would only include historic exogenous variables in your model,
you would be implicitly making assumptions about the future of these
exogenous variables in your forecast. That’s why TimeGPT requires you
to explicitly incorporate the future of these exogenous variables too,
so that you make your assumptions about these variables explicit.
Below, we’ll show you how we can also forecast Exogenous1 and Exogenous2 separately, so that you can generate the future exogenous variables in case they are not available.


# We read the data and create separate dataframes for the historic exogenous that we want to forecast separately.
df = pd.read_csv('https://raw.githubusercontent.com/Nixtla/transfer-learning-time-series/main/datasets/electricity-short-with-ex-vars.csv')
df_exog1 = df[['unique_id', 'ds', 'Exogenous1']]
df_exog2 = df[['unique_id', 'ds', 'Exogenous2']]

Next, we can use TimeGPT to forecast Exogenous1 and Exogenous2. In this case, we assume these quantities can be separately forecast.


timegpt_fcst_ex1 = nixtla_client.forecast(df=df_exog1, h=24, target_col='Exogenous1')
timegpt_fcst_ex2 = nixtla_client.forecast(df=df_exog2, h=24, target_col='Exogenous2')

INFO:nixtla.nixtla_client:Validating inputs...
INFO:nixtla.nixtla_client:Preprocessing dataframes...
INFO:nixtla.nixtla_client:Inferred freq: H
INFO:nixtla.nixtla_client:Calling Forecast Endpoint...
INFO:nixtla.nixtla_client:Validating inputs...
INFO:nixtla.nixtla_client:Preprocessing dataframes...
INFO:nixtla.nixtla_client:Inferred freq: H
INFO:nixtla.nixtla_client:Calling Forecast Endpoint...

We can now start creating X_df, which contains the future exogenous variables.


timegpt_fcst_ex1 = timegpt_fcst_ex1.rename(columns={'TimeGPT':'Exogenous1'})
timegpt_fcst_ex2 = timegpt_fcst_ex2.rename(columns={'TimeGPT':'Exogenous2'})


X_df = timegpt_fcst_ex1.merge(timegpt_fcst_ex2)

Next, we also need to add the day_0 to day_6 future exogenous variables. These are easy: this is just the weekday, which we can extract from the ds column.


# We have 7 days, for each day a separate column denoting 1/0
for i in range(7):
    X_df[f'day_{i}'] = 1 * (pd.to_datetime(X_df['ds']).dt.weekday == i)
    

We have now created X_df, let’s investigate it:


X_df.head(10)

unique_iddsExogenous1Exogenous2day_0day_1day_2day_3day_4day_5day_6
0BE2016-12-31 00:00:0066059.90625071178.5390620000010
1BE2016-12-31 01:00:0063927.19531268056.2890620000010
2BE2016-12-31 02:00:0062346.26171966209.7500000000010
3BE2016-12-31 03:00:0061194.63281263871.6835940000010
4BE2016-12-31 04:00:0060135.03125062013.0429690000010
5BE2016-12-31 05:00:0060664.35937562363.7382810000010
6BE2016-12-31 06:00:0061965.67187564697.6054690000010
7BE2016-12-31 07:00:0063863.85156267495.2031250000010
8BE2016-12-31 08:00:0065584.68750070831.9218750000010
9BE2016-12-31 09:00:0066338.75000071927.8750000000010
Let’s compare it to our pre-loaded version:

future_ex_vars_df.head(10)

unique_iddsExogenous1Exogenous2day_0day_1day_2day_3day_4day_5day_6
0BE2016-12-31 00:00:0064108.070318.00.00.00.00.00.01.00.0
1BE2016-12-31 01:00:0062492.067898.00.00.00.00.00.01.00.0
2BE2016-12-31 02:00:0061571.068379.00.00.00.00.00.01.00.0
3BE2016-12-31 03:00:0060381.064972.00.00.00.00.00.01.00.0
4BE2016-12-31 04:00:0060298.062900.00.00.00.00.00.01.00.0
5BE2016-12-31 05:00:0060339.062364.00.00.00.00.00.01.00.0
6BE2016-12-31 06:00:0062576.064242.00.00.00.00.00.01.00.0
7BE2016-12-31 07:00:0063732.065884.00.00.00.00.00.01.00.0
8BE2016-12-31 08:00:0066235.068217.00.00.00.00.00.01.00.0
9BE2016-12-31 09:00:0066801.069921.00.00.00.00.00.01.00.0
As you can see, the values for `Exogenous1` and `Exogenous2` are slightly different, which makes sense because we’ve made a forecast of these values with TimeGPT. Let’s create a new forecast of our electricity prices with TimeGPT using our new `X_df`:

timegpt_fcst_ex_vars_df_new = nixtla_client.forecast(df=df, X_df=X_df, h=24, level=[80, 90])
timegpt_fcst_ex_vars_df_new.head()

INFO:nixtla.nixtla_client:Validating inputs...
INFO:nixtla.nixtla_client:Preprocessing dataframes...
INFO:nixtla.nixtla_client:Inferred freq: H
INFO:nixtla.nixtla_client:Using the following exogenous variables: Exogenous1, Exogenous2, day_0, day_1, day_2, day_3, day_4, day_5, day_6
INFO:nixtla.nixtla_client:Calling Forecast Endpoint...
unique_iddsTimeGPTTimeGPT-lo-90TimeGPT-lo-80TimeGPT-hi-80TimeGPT-hi-90
0BE2016-12-31 00:00:0049.93564640.38319644.93604454.93524859.488097
1BE2016-12-31 01:00:0035.46344624.43869928.81370342.11318846.488192
2BE2016-12-31 02:00:0040.03736227.67040732.32490147.74982352.404316
3BE2016-12-31 03:00:0037.69335525.53307630.99946744.38724449.853634
4BE2016-12-31 04:00:0037.97248424.33001429.66465046.28031851.614954
Let’s create a combined dataframe with the two forecasts and plot the values to compare the forecasts.

timegpt_fcst_ex_vars_df = timegpt_fcst_ex_vars_df.rename(columns={'TimeGPT':'TimeGPT-provided_exogenous'})
timegpt_fcst_ex_vars_df_new = timegpt_fcst_ex_vars_df_new.rename(columns={'TimeGPT':'TimeGPT-forecasted_exogenous'})

forecasts = timegpt_fcst_ex_vars_df[['unique_id', 'ds', 'TimeGPT-provided_exogenous']].merge(timegpt_fcst_ex_vars_df_new[['unique_id', 'ds', 'TimeGPT-forecasted_exogenous']])


nixtla_client.plot(
    df[['unique_id', 'ds', 'y']], 
    forecasts, 
    max_insample_length=365, 
)


As you can see, we obtain a slightly different forecast if we use our forecasted exogenous variables.