Skip to main content

Introduction

Pricing decisions significantly impact retail demand. TimeGPT makes it possible to forecast product demand while incorporating price as a key factor, enabling retailers to evaluate how different pricing scenarios might affect sales. This approach offers valuable insights for strategic pricing decisions. This tutorial demonstrates how to use TimeGPT for scenario analysis by forecasting demand under various pricing conditions. You’ll learn to incorporate price data into forecasts and compare different pricing strategies to understand their impact on consumer demand.

What You’ll Learn

  • How to forecast retail demand using price as an exogenous variable
  • How to run what-if scenarios with different pricing strategies
  • How to compare baseline, increased, and decreased price forecasts
  • How to interpret price sensitivity in demand forecasts

How to Forecast Sales with Pricing Scenarios

Open In Colab

Step 1: Import required packages

Import the packages needed for this tutorial and initialize your Nixtla client:
import pandas as pd
import os

from nixtla import NixtlaClient
Initialize the Nixtla client:
nixtla_client = NixtlaClient(
    api_key='my_api_key_provided_by_nixtla'
)

Step 2: Load the M5 dataset

Let’s see an example on predicting sales of products of the M5 dataset. The M5 dataset contains daily product demand (sales) for 10 retail stores in the US. First, we load the data using datasetsforecast. This returns:
  • Y_df, containing the sales (y column), for each unique product (unique_id column) at every timestamp (ds column).
  • X_df, containing additional relevant information for each unique product (unique_id column) at every timestamp (ds column).
from datasetsforecast.m5 import M5

Y_df, X_df, S_df = M5.load(directory=os.getcwd())
Y_df.head(10)
unique_iddsy
FOODS_1_001_CA_12011-01-293.0
FOODS_1_001_CA_12011-01-300.0
FOODS_1_001_CA_12011-01-310.0
FOODS_1_001_CA_12011-02-011.0
FOODS_1_001_CA_12011-02-024.0
FOODS_1_001_CA_12011-02-032.0
FOODS_1_001_CA_12011-02-040.0
FOODS_1_001_CA_12011-02-052.0
FOODS_1_001_CA_12011-02-060.0
FOODS_1_001_CA_12011-02-070.0
For this example, we will only keep the additional relevant information from the column sell_price. This column shows the selling price of the product, and we expect demand to fluctuate given a different selling price.
X_df = X_df[['unique_id', 'ds', 'sell_price']]
X_df.head(10)
unique_iddssell_price
FOODS_1_001_CA_12011-01-292.0
FOODS_1_001_CA_12011-01-302.0
FOODS_1_001_CA_12011-01-312.0
FOODS_1_001_CA_12011-02-012.0
FOODS_1_001_CA_12011-02-022.0
FOODS_1_001_CA_12011-02-032.0
FOODS_1_001_CA_12011-02-042.0
FOODS_1_001_CA_12011-02-052.0
FOODS_1_001_CA_12011-02-062.0
FOODS_1_001_CA_12011-02-072.0

Step 3: Forecast demand using price as an exogenous variable

In this example, we forecast for a single product (FOODS_1_129_) across all 10 stores. This product exhibits frequent price changes, making it ideal for modeling price effects on demand. Learn more about using exogenous variables in TimeGPT.
products = [
    'FOODS_1_129_CA_1', 'FOODS_1_129_CA_2', 'FOODS_1_129_CA_3', 'FOODS_1_129_CA_4',
    'FOODS_1_129_TX_1', 'FOODS_1_129_TX_2', 'FOODS_1_129_TX_3',
    'FOODS_1_129_WI_1', 'FOODS_1_129_WI_2', 'FOODS_1_129_WI_3'
]

