Retention, Engagement, And Trial Reporting
The payment-history workflow combines account context, repeated transactions, and later outcomes. The account model adds several levels of context and targets. Once that pattern is familiar, apply it to a retailer’s purchase histories and customer retention decisions.
The review and study-reporting examples later on this page are optional applications to other event domains. Each keeps attributes at the root, related records in a branch, and a target describing a later outcome.
Retail: Who Will Make No Purchase Next Week?
A retail team can rank recently active customers by their estimated chance of making no purchase next week, then choose whom to contact. Whether that contact changes purchasing requires a separate intervention evaluation.
Define the population as customers who bought something in the preceding seven days. For each customer, predict inactive_next_7_days: true when there is no purchase after the decision time through seven days later. This gives the team a specific measure of short-term inactivity.
Customer attributes describe the person. Their purchase history describes interactions: which articles they bought, through which channels, and when they were booked. Your application joins those records and keeps only information available at the decision time before supplying the observation to RelFlow.
One Illustrative Observation
At the May 28, 2026 decision, a training observation contains customer attributes and purchases booked by that date. The root Boolean records customer inactivity during the seven days after that common snapshot cutoff and is attached once that window has completed:
customer_age: 34
club_member_status: ACTIVE
recent_purchases:
- booked_at: "2026-05-22T10:00:00"
article_id: article-17
amount: 32.00
sales_channel: online
- booked_at: "2026-05-26T17:30:00"
article_id: article-03
amount: 56.20
sales_channel: store
inactive_next_7_days: trueDescribe The Customer And Their Purchases
import relflow as rf
model = rf.Model.sm(
customer_age=rf.Number,
club_member_status=rf.Category,
recent_purchases=rf.Branch(
length=32,
overflow="tail",
booked_at=rf.DateParts(
dateparts=["day_of_month", "day_of_week", "hour_of_day"],
),
article_id=rf.Category,
amount=rf.Number,
sales_channel=rf.Category,
),
inactive_next_7_days=rf.Boolean(mask=True),
)The customer is the subject of the prediction; each purchase keeps its own article, amount, channel, and booking date together. Supply purchases oldest to newest so the branch retains the most recent 32. Choose that capacity for the history your application needs. mask=True keeps the later outcome out of the inputs while using it as supervision. This customer target is always masked, so omit it when requesting a new prediction. DateParts represents recurring calendar patterns; it does not supply elapsed time since a purchase. Retain customer identifiers and decision times in your application to associate the result with the right customer snapshot.
A table containing days since the last purchase, purchase counts, spending totals, and channel counts is a sensible baseline. Keeping individual purchases gives the model access to combinations of article, amount, channel, and timing that those summaries may omit. Compare both approaches on later decision windows with the same eligible customers and available evidence. Use relational context when that comparison justifies its preparation and processing cost.
Train And Predict From Parquet Files
Prepare your application’s training and validation files with one customer observation per row and the fields above. Use earlier decision windows for training and later windows for validation:
data = rf.ArrowDataModule(
model=model,
train="retention/train.parquet",
validate="retention/validation.parquet",
)
model.fit(data, batch_size=128, max_epochs=20)For new decisions, prepare the same customer attributes and purchase history in a request file, omitting inactive_next_7_days:
requests = rf.ArrowDataModule(
model=model,
predict="retention/requests.parquet",
)
predictions = model.predict(datamodule=requests, batch_size=256, devices=1)Prediction Output explains how to read the result under predictions.inactive_next_7_days in output format 2. The schema address remains /inactive_next_7_days.
Engagement: Will An Active Reviewer Stop Posting?
A team seeking fresh product feedback can use the same structure to anticipate review inactivity. Choose customers who posted a review in the preceding 91 days, and define the target as no review during the following 91 days.
Customer attributes stay at the root. Earlier reviews form the history, keeping each product, rating, and review date together. This outcome measures participation in a feedback channel: a customer can keep buying without posting a review. Compare a richer review history with review recency and frequency summaries before using it to prioritize invitations for feedback.
Clinical Studies: Which Studies Will Report Larger Totals?
A trial operations team may want to anticipate which ongoing studies will report larger totals of affected subjects. For studies that have already started, define a 365-day outcome: the sum of subjects_affected in reports marked serious or deaths that arrive after the decision time through 365 days later.
Study attributes provide the root context. Earlier reports form a branch, keeping report type, affected-subject count, and report date together. The later total is a masked numeric target. This sum can count a person in more than one report, so it does not measure unique affected people or an individual’s risk. Define how incomplete reporting affects label availability; a missing report does not establish a zero total.
Keep The Decision Time In Every Example
Construct every observation as it could have been seen at its decision time. An event that happened earlier but was reported later is unavailable until its report arrives. Mutable customer or study attributes also need values known at that time. Attach labels from the specified future window, and allow that window to finish before treating them as observed outcomes.
The same entity can appear at several decision times. Keep later evaluation windows separate and control overlap between their label periods and training examples. Evaluation explains the comparison; Preprocessing covers preparing the nested inputs.
After defining the observations, you can test reconstruction pretraining on the available histories or evaluate frozen representations for several outcomes from the same evidence. Each application needs its own schema, completed labels, and held-out comparison.