Skip to navigation

Explain Kumo Tabular Predictions

View as Markdown

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:

ViewWhat it describes
result.explanations.gradientsLocal sensitivity of each scored row’s output to its preprocessed numerical inputs, returned by the model.
result.explanations.columnsGroups of labelled context rows, with each group’s population share and mean outcome, computed by the client.

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

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:

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:

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:

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.

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