Skip to navigation

Predictive Query

View as Markdown

Use a predictive query to state what you want to predict and which entities to score. A number, a yes-or-no outcome, a category, and a ranked set of items answer different questions even when they use the same tables. These examples help you choose that task shape, validate it in Python, and understand what its predictions mean.

Data and relationships

The examples assume a prepared Kumo Engine graph with the following retail data. Replace the names with those in your graph. You need only the tables and relationships used by the example you choose.

TableRequired data and role
customerscustomer_id primary key and numerical age. One row per customer. Age can be missing.
itemsitem_id primary key. One row per product.
preferencespair_id primary key; customer_id, item_id, numerical rating, and Boolean likes. One row per customer and item pair to score. A rating or like can be missing.
purchasespurchase_id primary key; customer_id, item_id, purchased_at, numerical amount, and categorical channel. One row per purchased item, with its amount and a channel such as online or store.

Connect both preferences.customer_id and purchases.customer_id directly to customers.customer_id. Connect both item identifiers directly to items.item_id. Mark purchases.purchased_at as the purchases time column. The other tables have no designated time column.

The examples validate query definitions; they do not fit a model or generate model predictions. Run this import before the example you choose:

from kumo.engine import PredictiveQuery
QuestionTask shape
What is an unknown customer attribute?Regression on an entity.
How would a customer rate or like a particular item?Regression or binary classification on an explicit pair.
How much will an active customer spend?Regression over a future window.
Will an active customer stop purchasing?Binary classification over a future window.
Which channel will a customer’s next purchase use?Multiclass classification over a future window.
Which items will a customer buy in qualifying purchases?Temporal link prediction.

Estimate a customer attribute

Predict a numerical value on the customer row, such as an unknown age. Customers with known ages supply the training labels. The default prediction population contains customers with missing ages. The prediction is an estimated number for each customer you score.

query_text = "PREDICT customers.age FOR EACH customers.customer_id"
query = PredictiveQuery(graph, query_text)
query.validate()
print(query.get_task_type()) # regression

Score an explicit customer and item pair

Use the preferences table when the question concerns a specific pair already represented in your data. A numeric rating expresses a degree of preference, such as a rating from 1 to 5. The output is an estimated rating for each scored pair_id.

query_text = (
"PREDICT preferences.rating FOR EACH preferences.pair_id"
)
query = PredictiveQuery(graph, query_text)
query.validate()
print(query.get_task_type()) # regression

For a yes-or-no preference, compare the Boolean likes column with true. The output expresses the probability that the scored pair is liked. Use a Boolean literal here because the column contains true, false, or a missing value, rather than integer labels.

query_text = (
"PREDICT preferences.likes = true FOR EACH preferences.pair_id"
)
query = PredictiveQuery(graph, query_text)
query.validate()
print(query.get_task_type()) # binary_classification

Known ratings and likes supply labels for their respective tasks; missing labels do not become negative examples. These queries score existing pair rows. They do not enumerate every possible customer and item combination. By default, prediction row generation selects pairs whose target rating or like is missing.

Forecast an active customer’s spending

Predict the sum of purchase amounts over the next 30 days. The trailing WHERE keeps customers who purchased in the preceding 30 days, so the decision concerns recently active buyers. A historical window with no future purchases has a target of zero.

query_text = (
"PREDICT SUM(purchases.amount, 0, 30, days) "
"FOR EACH customers.customer_id "
"WHERE COUNT(purchases.*, -30, 0, days) > 0"
)
query = PredictiveQuery(graph, query_text)
query.validate()
print(query.get_task_type()) # regression

The prediction is expected revenue per eligible customer in the amount column’s currency. Remove the trailing WHERE clause if you want to estimate spending for all customers. This is revenue over a chosen horizon, not a claim about a customer’s entire lifetime.

Predict whether an active customer will stop purchasing

Keep the same recent-buyer population, but ask whether the next 30 days will contain no purchases. The comparison with zero turns a count into a yes-or-no target.

query_text = (
"PREDICT COUNT(purchases.*, 0, 30, days) = 0 "
"FOR EACH customers.customer_id "
"WHERE COUNT(purchases.*, -30, 0, days) > 0"
)
query = PredictiveQuery(graph, query_text)
query.validate()
print(query.get_task_type()) # binary_classification

A higher churn probability means a greater estimated chance of no purchases during the next 30 days. It does not mean that the customer has already stopped buying permanently. Adjust the recent-activity and future windows to match your purchase cycle.

Predict the next purchase channel

Predict the channel of the first purchase in the next seven days. FIRST selects one future purchase’s channel, so this task distinguishes categories such as online and store.

query_text = (
"PREDICT FIRST(purchases.channel, 0, 7, days) "
"FOR EACH customers.customer_id"
)
query = PredictiveQuery(graph, query_text)
query.validate()
print(query.get_task_type()) # multiclass_classification

Historical windows with no purchase have no first channel and supply no training label. The prediction therefore describes which channel the next purchase would use, conditional on a purchase occurring in that window. It does not estimate whether the customer will purchase. A customer with no future purchase can still be in the scoring population.

Rank items from qualifying purchases

Rank items a customer is likely to buy in purchases with an amount greater than 100 over the next 30 days. The filter inside LIST_DISTINCT selects qualifying purchase events, while LIST_DISTINCT counts each item once in the target even if it appears in several qualifying purchases.

query_text = (
"PREDICT LIST_DISTINCT(purchases.item_id "
"WHERE purchases.amount > 100, 0, 30, days) "
"RANK TOP 10 FOR EACH customers.customer_id"
)
query = PredictiveQuery(graph, query_text)
query.validate()
print(query.get_task_type()) # temporal_link_prediction

The prediction ranks candidate items for each customer by the modeled purchase relationship. It is link prediction because the target is an item identifier connected to the customer. The amount filter changes the historical targets; it does not guarantee that every candidate has a current catalog price greater than 100. Apply catalog eligibility rules separately when choosing items to display. Removing the in-aggregation WHERE makes the target include purchases of any amount.

Choose a prediction time

For the forward-looking examples, the window starts at a shared scoring time because the customers table has no time column. A window from zero to 30 days excludes purchases at the exact scoring time and includes purchases through 30 days later. The seven-day window follows the same convention. The recent-buyer filter uses purchases after 30 days before the scoring time, through the scoring time itself.

Choose that time explicitly when generating a prediction table for the selected temporal query:

from datetime import datetime
# Replace with your chosen UTC time.
prediction_time = datetime(2024, 8, 1, 12)
prediction_table = query.generate_prediction_table(
snapshot, prediction_time=prediction_time
)

Here snapshot is the prepared snapshot for your graph. The prediction table selects the entities and scoring time for a fitted model to use; it contains no model scores by itself. Keep the query, fitted model, snapshot, and intended scoring population aligned when continuing to prediction.