> This page is for Structured Data Models Client.

> 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.

# Prediction Types

> Task taxonomy: regression, classification, forecasting, ranking, and static tasks

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).

> **Note**
>
> 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](/sdgm/kumo-relational/about-kumo-relational/introduction#some-deployments-serve-only-classification-and-regression--the-client-builds-the-rest).

The Python snippets use sdm-client:

```python
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:

```sql
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`

```sql
-- Predict total revenue for item_id=42 in the next 30 days
PREDICT SUM(orders.price, 0, 30, days)
FOR items.item_id=42
```

```python
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`)

```sql
-- 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
```

```python
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`

```sql
-- 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
```

```python
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.

```sql
-- 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
```

```python
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](/sdgm/kumo-relational/user-guide/work-with-prediction-results/prediction-results#a-ranking-can-hold-fewer-than-k-candidates).

> **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](/sdgm/kumo-relational/user-guide/prepare-data/best-practices#pairs-table-for-ranking-over-a-fixed-candidate-set) and [Prediction Results](/sdgm/kumo-relational/user-guide/work-with-prediction-results/prediction-results#recommended-pattern-rank-over-a-table-of-pairs) 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`

```sql
-- 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
```

```python
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](/sdgm/kumo-relational/user-guide/make-predictions/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:

```sql
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

```sql
-- Predict the age of user_id=42
PREDICT users.age
FOR users.user_id=42
```

```python
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

```sql
-- Predict whether transaction_id=42 is fraudulent
PREDICT transactions.is_fraudulent
FOR transactions.transaction_id=42
```

```python
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

```sql
-- Predict the customer segment for customer_id=42
PREDICT customers.segment
FOR customers.customer_id=42
```

```python
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 Type                           | PQL Pattern                                                                            | Output                            | Category |
| ----------------------------------- | -------------------------------------------------------------------------------------- | --------------------------------- | -------- |
| Temporal Regression                 | `PREDICT SUM(t.col, 0, N, days) FOR ...`                                               | Numeric                           | Temporal |
| Temporal Binary Classification      | `PREDICT COUNT(t.*, 0, N, days) = 0 FOR ...`                                           | Boolean + Probability             | Temporal |
| Temporal Multi-Class Classification | `PREDICT FIRST(t.col, 0, N, days) FOR ...`                                             | One row per entity, class columns | Temporal |
| Recommendations (ranking)           | `PREDICT LIST_DISTINCT(t.col, 0, N, days) RANK TOP K FOR EACH ...`, with `candidates=` | Ranked item list                  | Temporal |
| Multi-Horizon Forecasting           | `PREDICT SUM(t.col, 0, N, days) FORECAST K TIMEFRAMES FOR ...`                         | Time-indexed numerics             | Temporal |
| Static Regression                   | `PREDICT t.numeric_col FOR ...`                                                        | Numeric                           | Static   |
| Static Binary Classification        | `PREDICT t.bool_col FOR ...`                                                           | Boolean + Probability             | Static   |
| Static Multi-Class                  | `PREDICT t.categorical_col FOR ...`                                                    | One row per entity, class columns | Static   |

## 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](/sdgm/kumo-relational/user-guide/explain-predictions/prediction-explainability).