Retail and consumer goods
Predict repeat purchase, recommend the next product from basket history, and plan replenishment from sales velocity.
Data mapping
- Entity
- customer
- Group
- store or channel
- Profile
- retail
Supported analyses
- Will this customer place another order within 60 days?
predict_event(target="order", window_days=60)
Order Type contains order or return. Returns carry negative values and are not counted as purchases. - What is the expected value of the next order?
predict_value(target="order", window_days=60)
Reference implementation
from datetime import datetime, timedelta
from vertiq import plugins, rules
from vertiq.mapping import Mapping, apply, repair
from vertiq.tasks import predict_event, predict_value
# rows: the source export as a list of dicts, e.g. list(csv.DictReader(open("export.csv")))
mapping = Mapping.parse({"entity": "Customer ID", "time": "Order Date", "type": "Order Type", "value": "Order Value", "group": "Store", "attrs": ["Category", "Coupon"], "date_format": "%Y-%m-%d"})
m, notes = repair(mapping, rows) # validates column names, value types and date format against the rows
ds, problems = apply(m, rows) # rows that fail to load are reported, not imputed
@plugins.feature("retail")
def return_rate(entity, before, cut): # receives only events recorded before the cutoff
orders = [e for e in before if e.type == "order"]
returns = [e for e in before if e.type == "return"]
return {"return_share": len(returns) / max(1, len(orders))}
task = predict_event(ds, target="order", window_days=60, pack="retail")
print(task.status, task.report()) # "trained" only if the model outperformed the baseline on held-out entities
if task.status == "trained":
print(task.score("C-88213")) # probability with contributing factors
size = predict_value(ds, target="order", window_days=60, pack="retail")
print(size.status, size.report())
flags = rules.run(ds, [
rules.repeat(1, type="return"), # two returns by the same customer on one day
])
print(flags["summary"])
This code is executed by the test suite (tests/test_guides.py) against generated records with these column names.
Recommended plugin
return_rate: Customers with a high return rate purchase differently. Returns are recorded as a separate event type.
Validation rules
rules.repeat(1, type="return"): two returns by the same customer on one day
Related modules
affinity: co-purchase associations and the next likely product per customersequences: category sequences with their typical lag, such as one category followed by another three weeks laterinventory: reorder points from sales velocity and lead time, slow-moving stock and marginsuplift: expected response to a campaign, estimated from control groups
Implementation notes
- Train only on customers with documented consent. Scoring existing customers is handled separately from training.
- Purchasing behaviour is seasonal. A retrained model replaces the production model only if it performs better on held-out customers.
Validation
- Customer retention and intervention uplift benchmarks, 5 runs each
- Retail sales tables, a domain excluded from Vertiq LM training
- Every deployment: the evaluation gate measures each model on the organisation's own held-out records before promotion.