Skip to navigation

Personalized Email Recommendations

View as Markdown

Choose products to feature in an email for each customer who can receive the campaign. The predictive target is an item the customer may purchase in the next 14 days. Kumo Engine ranks possible purchases; your current customer and catalog data determine which ranked items can appear in the email.

Data and relationships

This example assumes a prepared Kumo Engine graph, a matching snapshot, and these tables:

TableRequired columnsPurpose
usersuser_id as the primary key, email_opt_inDefines customers and their current email eligibility.
itemsitem_id as the primary key, email_featuredDefines products approved for this campaign.
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. The users and items pandas DataFrames below must reflect the campaign decision time. Their eligibility columns are campaign rules applied after ranking, not predictions made by Kumo Engine.

Rank purchases for the campaign window

This Python query ranks items each customer may purchase within 14 days after prediction_time. LIST_DISTINCT makes repeated purchases of one item a single target item in that window. It does not restrict the prediction population to customers who opted in.

from datetime import datetime
from kumo.engine import PredictiveQuery
query_text = (
"PREDICT LIST_DISTINCT(transactions.item_id, 0, 14, days) "
"RANK TOP 12 FOR EACH users.user_id"
)
query = PredictiveQuery(graph, query_text)
query.validate()
print(query.get_task_type()) # temporal_link_prediction
prediction_time = datetime(2024, 5, 1) # UTC in the source extracts.
prediction_table = query.generate_prediction_table(
snapshot, prediction_time=prediction_time
)
ranked = trainer.predict(
prediction_table, snapshot=snapshot, num_classes_to_return=12
).frame

Here trainer is a fitted model for this query. Replace the example time with a UTC campaign decision time after the latest observed purchase. In ranked, ENTITY identifies a customer, CLASS identifies an item, and SCORE orders the returned candidates for that customer. The score is not a guaranteed purchase probability.

Select customers and products for the email

Apply the current email eligibility and campaign catalog rules to the ranked rows. These pandas filters are outside the predictive query. Use the same user_id and item_id types as the graph tables.

eligible_users = users.loc[users["email_opt_in"].eq(True), ["user_id"]]
featured_items = items.loc[items["email_featured"].eq(True), ["item_id"]]
campaign_candidates = (
ranked.merge(eligible_users, left_on="ENTITY", right_on="user_id", how="inner")
.merge(featured_items, left_on="CLASS", right_on="item_id", how="inner")
.sort_values(["ENTITY", "SCORE"], ascending=[True, False])
[["ENTITY", "CLASS", "SCORE"]]
)

Each remaining row is an allowed item candidate for one currently eligible customer, ordered for a possible purchase in the next 14 days. Use the rows to select product cards for that campaign. Recheck permission and product availability against the authoritative systems before sending, since either can change after scoring. The query can generate rows for customers who cannot receive email, and the filters can leave a customer with fewer than 12 items or none. This example does not claim that the model predicts email opens or that sending the email causes a purchase.