Step 6: Make predictions
Predictions use deployed models that are activated to infer outcomes based on input data. They can be generated in real-time or as batch jobs.
Generate real-time predictions
Use a deployed model to infer outcomes for input feature sets and get immediate insights based on live data. To generate real-time predictions, send the following API call:
curl -L -X POST "https://<TENANT>/api/v1/ml/deployments/<DEPLOYMENT_ID>/realtime-predictions/actions/run" ^
-H "Authorization: Bearer <ACCESS_TOKEN>" ^
-H "Content-Type: application/json" ^
-H "Accept: text/csv" ^
-d "{
\"schema\": [
{
\"name\": \"<string>\"
},
{
\"name\": \"<string>\"
}
],
\"rows\": [
[
\"<string>\",
\"<string>\"
],
[
\"<string>\",
\"<string>\"
]
]
}"
Query parameters for real-time predictions
The request includes optional query parameters:
includeShap=<boolean>
: When set totrue
, the response includes SHAP (SHapley Additive exPlanations) values to explain predictions.includeSource=<boolean>
: When set totrue
, the response includes original input data in the response.includeNotPredictedReason=<boolean>
: When set totrue
, the response includes reasons for any prediction failures.index=<string>
: Specify a unique identifier column for tracking predictions.
Structure the request body for real-time predictions
You need to send input data that matches the features the model expects. Here’s how you can structure the request body:
schema
defines the features (columns) expected by the model to make a prediction.rows
contains the actual data to predict outcomes for. Each row is an array of feature values in the same order as the schema.
The example model v03_RAFC_01_00
that has been deployed in the previous steps expects the
following features:
PlanType
NumberOfPenalties
HasRenewed
BaseFee
ServiceTickets
AdditionalFeatureSpend
ServiceRating
Promotion
Now, imagine you’re predicting churn for two customers:
Feature | Customer 1 | Customer 2 |
---|---|---|
PlanType | Standard | Premium |
NumberOfPenalties | 1 | 3 |
HasRenewed | true | false |
BaseFee | $50.00 | $80.00 |
ServiceTickets | 5 | 2 |
AdditionalFeatureSpend | $15.50 | $25.00 |
ServiceRating | 4.2 | 3.8 |
Promotion | true | false |
These details are placed into the rows
section of the request body.
Put all this together:
{
"schema": [
{ "name": "PlanType" },
{ "name": "NumberOfPenalties" },
{ "name": "HasRenewed" },
{ "name": "BaseFee" },
{ "name": "ServiceTickets" },
{ "name": "AdditionalFeatureSpend" },
{ "name": "ServiceRating" },
{ "name": "Promotion" }
],
"rows": [
["Standard", 1, true, 50.0, 5, 15.5, 4.2, true],
["Premium", 3, false, 80.0, 2, 25.0, 3.8, false]
]
}
Request example with SHAP values and reasons for prediction failures
curl -L -X POST "https://<TENANT>/api/v1/ml/deployments/<DEPLOYMENT_ID>/realtime-predictions/actions/run?includeShap=true&includeNotPredictedReason=true" ^
-H "Content-Type: application/json" ^
-H "Accept: application/json" ^
-H "Authorization: Bearer <ACCESS_TOKEN>" ^
-d "{
\"schema\": [
{ \"name\": \"PlanType\" },
{ \"name\": \"NumberOfPenalties\" },
{ \"name\": \"HasRenewed\" },
{ \"name\": \"BaseFee\" },
{ \"name\": \"ServiceTickets\" },
{ \"name\": \"AdditionalFeatureSpend\" },
{ \"name\": \"ServiceRating\" },
{ \"name\": \"Promotion\" }
],
\"rows\": [
[\"Standard\", 1, true, 50.0, 5, 15.5, 4.2, true],
[\"Premium\", 3, false, 80.0, 2, 25.0, 3.8, false]
]
}"
Understand real-time predictions
Response example
{
"data": {
"type": "realtime-prediction",
"attributes": {
"schema": [
{
"name": "automl_row_index",
"type": "numeric"
},
{
"name": "Churned_predicted",
"type": "categorical"
},
{
"name": "Churned_no",
"type": "numeric"
},
{
"name": "Churned_yes",
"type": "numeric"
},
{
"name": "PlanType_SHAP",
"type": "numeric"
},
{
"name": "NumberOfPenalties_SHAP",
"type": "numeric"
},
{
"name": "BaseFee_SHAP",
"type": "numeric"
},
{
"name": "HasRenewed_SHAP",
"type": "numeric"
},
{
"name": "ServiceTickets_SHAP",
"type": "numeric"
},
{
"name": "AdditionalFeatureSpend_SHAP",
"type": "numeric"
},
{
"name": "Promotion_SHAP",
"type": "numeric"
},
{
"name": "ServiceRating_SHAP",
"type": "numeric"
},
{
"name": "not_predicted_reason",
"type": "categorical"
}
],
"rows": [
[
0,
"no",
0.5748563288337797,
0.4251436711662205,
-0.08696714660398806,
-0.016504858877164276,
0.31270329674944836,
0.0751632395258829,
-0.026030621640180034,
-0.008297165265234656,
-0.07740939502064204,
-0.08043817693148562,
null
],
[
1,
"yes",
0.4220295388409809,
0.5779704611590192,
-0.08042057594415754,
-0.023509910893523875,
0.29031823511489696,
0.07309979343955059,
0.08679203458265218,
0.09052554583195933,
-0.07936633175213981,
-0.11239282844980283,
null
]
]
}
}
}
The reponse contains the results of the real-time prediction request:
- Prediction: The predicted class for each input row (in this example, whether the customer is likely to churn).
- Confidence scores: How sure the model is about its predictions, expressed as probabilities (in this example, the likelihood of “yes” or “no”).
- SHAP values: The importance of each feature to the prediction. SHAP values help you understand why the model made its predictions. For more information, see Understanding SHAP importance in experiment training on Qlik Help.
- Errors: Reasons why the model couldn’t make a prediction, if any.
schema
lists all the columns in the prediction response:
Column Name | Type | Description |
---|---|---|
automl_row_index | numeric | The index of the input row from the request. |
Churned_predicted | categorical | The predicted outcome (“yes” for churn or “no” for not churn). |
Churned_no | numeric | The model’s confidence score (probability) that the customer will not churn. |
Churned_yes | numeric | The model’s confidence score (probability) that the customer will churn. |
PlanType_SHAP | numeric | SHAP value indicating how the PlanType feature influenced the prediction. |
NumberOfPenalties_SHAP | numeric | SHAP value for NumberOfPenalties . |
BaseFee_SHAP | numeric | SHAP value for BaseFee . |
HasRenewed_SHAP | numeric | SHAP value for HasRenewed . |
ServiceTickets_SHAP | numeric | SHAP value for ServiceTickets . |
AdditionalFeatureSpend_SHAP | numeric | SHAP value for AdditionalFeatureSpend . |
Promotion_SHAP | numeric | SHAP value for Promotion . |
ServiceRating_SHAP | numeric | SHAP value for ServiceRating . |
not_predicted_reason | categorical | If the row wasn’t predicted, this provides the reason. |
rows
contains the prediction results for each input (in this example, Customer 1 and Customer 2):
Row index | Prediction | Confidence (No) | Confidence (Yes) | SHAP Values |
---|---|---|---|---|
0 | no | 0.5749 | 0.4251 | Importance of PlanType , BaseFee , ServiceTickets , etc., for predicting “no” |
1 | yes | 0.4220 | 0.5780 | Importance of PlanType , BaseFee , ServiceTickets , etc., for predicting “yes” |
The predictions can be interpreted as follows:
-
Predictions (
Churned_predicted
):"yes"
means the model predicts the customer is likely to churn."no"
means the model predicts the customer is unlikely to churn.
-
Confidence scores (
Churned_no
andChurned_yes
) show how sure the model is about each outcome. They are probabilities. For example:- For Customer 1 (row 0), the model is
57.49%
confident they will not churn (Churned_no
=0.5749
) . - For Customer 2 (row 1), the model is
57.80%
confident they will churn (Churned_yes
=0.5780
).
- For Customer 1 (row 0), the model is
-
SHAP Values explain how strongly each feature impacted the prediction. They are “pushes” towards a decision. Positive values mean the feature makes the model more likely to predict “yes” (churn). Negative values mean the feature makes the model more likely to predict “no” (not churn). For example:
- For Customer 1 (row 0),
BaseFee_SHAP
contributes positively towards predicting “no” (churn). - For Customer 2 (row 1),
AdditionalFeatureSpend_SHAP
contributes positively towards predicting “yes” (not churn).
- For Customer 1 (row 0),
-
Errors (
not_predicted_reason
): If a prediction is not made for a row, thenot_predicted_reason
column explains why. In this example, all predictions succeeded, so the column isnull
.
Generate batch predictions
You can also use a deployed model to generate batch predictions to process larger datasets asynchronously. This is useful when you have a significant volume of data to analyze or when real-time predictions aren’t feasible.
Create a batch prediction job
To create a batch prediction job, use the following API call:
curl -L -X POST "https://<TENANT>/api/v1/ml/deployments/<DEPLOYMENT_ID>/batch-predictions" ^
-H "Authorization: Bearer <ACCESS_TOKEN>" ^
-H "Content-Type: application/json" ^
-d "{
\"data\": {
\"type\": \"batch-prediction\",
\"attributes\": {
\"name\": \"<NAME>\",
\"deploymentId\": \"<DEPLOYMENT_ID>\",
\"description\": \"<DESCRIPTION>\",
\"dataSetId\": \"<DATASET_ID>\",
\"indexColumn\": \"<INDEX_COLUMN>\",
\"schedule\": {
\"timezone\": \"<TIMEZONE>\",
\"recurrence\": [\"RECURRENCE_RULE\"],
\"endDateTime\": \"<END_TIME>\",
\"startDateTime\": \"<START_TIME>\",
\"applyDatasetChangeOnly\": boolean
},
\"writeback\": {
\"format\": \"<FORMAT>\",
\"dstName\": \"<OUTPUT_FILE_NAME>\",
\"spaceId\": \"<SPACE_ID>\",
\"dstShapName\": \"<SHAP_FILE_NAME>\",
\"dstSourceName\": \"<SOURCE_FILE_NAME>\",
\"dstCoordShapName\": \"<COORDINATE_SHAP_FILE_NAME>\",
\"dstNotPredictedName\": \"<NOT_PREDICTED_FILE_NAME>\"
}
}
}
}"
Structure the request body for batch predictions
The attributes
field specifies general job details:
name
: A name for the batch prediction job.description
: A short description of the job’s purpose.dataSetId
: The unique identifier for the apply dataset (the new dataset for which you will generate batch predictions).indexColumn
: (Optional) A column in the apply dataset used to uniquely identify rows in the prediction results. If not specified, a column will be automatically generated.
The schedule
field defines when and how frequently the batch prediction runs:
timezone
: The time zone for the schedule (for example,"America/Toronto"
).recurrence
: A recurrence rule in RFC 5545 format. For example,RRULE:FREQ=DAILY;INTERVAL=1;BYHOUR=16;BYMINUTE=30;BYSECOND=0
.startDateTime
andendDateTime
: Define the prediction job’s start and end times.applyDatasetChangeOnly
: Whentrue
, triggers predictions only when the dataset changes. If you don’t want to schedule the batch prediction job and run it manually, set this tonull
.
The writeback
field specifies how and where the prediction results are saved. At a minimum, it requires the spaceId
,
format
, and dstName
properties.
Property | Type | Description |
---|---|---|
spaceId | string | The ID of the storage space where prediction results will be saved. Leave as an empty string ("" ) to save results to your personal space. |
format | string | File format for the output. The supported formats are "qvd" , "parquet" , "csv" . |
dstName | string | The name of the main output file containing the prediction results. |
dstShapName | string | The name of the file containing SHAP (SHapley Additive exPlanations) values for feature importance explanations. |
dstSourceName | string | The name of the apply dataset, which contains the input data rows used for predictions (useful for traceability and debugging). |
dstCoordShapName | string | The name of the file containing SHAP values for geospatial coordinates, if applicable. |
dstNotPredictedName | string | The name of the file containing rows that could not be predicted, along with associated error messages. |
Here is an example:
"writeback": {
"spaceId": "6745f737f536738170dfe82f",
"format": "parquet",
"dstName": "customer_predictions",
"dstShapName": "customer_predictions_shap.parquet",
"dstSourceName": "customer_predictions_source.parquet",
"dstCoordShapName": "customer_predictions_coord_shap.parquet",
"dstNotPredictedName": "customer_predictions_not_predicted.parquet"
}
Response example
{
"data": {
"type": "batch-prediction",
"id": "9bf8c57e-5f65-4ed5-b504-21daa33248db",
"attributes": {
"id": "9bf8c57e-5f65-4ed5-b504-21daa33248db",
"deploymentId": "f822f467-6a81-4cb7-bb90-ebe3b4224c30",
"createdAt": "2024-12-13T14:24:48.704645172Z",
"updatedAt": "2024-12-13T14:24:48.704645172Z",
"name": "Churn_predictions",
"dataSetId": "6749ddb8bf86ce46d48fe0a3",
"createdBy": "67475097984561d02f0cb3dc",
"ownerId": "67475097984561d02f0cb3dc",
"errorMessage": null,
"indexColumn": null,
"status": "modified",
"schedule": null,
"writeback": {
"spaceId": "6745f737f536738170dfe82f",
"format": "parquet",
"dstName": "customer_predictions.parquet",
"dstShapName": "customer_predictions_shap.parquet",
"dstSourceName": "customer_predictions_source.parquet",
"dstCoordShapName": "customer_predictions_coord_shap.parquet",
"dstNotPredictedName": "customer_predictions_not_predicted.parquet"
}
}
}
}
In this example:
- Results are saved in the parquet format and saved in the space with the identifier
6745f737f536738170dfe82f
. - SHAP values are saved to
customer_predictions_shap.parquet
. - Source rows are saved to
customer_predictions_source.parquet
. - SHAP values for geospatial coordinates are saved to
customer_predictions_coord_shap.parquet
. - Non-predicted rows are saved to
customer_predictions_not_predicted.parquet
.
Start a batch prediction job
Once the batch prediction is configured, start the job with the following API call:
curl -L -X POST "https://<TENANT>/api/v1/ml/deployments/<DEPLOYMENT_ID>/batch-predictions/<BATCH_PREDICTION_ID>/actions/predict" ^
-H "Authorization: Bearer <ACCESS_TOKEN>"
Batch predictions run as background jobs. The 201 Created
confirms job creation.
Response example
{
"data": {
"id": "e217457-8087-47d6-84b1-3f9dfce4955c",
"type": "job",
"attributes": {
"id": "e217457-8087-47d6-84b1-3f9dfce4955c",
"createdAt": "2024-12-13T14:24:48.704645172Z",
"updatedAt": "2024-12-13T14:24:48.704645172Z",
"deletedAt": null,
"tenantId": "GIlHILBfb5R6drAY2L7Zvi2c_YnlFDHR",
"createdBy": "67475097984561d02f0cb3dc",
"status": "pending",
"corrId": "fe4f2cbd-7961-4596-bfd8-3b4520acf712",
"jobType": "prediction",
"corrType": "prediction",
"deploymentId": "f822f467-6a81-4cb7-bb90-ebe3b4224c30",
"spaceId": "6745f737f536738170dfe82f",
"name": "Churn_predictions",
"parentName": "Model deployment for churn predictions",
"details": {
"outputFiles": [],
"isScheduled": false
},
"trigger": "manual",
"success": null,
"modelId": "f7336f07-978e-45f7-b449-fc1da6f17c37"
}
}
}
Monitor batch prediction progress
Monitoring the batch prediction progress ensures predictions are running as expected and helps you track when results are ready.
After the prediction job has started, you can monitor its status with the following API call:
curl -L "https://<TENANT>/api/v1/ml/deployments/<DEPLOYMENT_ID>/batch-predictions" ^
-H "Authorization: Bearer <ACCESS_TOKEN>"
The API returns details about batch predictions job, including the prediction status. For example, ready
means that
process has completed, and you can evaluate the prediction results.
Response example
{
"type": "batch-prediction",
"id": "9bf8c57e-5f65-4ed5-b504-21daa33248db",
"attributes": {
"id": "9bf8c57e-5f65-4ed5-b504-21daa33248db",
"deploymentId": "f822f467-6a81-4cb7-bb90-ebe3b4224c30",
"createdAt": "2024-12-13T14:24:48.704645172Z",
"updatedAt": "2024-12-13T14:24:48.704645172Z",
"name": "Churn_predictions",
"dataSetId": "6749ddb8bf86ce46d48fe0a3",
"createdBy": "67475097984561d02f0cb3dc",
"ownerId": "67475097984561d02f0cb3dc",
"errorMessage": null,
"indexColumn": null,
"status": "ready",
"schedule": null,
"writeback": {
"spaceId": "6745f737f536738170dfe82f",
"format": "parquet",
"dstName": "customer_predictions.parquet",
"dstShapName": "customer_predictions_shap.parquet",
"dstSourceName": "customer_predictions_source.parquet",
"dstCoordShapName": "customer_predictions_coord_shap.parquet",
"dstNotPredictedName": "customer_predictions_not_predicted.parquet"
}
}
}
Once in ready
status, predictions are available in the specified space.
Next steps
- Verify that the predictions align with your expectations.
- Analyze SHAP values to understand which features had the biggest impact on the model’s decisions.
- If any prediction fails, review prediction errors and solve the issue.