Skip to navigation

Try Something New

View as Markdown

Recommend items with no recorded purchase by a user that the user may buy in the next 30 days. This is a product discovery ranking for each user. The predictive query ranks future purchases; a history filter makes the displayed candidates new within the available purchase history.

Data and relationships

The example assumes a Kumo Engine graph and matching snapshot with these tables:

TableRequired columnsPurpose
usersuser_id as the primary keyDefines the users to score.
itemsitem_id as the primary keyDefines the product candidates.
transactionsuser_id, item_id, timestampRecords purchases and their times.

Connect transactions.user_id to users.user_id and transactions.item_id to items.item_id. Mark transactions.timestamp as the time column. Keep a transactions pandas DataFrame from the same source extract as the snapshot so the history filter uses purchases known at the prediction time.

Rank purchases in the next 30 days

This Python query asks Kumo Engine to rank items each user may purchase during the next 30 days. LIST_DISTINCT makes repeat purchases of one item a single target item within a window. Its training labels can include both first and repeat purchases.

from datetime import datetime
from kumo.engine import PredictiveQuery
query_text = (
"PREDICT LIST_DISTINCT(transactions.item_id, 0, 30, days) "
"RANK TOP 50 FOR EACH users.user_id"
)
query = PredictiveQuery(graph, query_text)
query.validate()
print(query.get_task_type()) # temporal_link_prediction
prediction_time = datetime(2024, 4, 30) # Replace with your chosen UTC time.
prediction_table = query.generate_prediction_table(
snapshot, prediction_time=prediction_time
)
ranked = trainer.predict(
prediction_table, snapshot=snapshot, num_classes_to_return=50
).frame

Here trainer is a fitted model for this query. For a live run, choose a prediction time after the latest observed purchase. ENTITY identifies a user, CLASS identifies an item, and SCORE orders candidates for that user. A score is not a guaranteed purchase probability.

Keep only items new to each user

Exclude user and item pairs with a purchase at or before prediction_time. This is Python postprocessing on ranked, not a constraint in the predictive query.

history = transactions.loc[
transactions["timestamp"] <= prediction_time, ["user_id", "item_id"]
].drop_duplicates()
new_candidates = (
ranked.merge(
history,
left_on=["ENTITY", "CLASS"],
right_on=["user_id", "item_id"],
how="left",
indicator=True,
)
.loc[lambda rows: rows["_merge"].eq("left_only"),
["ENTITY", "CLASS", "SCORE"]]
.sort_values(["ENTITY", "SCORE"], ascending=[True, False])
)

Each remaining row is a product with no recorded purchase by that user as of the prediction time, ranked for a purchase in the next 30 days. Use the rows to order a discovery shelf or choose candidates for a message. Check product availability separately before showing an item. Because RANK TOP 50 limits candidates before this filter runs, a user may have fewer than 50 new items or none. The query does not guarantee that a new item will be purchased.