Skip to navigation

Prediction Types

View as Markdown

Kumo Relational supports a variety of prediction types, organized into temporal tasks (which involve a future time horizon) and static tasks (which infer attributes without a time component).

Some kumo-relational deployments natively answer only classification and regression. For that narrower deployment, a ranking is decomposed into one classification call per candidate, and a multi-step forecast into one regression call per step — materialize() and predict() handle this automatically, in several round trips, and you still call them once. See How Kumo Relational Works.

The Python snippets use sdm-client:

from sdm_client import PredictiveQuery, SDMClient, KumoRelational
def predict(query_text, indices, **options):
query = PredictiveQuery(query_text, schema)
request = query.materialize(indices=indices, **options)
with SDMClient(url="http://localhost:8000") as client:
return client.predict(request, model=KumoRelational())

Temporal Tasks (Forecast)

All temporal tasks predict future outcomes over a defined time horizon by using historical data from relational tables. Every temporal prediction is defined by the following components:

  • Target: What is being predicted (an aggregation expression)
  • Entity: Who the prediction is for (a table primary key)
  • Horizon: When the prediction applies (a future time window)

The general PQL pattern for temporal tasks is:

PREDICT <aggregation>(table.column, <start>, <end>, <unit>) FOR entity_table.pk=value

where <start> and <end> define the future time window relative to “now,” and the <unit> value specifies the time granularity, such as days, hours, or minutes.

Forecast: Regression

Predict a continuous numeric value for an entity over a future time horizon.

Use case: Demand forecasting, revenue prediction, quantity estimation.

Supported aggregations: SUM, AVG, COUNT, MAX, MIN

-- Predict total revenue for item_id=42 in the next 30 days
PREDICT SUM(orders.price, 0, 30, days)
FOR items.item_id=42
result = predict(
"PREDICT SUM(orders.price, 0, 30, days) FOR items.item_id=42", [42]
)

Output: Numeric value per entity, under prediction — the model’s predicted median by default. Pass materialize(..., prediction_statistic="mean") for the mean instead; prefer the mean when predictions will be summed across entities, since medians don’t add up the way means do.

Metrics: mae, mse, rmse, mape, smape, r2.

Forecast: Binary Classification

Predict whether an entity will or will not experience an event within a future time window. This is defined by applying a boolean condition to an aggregation expression.

Use case: Customer churn prediction, event occurrence prediction.

Supported aggregations: SUM, AVG, COUNT, MAX, MIN (with a boolean condition such as = 0, > 100)

-- Predict whether user_id=42 will make zero orders in the next 90 days (churn)
PREDICT COUNT(orders.*, 0, 90, days) = 0
FOR users.user_id=42
result = predict(
"PREDICT COUNT(orders.*, 0, 90, days) = 0 FOR users.user_id=42", [42]
)

The boolean condition (= 0, > 100, etc.) on the aggregation makes this a binary classification task.

Output: prediction (Boolean) and probability_<class> columns per entity.

Metrics: acc, auroc, auprc, ap, precision, recall, f1.

Forecast: Multi-Class Classification

Predict which class or state an entity will belong to at a future point in time. Use FIRST() to predict the first value that occurs in the window, or LAST() to predict the final value.

Use case: Tier migration, lifecycle stage prediction, feature engagement.

Supported aggregations: FIRST, LAST

-- Predict what subscription tier user_id=42 will be in after 30 days
PREDICT FIRST(subscriptions.tier, 0, 30, days)
FOR users.user_id=42
result = predict(
"PREDICT FIRST(subscriptions.tier, 0, 30, days) FOR users.user_id=42", [42]
)

Output: One row per entity, with a probability_<class> column per class.

Metrics: acc, precision, recall, f1, mrr.

Recommendations (Ranking)

Predict a ranked list of items an entity is most likely to interact with over a future time window, using LIST_DISTINCT() with RANK TOP N.

Use case: Product recommendations, content ranking, next best action.

-- Rank which of a candidate set user_id=42 is most likely to order in the next 30 days
PREDICT LIST_DISTINCT(orders.item_id, 0, 30, days) RANK TOP 3
FOR EACH users.user_id
from sdm_client import PredictiveQuery, SDMClient, KumoRelational
request = PredictiveQuery(
"PREDICT LIST_DISTINCT(orders.item_id, 0, 30, days) RANK TOP 3 FOR EACH users.user_id",
schema,
).materialize(indices=[42], candidates=items["item_id"])
with SDMClient(url="http://localhost:8000") as client:
result = client.predict(request, model=KumoRelational())
print(result.to_pandas())
print(result.unscored_candidates)

You must name the candidate set with candidates=. No ranking task assumes one. Each candidate is asked as its own classification call — “will this entity reach this one?” — so a RANK TOP 3 over 50 candidates makes 50 calls.

A candidate whose sampled context holds only one answer (nobody reached it in the window, or everybody did) can’t be scored and is left out rather than refusing the whole ranking. It carries no score and appears in no row’s prediction or rankings; result.unscored_candidates names which ones, in the order you passed them. See Prediction Results.

