Case 04 / Recommendation systems · Machine learning
What belongs in the next grocery order?
A personalized grocery recommendation engine that combines repeat-purchase prediction with new-item discovery. XGBoost scores familiar products, while similar customers and products bought together supply unseen candidates for a separate discovery model. The output keeps accepted repeats first and adds at most two clearly labeled discoveries.
- XGBoost
- Logistic Regression
- Random Forest
- CatBoost
- Cosine Similarity
- Co-basket Retrieval
- Polars
- Scikit-learn
- 01 / HISTORYBuild purchase signalsFrequency, recency, replenishment intervals, and category preferences
- 02 / REPEATScore familiar productsEstimate next-order reorder probabilities and apply a 0.5 cutoff
- 03 / DISCOVERYRank unseen candidatesSimilar customers, co-basket links, popularity, and a separate classifier
- 04 / DISPLAYKeep the labels clearUp to five suggestions, with at most two labeled Discovery items
- Labeled next orders
- 131,20949,688 products in the catalog
- Displayed repeat precision
- 63.92%0.5 cutoff · 19,682 test customers
- Discovery display limit
- Up to 2within five total suggestion positions
Which familiar products should return, and what could be new?
Grocery recommendations have two different tasks: anticipate repeat purchases and suggest products a customer has never bought. The project gives each task its own candidate pool and learned scorer, then combines their outputs with a simple display policy.
Previously purchased products need an estimated reorder probability of at least 0.5 to appear. Up to two unseen products can fill remaining positions. Three accepted repeats allow two discoveries; four allow one; five allow none. With no accepted repeats, the output contains at most two discoveries.
Predict one complete next order.
The Instacart data contains 3,214,874 prior orders, 32,434,489 prior product rows, 131,209 labeled next orders, and 75,000 unlabeled next orders. The catalog has 49,688 unique products.
A repeat candidate is a product the customer has bought before. Its label is 1 if it appears anywhere in the next order and 0 otherwise. Only completed histories and product metadata are inputs: the next basket's contents, size, day, hour, and elapsed time are excluded.
The display has up to five positions, but the prediction horizon is the entire next order, regardless of its size. A product bought only in a later order does not count as a hit in this evaluation.
Separate the repeat decision from discovery ranking.
Repeat prediction
A 600-round XGBoost binary classifier, with depth 6 and learning rate 0.05, uses 22 numeric features. These describe order and basket history, customer-product frequency and recency, recent purchases, typical replenishment intervals, global prior-order product behavior, and aisle and department preferences.
Candidates are ranked by estimated next-order reorder probability. Up to five products meeting the 0.5 cutoff are retained. Purchase frequency, logistic regression, random forest, and CatBoost were also compared; the repository records their controlled benchmarks.
New-item discovery
Recency-weighted sparse purchase vectors identify 50 similar customers using cosine similarity. Their purchases, a graph of products bought together in completed baskets, and popular unseen products supply up to 80 discovery candidates per customer. All previously purchased products are excluded.
A separate 350-round XGBoost classifier ranks these candidates using customer preferences, product behavior, and retrieval scores and support. The discovery model was developed on a 10,000-customer pilot. Its scores are not calibrated purchase probabilities, so Discovery rows do not receive the repeat model's probability label or cutoff.
Evaluation protocol
The full-data split holds customers together: 91,846 training, 19,681 validation, and 19,682 test customers. Validation is divided into 9,840 customers for selecting boosting rounds and 9,841 for decision-cutoff analysis. A separate deployment repeat model is refitted on all labeled customers; reported test results come from the evaluated model.
The discovery pilot samples from the original training population, with 7,000 fit, 1,500 validation, and 1,500 test customers. Its selected classifiers are refitted on fit plus validation customers before pilot-test scoring.
Higher precision with fewer suggestions.
At the 0.5 cutoff, precision counts matches among products actually displayed. Recall counts matches among all actual repeat products, aggregated across customers. These metrics describe the repeat portion of the output.
| Metric | Decision validation | Established test |
|---|---|---|
| Customers | 9,841 | 19,682 |
| Displayed repeat precision | 64.06% | 63.92% |
| Recall of actual repeat products | 14.91% | 14.84% |
| Repeat F1 | 24.20% | 24.08% |
| Suggestions shown | 14,389 | 28,734 |
| Next-order matches | 9,218 | 18,368 |
| Repeats shown per customer | 1.46 | 1.46 |
| Customers receiving a repeat | 58.37% | 59.07% |
Returning fewer products improves precision while reducing coverage: 40.93% of test customers receive no repeat suggestion at this cutoff. The 63.92% result does not describe the combined Repeat + Discovery list.
Higher cutoffs were also documented. Test repeat precision reaches 70.88% at 0.6 and 81.42% at 0.75, while suggestions per customer fall to 0.86 and 0.24 respectively. The README includes the full threshold comparison and reproduction commands.
Additional matches, with a weaker purchase signal.
The combined policy was evaluated using matched predictions for the same 1,500 pilot-test customers, with 350-round pilot models and a 0.5 repeat cutoff.
| Metric | Repeats only | Repeats + up to two discoveries |
|---|---|---|
| Overall displayed precision | 61.47% | 30.18% |
| Repeat portion precision | 61.47% | 61.47% |
| Discovery portion precision | — | 3.08% |
| Repeat matches | 1,385 | 1,385 |
| Discovery matches | 0 | 80 |
| Total matches | 1,385 | 1,465 |
| Suggestions per customer | 1.50 | 3.24 |
Discovery retained every accepted repeat and added 80 next-order matches. Its lower purchase rate reduced precision across the combined list. A separate five-new-items benchmark achieved 2.41% Precision@5, compared with 2.11% for retrieval ordering alone.
These results do not evaluate the full-data deployment repeat model combined with the discovery model. Discovery remains an experimental component. Louvain product grouping was tested too, but its candidate retrieval underperformed the selected similarity, co-basket, and popularity pool.
Purchase matching is one measure of usefulness.
About 40.4% of next-order products in the established full-data test benchmark were new to the customer. Repeat prediction cannot cover those products, and discovery currently captures only a small fraction of new purchases. A relevant suggestion bought in a later order is also a miss under this next-order target.
The test splits have been inspected during development, so they are established offline benchmarks rather than untouched confirmation sets. Global repeat features use the available prior-order corpus, including validation and test customer histories but no hidden next-order labels; this is a transductive evaluation.
The dataset lacks exact calendar dates, prices, promotions, inventory, recommendation impressions, and live customer feedback. Days between orders are capped at 30. Offline matches cannot show whether recommendations cause purchases or increase sales.
The repository includes the training pipeline, 26 passing tests, methodology, model comparisons, discovery experiments, and saved reports. The system is available as a local command-line application.