> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/sdgm/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/sdgm/_mcp/server.

# Forecast AdventureWorks Orders on Linux

> Train a local forecasting model, inspect three 30-day predictions per customer, and reload the saved model

Predict each customer's order count for three consecutive 30-day windows from one prediction time.
This example trains a forecasting model from AdventureWorks order history and saves predictions for each window.
Evaluate the forecast against later observed outcomes before using it in a business workflow.
This guide uses the local Python API from the Linux setup. Follow this page's Linux data and storage preparation; Databricks notebooks use their own setup and connector procedure.

## Prepare Sufficient History

Complete [Linux Machine Deployment Setup](/kumo-engine/1.0.0/get-started-with-kumo-engine/installation/linux-machine-deployment), then download the [Linux examples bundle and prepare the sample CSV files](/kumo-engine/1.0.0/examples/linux-local-examples#prepare-the-input-files).
Activate the installed Python environment.
Run the following commands from the extracted bundle directory.

The AdventureWorks sample contains approximately three years of order history.
Use prepare mode to validate and copy the same four files without duplicating or shifting events.

Replace the paths below with separate input, scratch, and output directories.
Use local storage for scratch and retain inputs and results on storage whose lifetime meets your needs.
Choose a prediction time that follows the input history and leaves the evaluation period you need.

```bash
export KUMO_FORECAST_INPUT=/path/to/adventureworks-forecast-inputs
export KUMO_FORECAST_SCRATCH=/path/to/local-storage/forecast-scratch
export KUMO_FORECAST_OUTPUT=/path/to/retained-results/forecast-01
export KUMO_FORECAST_TIME=2025-06-30T00:00:00
python adventureworks_forecast.py prepare \
  --input-dir "$ADVENTUREWORKS_DATA" \
  --prepared-dir "$KUMO_FORECAST_INPUT"
```

`KUMO_FORECAST_INPUT` must be a new path that is separate from the downloaded data, scratch, and retained output.
The prepare command validates the history and creates the forecast inputs.

See [Predictive Queries](/kumo-engine/1.0.0/user-code-guide/train-a-model/predictive-queries) for guidance on selecting a horizon that your history can support.

## Train and Save the Forecast

Run the forecast workflow after preparing sufficient history:

```bash
python adventureworks_forecast.py fit \
  --input-dir "$KUMO_FORECAST_INPUT" \
  --scratch-dir "$KUMO_FORECAST_SCRATCH" \
  --output-dir "$KUMO_FORECAST_OUTPUT" \
  --prediction-time "$KUMO_FORECAST_TIME"
```

The script builds the graph, generates the training table, fits the model, and saves its complete bundle under `model/`.
It then predicts the three 30-day windows and writes `predictions.parquet`.
A nonzero exit means the example did not complete; preserve the error and existing outputs before retrying in a new output directory.

The predictive query expresses the number of orders in each 30-day window:

```text
PREDICT COUNT(SalesOrderHeader.*, 0, 30, days) FORECAST 3 TIMEFRAMES FOR EACH Customer.CustomerID
```

The task type is `forecasting`.
For each anchor time, the three targets count orders in the next three consecutive 30-day windows.
Each window excludes its start and includes its end.
The default past-value feature counts orders in the preceding 30 days.
Review the generated training anchors and confirm that every target window used for evaluation is covered by observed history.

Pass a Python datetime without timezone information; Kumo interprets it as UTC.
The script sets this time when it generates the prediction table, then passes that table and the matching snapshot to inference.

## Inspect the Saved Forecast

The script imports `MetadataField` from `kumoapi.jobs` and passes `extra_fields=[MetadataField.ANCHOR_TIMESTAMP]` in its `PredictionOutputConfig` when generating predictions.
This includes the anchor column used by the checks below.

Run this Python block in a new process with the same environment variables:

```python
import os
from pathlib import Path

import numpy as np
import pandas as pd

output = Path(os.environ["KUMO_FORECAST_OUTPUT"]).expanduser().resolve()
inputs = Path(os.environ["KUMO_FORECAST_INPUT"]).expanduser().resolve()
prediction_time = pd.Timestamp(os.environ["KUMO_FORECAST_TIME"])
predicted = pd.read_parquet(output / "predictions.parquet")
customers = pd.read_csv(inputs / "Customer.csv")
columns = ["ENTITY", "TIMESTAMP", "ANCHOR_TIMESTAMP", "TARGET_PRED"]
missing = set(columns) - set(predicted.columns)
if missing:
    raise KeyError(f"Missing prediction columns: {sorted(missing)}")
assert predicted["ENTITY"].isin(customers["CustomerID"]).all()
assert predicted.groupby("ENTITY").size().eq(3).all()
assert predicted["ANCHOR_TIMESTAMP"].eq(prediction_time).all()
assert set(predicted["TIMESTAMP"]) == {
    prediction_time + pd.Timedelta(days=30 * offset) for offset in range(3)
}
assert np.isfinite(predicted["TARGET_PRED"].to_numpy()).all()
print("Rows:", len(predicted))
print(predicted.sort_values(["ENTITY", "TIMESTAMP"]).head(9))
```

Expect three rows for each customer in the generated prediction population:

| Column             | Meaning                                          |
| ------------------ | ------------------------------------------------ |
| `ENTITY`           | Customer identifier                              |
| `ANCHOR_TIMESTAMP` | The common prediction anchor                     |
| `TIMESTAMP`        | The start of the corresponding 30-day window     |
| `TARGET_PRED`      | Numeric prediction for that window's order count |

Predictions are model estimates, not observed counts.
Compare them with later observed outcomes to measure forecast quality.

Without this metadata selection, the default forecast output contains `ENTITY`, `TIMESTAMP`, and `TARGET_PRED`, but omits `ANCHOR_TIMESTAMP`.
`TIMESTAMP` remains the start of each forecast window whether or not the anchor column is selected.

## Reload Without Retraining

Retain the complete trusted model bundle and provide compatible forecast inputs
with the same graph schema and query fields. Start a new process, choose new
local scratch if needed, and choose a new output directory:

```bash
export KUMO_FORECAST_REPLAY=/path/to/retained-results/forecast-replay-01
python adventureworks_forecast.py predict \
  --input-dir "$KUMO_FORECAST_INPUT" \
  --scratch-dir "$KUMO_FORECAST_SCRATCH" \
  --model-dir "$KUMO_FORECAST_OUTPUT/model" \
  --output-dir "$KUMO_FORECAST_REPLAY" \
  --prediction-time "$KUMO_FORECAST_TIME"
```

This command uses `Trainer.load()` and writes a new `predictions.parquet` without calling `fit()`.
Repeat the inspection block with `output` pointing to `KUMO_FORECAST_REPLAY`.
With unchanged inputs and prediction time, expect the same entity coverage, three windows, and anchor.
With updated inputs or prediction time, check coverage against the current customer population and timestamps against the selected anchor.
Load only trusted model bundles.
The model does not contain source data or a graph snapshot.
Updated data can be scored when it remains compatible.

If prediction-table generation reports `lag_offsets_secs is required for forecasting tasks`, verify that the installed Kumo packages use matching supported versions and restart Python.
For a timestamp error, use a timezone-free datetime representing the intended UTC time rather than passing a string directly to the Python API.
This example uses default forecasting settings; custom lag and year-over-year configurations are not covered.
See [Training](/kumo-engine/1.0.0/user-code-guide/train-a-model/training) and [Making Predictions](/kumo-engine/1.0.0/user-code-guide/making-predictions) for method signatures, and [Publish and Retrieve Models](/kumo-engine/1.0.0/user-code-guide/train-a-model/publish-and-retrieve-models) for model artifact lifetimes.