Create a Demand Forecast Model

This tutorial will walk you through how to create a demand forecast model

πŸ“˜

Tutorial Overview

In this tutorial we will explain how to create and deploy a Network of Time Series (NoTS) that generates 7-day demand forecasts based on user-specified historical demand data. The resulting forecast will be generated every hour on an ongoing basis.

Create your NoTS

For this tutorial you will leverage the client library to create your NoTS. The NoTS that you'll create will use an XGBoost model with time-based and weather-based features to forecast demand data. For the weather data we are using a Time Series Recipe from The Weather Company. In this tutorial we are using weather data for METAR station KSFO, which corresponds to the SFO Airport. Click here for more information on the available METAR stations.

🚧

Historical Demand Data

In this tutorial we are using randomly generated data for the historical demand data. Note that you should replace this with your own historical demand data.

Client Library

To create the NoTS in the client library, you can use the following code.

import myst
import numpy as np
from myst.connectors.model_connectors import xgboost
from myst.connectors.source_connectors import time_trends
from myst.recipes.time_series_recipes import the_weather_company

myst.authenticate()

# Create a new project.
project = myst.Project.create(title="My Project")

# Create an hour of day, day of week, and month of year time series from a time trends source.
time_trends_source = project.create_source(
    title="Time Trends",
    connector=time_trends.TimeTrends(
        sample_period=myst.TimeDelta("PT1H"),
        time_zone="UTC",
        fields=[
            time_trends.Field.HOUR_OF_DAY,
            time_trends.Field.DAY_OF_WEEK,
            time_trends.Field.DAY_OF_YEAR,
        ],
    ),
)
hour_of_day_time_series = time_trends_source.create_time_series(
    title="Hour of Day",
    sample_period=myst.TimeDelta("PT1H"),
    label_indexer=time_trends.Field.HOUR_OF_DAY,
)
day_of_week_time_series = time_trends_source.create_time_series(
    title="Day of Week",
    sample_period=myst.TimeDelta("PT1H"),
    label_indexer=time_trends.Field.DAY_OF_WEEK,
)
day_of_year_time_series = time_trends_source.create_time_series(
    title="Day of Year",
    sample_period=myst.TimeDelta("PT1H"),
    label_indexer=time_trends.Field.DAY_OF_YEAR,
)

# Create a temperature and humidity time series using a The Weather Company recipe.
temperature_time_series = project.create_time_series_from_recipe(
    recipe=the_weather_company.TheWeatherCompany(
        metar_station=the_weather_company.MetarStation.KSFO,
        field=the_weather_company.Field.TEMPERATURE,
    )
)
humidity_time_series = project.create_time_series_from_recipe(
    recipe=the_weather_company.TheWeatherCompany(
        metar_station=the_weather_company.MetarStation.KSFO,
        field=the_weather_company.Field.RELATIVE_HUMIDITY,
    )
)

# Create a target time series and insert random data.
# TODO: Replace this with your historical demand data.
target_time_series = project.create_time_series(
    title="Historical Demand", sample_period=myst.TimeDelta("PT1H")
)
target_time_series.insert_time_array(
    time_array=myst.TimeArray(
        sample_period=myst.TimeDelta("PT1H"),
        start_time=myst.Time("2022-01-01T00:00:00Z"),
        end_time=myst.Time("2022-02-01T00:00:00Z"),
        as_of_time=myst.Time("2022-02-14T00:00:00Z"),
        values=np.random.random(31 * 24),
    )
)

# Create an XGBoost model.
model = project.create_model(
    title="Demand Model", 
    connector=xgboost.XGBoost(num_boost_round=100, max_depth=3, learning_rate=0.1),
)

# Add the time series as inputs to the model.
for time_series in [
    hour_of_day_time_series,
    day_of_week_time_series,
    day_of_year_time_series,
    temperature_time_series,
    humidity_time_series
]:
    model.create_input(time_series, group_name=xgboost.GroupName.FEATURES)
model.create_input(target_time_series, group_name=xgboost.GroupName.TARGETS)

# Add a fit policy to the model.
model.create_fit_policy(
    start_timing=myst.Time("2022-01-01T00:00:00Z"),
    end_timing=myst.Time("2022-02-01T00:00:00Z"),
    schedule_timing=myst.TimeDelta("PT24H"),
)

# Create a time series with the model predictions.
forecast_time_series = model.create_time_series(
    title="Demand Forecast", sample_period=myst.TimeDelta("PT1H")
)

# Add a run policy to the time series.
forecast_time_series.create_run_policy(
    start_timing=myst.TimeDelta("PT1H"),
    end_timing=myst.TimeDelta("PT169H"),
    schedule_timing=myst.TimeDelta("PT1H"),
)

Deploy your NoTS

Once you've finished creating your NoTS, you can now go ahead and deploy your Project.

Web Application

To create a new Deployment, click the Deploy button in the top right corner of the Project Create page. Specify a title for your Deployment and then click the Deploy button.

Once you’ve deployed a project, your Model Fit Policy and Time Series Run Policy will begin to run according to their schedules. This means that your Model will be fitted once a day and your Time Series will be run every hour. Note that these Policies will run indefinitely, until you deactivate your Deployment.

To track and verify the results of your Deployment, navigate to the Project Monitor space by clicking on the Monitor tab at the top of the Project page. The results table shows a list of ongoing results that are being generated by your policy. You can refresh the table by clicking on the refresh icon.

Client Library

The code below will deploy your project, creating a first model fit and time series run immediately.

# Deploy the project.
project.deploy("My Deployment")

# Create ad hoc time series node run job.
time_series_run_job = forecast_time_series.run(
    start_timing=myst.TimeDelta("PT1H"), 
    end_timing=myst.TimeDelta("PT169H"),
)

πŸ‘

Tutorial Complete

You are now generating the 7-day demand forecasts based on your historical demand data on an ongoing basis. See the section on Query Time Series Data to learn more about how to query your stored forecasts.