Y_df_product = Y_df.query('unique_id in @products')
X_df_product = X_df.query('unique_id in @products')
Merge the sales (y) and price (sell_price) data into one DataFrame:
df = Y_df_product.merge(X_df_product)
df.head(10)
unique_iddsysell_price
FOODS_1_129_CA_12011-02-011.06.22
FOODS_1_129_CA_12011-02-020.06.22
FOODS_1_129_CA_12011-02-030.06.22
FOODS_1_129_CA_12011-02-040.06.22
FOODS_1_129_CA_12011-02-051.06.22
FOODS_1_129_CA_12011-02-060.06.22
FOODS_1_129_CA_12011-02-070.06.22
FOODS_1_129_CA_12011-02-080.06.22
FOODS_1_129_CA_12011-02-090.06.22
FOODS_1_129_CA_12011-02-103.06.22
Let’s investigate how the demand, our target y, of these products has evolved in the last year of data.
nixtla_client.plot(df, unique_ids=products, max_insample_length=365)
Historical retail demand showing intermittent sales patterns across 10 stores for FOODS_1_129 product

Historical retail demand showing intermittent sales patterns across 10 stores

We see that in the California stores (with a CA_ suffix), the product has sold intermittently, whereas in the other regions (TX and WY) sales where less intermittent. Note that the plot only shows 8 (out of 10) stores. Next, we look at the sell_price of these products across the entire data available.
nixtla_client.plot(df, unique_ids=products, target_col='sell_price')
Historical pricing trends showing approximately 20 price changes from 2011 to 2016 for retail products

Historical pricing trends showing price changes over 5 years for retail products

We find that there have been relatively few price changes (about 20 in total) over the period 2011 to 2016. Let’s turn to our forecasting task. We will forecast the last 28 days in the dataset. To use the sell_price exogenous variable in TimeGPT, we have to add it as future values. Therefore, we create a future values dataframe, that contains the unique_id, the timestamp ds, and sell_price.
future_ex_vars_df = df.drop(columns = ['y'])
future_ex_vars_df = future_ex_vars_df.query("ds >= '2016-05-23'")

future_ex_vars_df.head(10)
unique_iddssell_price
FOODS_1_129_CA_12016-05-235.74
FOODS_1_129_CA_12016-05-245.74
FOODS_1_129_CA_12016-05-255.74
FOODS_1_129_CA_12016-05-265.74
FOODS_1_129_CA_12016-05-275.74
FOODS_1_129_CA_12016-05-285.74
FOODS_1_129_CA_12016-05-295.74
FOODS_1_129_CA_12016-05-305.74
FOODS_1_129_CA_12016-05-315.74
FOODS_1_129_CA_12016-06-015.74
Next, we limit our input dataframe to all but the 28 forecast days:
df_train = df.query("ds < '2016-05-23'")

df_train.tail(10)
unique_iddsysell_price
FOODS_1_129_WI_32016-05-133.07.23
FOODS_1_129_WI_32016-05-141.07.23
FOODS_1_129_WI_32016-05-152.07.23
FOODS_1_129_WI_32016-05-163.07.23
FOODS_1_129_WI_32016-05-171.07.23
FOODS_1_129_WI_32016-05-182.07.23
FOODS_1_129_WI_32016-05-193.07.23
FOODS_1_129_WI_32016-05-201.07.23
FOODS_1_129_WI_32016-05-210.07.23
FOODS_1_129_WI_32016-05-220.07.23
Now, we can generate forecasts using TimeGPT (28 days ahead):
timegpt_fcst_df = nixtla_client.forecast(
    df=df_train,
    X_df=future_ex_vars_df,
    h=28
)
timegpt_fcst_df.head()
unique_iddsTimeGPT
FOODS_1_129_CA_12016-05-230.875594
FOODS_1_129_CA_12016-05-240.777731
FOODS_1_129_CA_12016-05-250.786871
FOODS_1_129_CA_12016-05-260.828223
FOODS_1_129_CA_12016-05-270.791228
We plot the forecast, the actuals and the last 28 days before the forecast period:
nixtla_client.plot(
    df[['unique_id', 'ds', 'y']],
    timegpt_fcst_df,
    max_insample_length=56
)
TimeGPT baseline forecast showing actual demand and 28-day ahead predictions for retail products

