Skip to navigation

Predict Multiple Labels on Linux

View as Markdown

Predict whether each customer will place online orders, offline orders, or both in the next 90 days. More than one order channel can occur in the same prediction window. This example trains a small multilabel model and saves a separate probability and decision for each type. Evaluate its per-label performance before using the decisions in a business workflow. This guide uses the local Python API from the Linux setup. Do not combine its calls with legacy Kumo Studio examples.

Run the Complete Example

Complete Linux Machine Deployment Setup, then download the Linux examples bundle and prepare the sample CSV files. Use the four prepared AdventureWorks CSVs. Activate the installed Python environment and keep ADVENTUREWORKS_DATA set to the prepared CSV directory.

Run this command from the extracted bundle directory. Replace the two output paths with new, separate directories. Use local storage for scratch and retain results on storage whose lifetime meets your needs. Keep both directories separate from the inputs and from each other.

export KUMO_MULTILABEL_OUTPUT=/path/to/retained-results/adventureworks-multilabel-01
python adventureworks_multilabel.py \
--input-dir "$ADVENTUREWORKS_DATA" \
--scratch-dir /path/to/local-storage/adventureworks-multilabel-scratch \
--output-dir "$KUMO_MULTILABEL_OUTPUT" \
--prediction-time 2025-06-30T00:00:00

The script builds the graph, generates historical labels from the event data, suggests a model plan, trains the model, and saves it under model/. It writes predictions.parquet with one row for each returned customer and order channel. Review the model plan and training budget before adapting it to production data.

A nonzero exit means the example did not complete. Preserve its error and existing outputs, correct the reported problem, and choose a new output directory before another attempt.

Understand the Prediction Task

The script uses this predictive query:

PREDICT LIST_DISTINCT(SalesOrderHeader.OnlineOrderFlag, 0, 90, days)
CLASSIFY TOP 2 FOR EACH Customer.CustomerID
WHERE COUNT(SalesOrderHeader.*, -365, 0, days) > 0

At each training time, LIST_DISTINCT collects the order-channel values that occur after that time and up to and including 90 days later. Repeated occurrences of the same type contribute one label. The result can contain no types, one type, or several types. The query uses CLASSIFY TOP 2, and the inference call separately requests both values with num_classes_to_return=2. A customer does not need to have both labels.

Generated training rows use ENTITY1, TIMESTAMP, and TARGET1. The query’s task type is multilabel_classification.

The prediction time is June 30, 2025, at midnight UTC. Pass a 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 Predictions

After the script exits, read the output in a new Python process with the same KUMO_MULTILABEL_OUTPUT environment variable:

import os
from pathlib import Path
import numpy as np
import pandas as pd
output = Path(os.environ["KUMO_MULTILABEL_OUTPUT"]).expanduser().resolve()
predicted = pd.read_parquet(output / "predictions.parquet")
columns = ["ENTITY", "TIMESTAMP", "PREDICTED", "CLASS", "SCORE"]
missing = set(columns) - set(predicted.columns)
if missing:
raise KeyError(f"Missing prediction columns: {sorted(missing)}")
expected_classes = {"0", "1"}
assert all(set(group["CLASS"].astype(str)) == expected_classes
for _, group in predicted.groupby("ENTITY"))
assert np.isfinite(predicted["SCORE"].to_numpy()).all()
assert predicted["SCORE"].between(0, 1).all()
print("Rows:", len(predicted))
print(predicted.head(8))
print("Selected labels per customer:")
print(predicted.groupby("ENTITY")["PREDICTED"].sum().value_counts().sort_index())

Expect one row per customer and class, with these columns:

ColumnMeaning
ENTITYCustomer identifier
TIMESTAMPRequested prediction time
CLASSOffline (0) or online (1) order flag
SCOREPredicted probability that this order channel occurs in the window
PREDICTEDModel’s true or false decision for this order channel

These probabilities describe separate labels and do not need to sum to one for a customer. PREDICTED is a decision for each label, so it can select no labels or several labels. It is not a ground-truth value or a marker for one winning class. The script requests both class rows with num_classes_to_return=2; do not discard classes before checking that both values are present.

Handle Threshold and Time Errors

Omit binary_classification_threshold for multilabel prediction output. Supplying it raises a ValueError stating that an explicit classification threshold is unsupported for this output. Remove the argument and use the returned per-class scores and decisions. If you need a separate business decision rule, apply it to the saved SCORE values in your own analysis and validate that rule on an appropriate evaluation dataset.

If the script rejects a timestamp with timezone information, supply the intended UTC time without the timezone suffix, as in the command above. Convert other local times to UTC before removing timezone information.

Use an appropriate evaluation dataset and training budget before relying on the model’s decisions. See Making Predictions for prediction parameters and output retention, and Publish and Retrieve Models for model reload requirements.