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

# Explain Kumo Tabular Predictions

> Inspect input sensitivity and patterns in labelled examples with the SDM client

Request explanations to inspect how a prediction responds to small input changes and how outcomes vary across your labelled examples.
The result contains two views:

| View                            | What it describes                                                                                             |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `result.explanations.gradients` | Local sensitivity of each scored row's output to its preprocessed numerical inputs, returned by the model.    |
| `result.explanations.columns`   | Groups of labelled context rows, with each group's population share and mean outcome, computed by the client. |

> **Warning**
>
> These APIs describe upcoming client functionality and require a deployment that serves explanations.
> Client 1.0.0 and the shipping Kumo Tabular NIM 1.0.0 do not support this workflow.
> Confirm support in your client and NIM release notes before running these examples.

## Request explanations

Start with the `labelled` and `to_score` DataFrames from the [quickstart](/sdgm/kumo-tabular/get-started/quickstart).
The labelled rows contain the `churn` target; the rows to score must omit it.
Add `"explanation"` to the outputs while retaining the prediction fields you need:

```python
from sdm_client import KumoTabular, Request, SDMClient

request = Request(
    context=labelled,
    predict=to_score,
    target="churn",
    task="classification",
)
with SDMClient(url="http://localhost:8000") as client:
    result = client.predict(
        request,
        model=KumoTabular(),
        outputs=["prediction", "probabilities", "explanation"],
    )

predictions = result.to_pandas()
gradients = result.explanations.gradients.to_pandas()
```

Replace the URL with your endpoint and supply `api_key` if your gateway requires it.
An explanation request can score multiple rows.
The prediction DataFrame stays separate from the explanation tables.

If you use PQL, prefix the same question with `EXPLAIN` instead.
Using the `users_df` table from [Make Predictions](/sdgm/kumo-tabular/user-guide/make-predictions/make-predictions):

```python
from sdm_client import PredictiveQuery

query = PredictiveQuery(
    "EXPLAIN PREDICT users.churn FOR EACH users.user_id",
    {"users": users_df},
)
request = query.materialize(indices=[7, 12, 3], task="classification")
with SDMClient(url="http://localhost:8000") as client:
    result = client.predict(request, model=KumoTabular())
```

`EXPLAIN` adds explanations to the outputs the call would otherwise request.
Passing both the prefix and `outputs=[..., "explanation"]` is allowed but unnecessary.

## Inspect one prediction's gradients

The following examples use `result` from the PQL request above, which replaces the direct-request result and supplies the user IDs used here.

`result.explanations.gradients` maps each scored row to its explanation.
The key is its `id` when IDs are unique, or `row_index` when there is no ID or IDs repeat.
For the PQL example, inspect user 7:

```python
explanation = result.explanations.gradients[7]
explained_outputs = explanation["outputs"]
feature_names = explanation["instance"]["columns"]
values = explanation["instance"]["gradients"]
```

`values` is indexed by output, then column.
Classification explains each class probability; regression explains the returned prediction and quantiles in the response.
The column names are numerical inputs after model preprocessing, so categorical or date columns can appear under derived names.
Only scored rows get gradients, not labelled context rows.

For a DataFrame, use `result.explanations.gradients.to_pandas()`.
Each line identifies the scored row, output, preprocessed column, and gradient.
Tabular rows use `table="instance"` and `hop=0`.
Inspect the outputs for one user, and compare gradients only within the same output:

```python
gradients = result.explanations.gradients.to_pandas()
user_gradients = gradients.loc[gradients["id"] == 7]
print(user_gradients[["output", "column", "gradient"]])
```

A positive gradient means a small increase in that preprocessed input locally increases the selected output; a negative gradient means it decreases the output.
Gradient values depend on how inputs are scaled, so a larger absolute value does not necessarily mean a feature is more important to the prediction.
Use gradients to investigate sensitivity.
Correct a suspect value only after checking it against the source record, then rerun the prediction to check its effect.

## Compare groups of labelled examples

Column explanations group the labelled rows the request sends by feature values.
They describe patterns in those examples, not the reason for an individual prediction.
The target, primary key, and timestamps are excluded from tabular column analysis.

```python
analysis = result.explanations.columns
if analysis is not None:
    cohorts = analysis.to_pandas()
    print(cohorts[["column", "cohort", "class", "share", "mean"]])
```

Numerical columns use up to ten quantile bins.
Categorical columns use up to ten cohorts.
If there are more, the tenth and later cohorts are combined into `OTHER(*)`, which can also absorb the `N/A` cohort for missing values.
Missing numerical values are excluded from their column analysis.
The table name is `instance_table`.

For classification, `class` identifies the target label and `mean` is the proportion of the cohort's labelled examples with that label.
For example, `class: "churned"` and `mean: 0.3` means 30% of those examples churned, not that an individual prediction has a 30% churn probability.
At most 30 classes are reported, selected by frequency.
For regression, `mean` is the average observed target in its original units, and `class` is `None`.
For example, `mean: 120` for an order total measured in dollars means an average observed order total of \$120.

`share` is the fraction of the analysed population in the cohort; `share: 0.2` means 20% of that population.
Compare means within the same column and class, and consider how well each cohort is represented before interpreting differences.
A small share does not necessarily mean a small absolute sample size.

## Use explanations with a fitted session

A session computes column analysis once at `fit()`, after removing `holdout` rows, and reuses it for subsequent predictions.
Gradients describe the rows scored in each prediction; they are not reused from an earlier prediction.
Request explanations in `fit(..., outputs=["prediction", "probabilities", "explanation"])` or fit an `EXPLAIN PREDICT` query to attach explanations to every prediction.
A session fitted without explanations can also accept the same question with the `EXPLAIN` prefix on a later prediction.
The prefix changes the requested output, not the pinned question.
See [fitted sessions](/sdgm/kumo-tabular/user-guide/make-predictions/make-predictions#ask-the-same-context-several-questions-with-fit) for context and holdout preparation.

## Handle unavailable explanations

* If the client or endpoint refuses `explanation`, confirm that both versions support it before retrying.
* Check `result.absent(["explanation"])` for missing gradient output and inspect the client's warning.
* Check `result.explanations.columns is None` separately before converting cohorts to a DataFrame. Column analysis can fail with an `SDMWarning` while the prediction still succeeds.

Neither gradients nor cohort associations establish causality or identify a business action that will change the real outcome.
Keep the query and labelled context alongside your analysis so another reader can understand what was explained.