TimeGPT baseline forecast with 28-day ahead predictions for retail demand

Step 4: What-If Scenario Forecasting with Price Changes

What happens when we change the price of the products in our forecast period? Let’s see how our forecast changes when we increase and decrease the sell_price by 5%.
price_change = 0.05

future_ex_vars_df_plus = future_ex_vars_df.copy()
future_ex_vars_df_plus["sell_price"] *= (1 + price_change)

future_ex_vars_df_minus = future_ex_vars_df.copy()
future_ex_vars_df_minus["sell_price"] *= (1 - price_change)
Let’s create a new set of forecasts with TimeGPT.
timegpt_fcst_df_plus = nixtla_client.forecast(df_train, future_ex_vars_df_plus, h=28)
timegpt_fcst_df_minus = nixtla_client.forecast(df_train, future_ex_vars_df_minus, h=28)
Rename and combine the scenario forecasts:
timegpt_fcst_df_plus = timegpt_fcst_df_plus.rename(columns={'TimeGPT':f'TimeGPT-sell_price_plus_{price_change * 100:.0f}%'})
timegpt_fcst_df_minus = timegpt_fcst_df_minus.rename(columns={'TimeGPT':f'TimeGPT-sell_price_minus_{price_change * 100:.0f}%'})

timegpt_fcst_df = pd.concat([timegpt_fcst_df, 
                             timegpt_fcst_df_plus[f'TimeGPT-sell_price_plus_{price_change * 100:.0f}%'], 
                             timegpt_fcst_df_minus[f'TimeGPT-sell_price_minus_{price_change * 100:.0f}%']], axis=1)

timegpt_fcst_df.head(10)
unique_iddsTimeGPTTimeGPT-sell_price_plus_5%TimeGPT-sell_price_minus_5%
FOODS_1_129_CA_12016-05-230.8755940.8470061.370029
FOODS_1_129_CA_12016-05-240.7777310.7491421.272166
FOODS_1_129_CA_12016-05-250.7868710.7582831.281306
FOODS_1_129_CA_12016-05-260.8282230.7996351.322658
FOODS_1_129_CA_12016-05-270.7912280.7626401.285663
FOODS_1_129_CA_12016-05-280.8191330.7905451.313568
FOODS_1_129_CA_12016-05-290.8399920.8114041.334427
FOODS_1_129_CA_12016-05-300.8430700.8144811.337505
FOODS_1_129_CA_12016-05-310.8330890.8045001.327524
FOODS_1_129_CA_12016-06-010.8550320.8264431.349467
As expected, demand increases when we reduce the price and decreases when we increase it. A cheaper product leads to higher sales and vice versa. Finally, let’s plot the forecasts for our different pricing scenarios, showing how TimeGPT forecasts a different demand when the price of a set of products is changed.
nixtla_client.plot(
    df[['unique_id', 'ds', 'y']],
    timegpt_fcst_df,
    max_insample_length=56
)
What-if scenario comparison: baseline, +5% price increase, and -5% price decrease demand forecasts

What-if scenario comparison showing demand forecasts under different pricing strategies

In the graphs we can see that for specific products for certain periods the discount increases expected demand, while during other periods and for other products, price change has a smaller effect on total demand.

Conclusion

What-if forecasting with TimeGPT enables data-driven pricing decisions by:
  • Modeling demand sensitivity to price changes
  • Comparing multiple pricing scenarios simultaneously
  • Incorporating exogenous variables for realistic predictions
This scenario analysis approach helps retailers optimize pricing strategies and maximize revenue while understanding demand elasticity.

Next Steps

Important Considerations

  • This method assumes that historical demand and price behaviour is predictive of future demand, and omits other factors affecting demand. To include these other factors, use additional exogenous variables that provide the model with more context about the factors influencing demand.
  • This method is sensitive to unmodelled events that affect the demand, such as sudden market shifts. To include those, use additional exogenous variables indicating such sudden shifts if they have been observed in the past too.