Skip to navigation

Buy It Again Recommendations

View as Markdown

Recommend products a customer has bought before and may buy again in the next 30 days. This is a ranking decision for each user, not a prediction that a purchase will certainly occur.

Data and relationships

The example assumes a Kumo Engine graph and a 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 transaction extract from the same data as the snapshot for the history filter below. The filter uses only purchases at or before the prediction time.

Rank future purchases

This Python query asks Kumo Engine to rank items each user may purchase during the next 30 days. LIST_DISTINCT makes repeated purchases of an item one target item in a window. The query includes first purchases, so the next step selects the repeat candidates.

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. The prediction table selects users and the requested time; it does not train the model. For a live run, choose a time after the latest observed purchase. The returned ENTITY identifies a user, CLASS identifies an item, and SCORE orders candidate items for that user. A score is not a guaranteed purchase probability.

Keep previously purchased items

Use transactions, a pandas DataFrame from the graph’s source extract, to retain only user and item pairs purchased by the prediction time. This step is Python postprocessing; the predictive query itself does not enforce the repeat condition.

history = transactions.loc[
transactions["timestamp"] <= prediction_time, ["user_id", "item_id"]
].drop_duplicates()
repeat_candidates = (
ranked.merge(
history,
left_on=["ENTITY", "CLASS"],
right_on=["user_id", "item_id"],
how="inner",
)
.sort_values(["ENTITY", "SCORE"], ascending=[True, False])
[["ENTITY", "CLASS", "SCORE"]]
)

Each remaining row is a product the user previously bought, ranked by its score for a purchase in the next 30 days. You can use the rows to order a replenishment shelf or choose candidates for a message. RANK TOP 50 limits the general purchase candidates before the history filter runs, so a user may have fewer than 50 repeat candidates or none. A first purchase in the future window can be a training label, but it cannot pass the history filter for a buy again recommendation.