Prefer ranking over a table of pairs when you can

One call per candidate is expensive and, on sparse data, often can’t be scored at all. If you can build a table with one row per (entity, candidate) pair, ask a single classification request over the pairs instead, batched if needed, and every candidate pools context from every pair. See Best Practices and Prediction Results for the full pattern.

Output: One row per entity, with prediction holding the ranked candidates and rankings pairing each with its score.

Metrics: map@k, ndcg@k, mrr@k, precision@k, recall@k, f1@k, hit_ratio@k.

Multi-Horizon Regression (Forecasting)

Predict a numeric value for an entity across multiple future time steps. This task produces a time series of predictions.

Use case: Multi-step demand forecasting, time series prediction.

Supported aggregations: SUM, COUNT, COUNT_DISTINCT

-- Predict weekly revenue for item_id=42 over the next 60 weeks
PREDICT SUM(orders.price, 0, 7, days) FORECAST 60 TIMEFRAMES
FOR items.item_id=42
result = predict(
"PREDICT SUM(orders.price, 0, 7, days) FORECAST 60 TIMEFRAMES "
"FOR items.item_id=42",
[42],
)

The FORECAST N TIMEFRAMES clause tells Kumo Relational to produce N predictions, each separated by the time window specified in the aggregation (7 days in this example). So FORECAST 60 TIMEFRAMES with a 7-day window predicts out 60 × 7 = 420 days total. Forecasting is limited to a single entity per request; each step is its own call. See Forecasting.

Output: Time-indexed numeric values, one row per forecast step.

Metrics: mae, mse, rmse, mape, smape, r2.

Static Tasks

Static tasks infer latent or unknown entity attributes without modeling temporal evolution. A static prediction has no time horizon — the prediction is about the entity’s current state based on its attributes and relational context.

Every static prediction is defined by: Target × Entity (no horizon).

The general PQL pattern for static tasks is:

PREDICT table.column FOR entity_table.pk=value

Static Regression

Infer a continuous numeric attribute of an entity.

Use case: Age estimation, price imputation, value scoring.

Supported target type: Numeric columns

-- Predict the age of user_id=42
PREDICT users.age
FOR users.user_id=42
result = predict("PREDICT users.age FOR users.user_id=42", [42])

Output: Numeric value per entity, under prediction (median by default).

Metrics: mae, mse, rmse, mape, smape, r2.

Static Binary Classification

Infer whether an entity belongs to one of two classes based on its attributes.

Use case: Fraud detection, quality classification.

Supported target type: Boolean columns

-- Predict whether transaction_id=42 is fraudulent
PREDICT transactions.is_fraudulent
FOR transactions.transaction_id=42
result = predict(
"PREDICT transactions.is_fraudulent FOR transactions.transaction_id=42", [42]
)

A 0/1 integer target is read as a binary label, not a regression, as long as it holds only zeros, ones, and at most one missing value.

Output: prediction (Boolean) and probability_<class> columns per entity.

Metrics: acc, auroc, auprc, ap, precision, recall, f1.

Static Multi-Class Classification

Infer which single class an entity belongs to from a set of possible classes.

Use case: Customer segmentation, category prediction.

Supported target type: Categorical columns

-- Predict the customer segment for customer_id=42
PREDICT customers.segment
FOR customers.customer_id=42
result = predict(
"PREDICT customers.segment FOR customers.customer_id=42", [42]
)

Output: One row per entity, with a probability_<class> column per class.

Metrics: acc, precision, recall, f1, mrr.

Summary

Task TypePQL PatternOutputCategory
Temporal RegressionPREDICT SUM(t.col, 0, N, days) FOR ...NumericTemporal
Temporal Binary ClassificationPREDICT COUNT(t.*, 0, N, days) = 0 FOR ...Boolean + ProbabilityTemporal
Temporal Multi-Class ClassificationPREDICT FIRST(t.col, 0, N, days) FOR ...One row per entity, class columnsTemporal
Recommendations (ranking)PREDICT LIST_DISTINCT(t.col, 0, N, days) RANK TOP K FOR EACH ..., with candidates=Ranked item listTemporal
Multi-Horizon ForecastingPREDICT SUM(t.col, 0, N, days) FORECAST K TIMEFRAMES FOR ...Time-indexed numericsTemporal
Static RegressionPREDICT t.numeric_col FOR ...NumericStatic
Static Binary ClassificationPREDICT t.bool_col FOR ...Boolean + ProbabilityStatic
Static Multi-ClassPREDICT t.categorical_col FOR ...One row per entity, class columnsStatic

What your deployment actually serves

The client declares a broader output surface than any one deployment may answer. A deployment that serves only classification and regression natively still answers ranking end to end (it is decomposed into classification calls), but scores, embeddings, and explanation can be refused outright. Check what your deployment actually returns with a representative request before depending on an optional output field — see Prediction Explainability.