All 1,371,980 requested customer rows received a complete top-12 list.
H&M Personalized Fashion Recommendations
Every one of twelve slots has to earn its place.
A full-scale retrieval-and-ranking system that turns 31.8 million purchases into a personalised top-12 recommendation list for every customer.
The product
decision
The surface area is deceptively small: recommend twelve fashion articles that a customer is likely to buy next. The hard part is that a model cannot rank a useful article if it never makes the candidate pool.
I treated this as a product-system problem, not a one-model shootout: retrieve a compact but diverse set of plausible articles, rank them with time-safe signals, and verify that the final output works for every customer—including cold-start customers.
Product metrics
Would the experience work for every customer?
MAP@12 measures offline ranking relevance. Product health also depends on whether every customer can receive a useful, complete, and valid recommendation set—including people with no prior purchase history.
Customers without purchase history still received a cutoff-valid recommendation set.
Every row contained twelve unique, active, zero-padded article IDs.
A bounded, personalised pool keeps the experience relevant without ranking the full catalogue.
Did the ranked list recover articles purchased in the following week?
Did every customer receive twelve eligible recommendations without malformed output?
In production, a randomized control group separates real incremental impact from raw engagement.
If launched: product measurement plan
From relevance signals to customer and commercial value.
These are proposed production metrics, not results from this offline batch. Incrementality would be established against a control experience, alongside the guardrails that keep the experience useful and trustworthy.
Did recommendations create value beyond the normal shopping experience? Measure the lift per exposed customer against a control.
Are customers acting on recommended items before purchase happens?
Can the system reliably serve a useful set to every eligible customer?
Are suggestions relevant without becoming repetitive, overly narrow, or unwelcome?
Is the experience creating healthy value rather than shifting poor-quality demand?
Do useful recommendations encourage customers to return after the current visit?
How I would read the resultsMAP@12 remains the offline relevance proxy. Compare eligible customers who see recommendations with a randomized control, then interpret add-to-bag, conversion, margin, and 30-day retention alongside return, stock, and diversity guardrails.
System at a glance
Coverage first. Ranking second.
- 01Purchase history
31.8M transactions, customer attributes, and product metadata.
- 02300 candidates
17 complementary retrieval signals compete for a finite candidate budget.
- 0343 features
Recency, popularity, source evidence, similarity, affinity, and product context.
- 04Top 12
A frozen model ranks each pool and a verified output renderer closes the loop.
Candidate
diversity
Candidate diversity is not random variety. It means each retrieval path should add likely future purchases that the other paths missed—rather than returning the same popular articles again and again.
Repeat & recency
Articles the customer has bought before, weighed by how recently they appeared.
Similarity & variants
Item-to-item CF, product-code alternatives, and item-graph neighbours.
Trend & context
Short-window popularity, age signals, department and section affinity.
Category intent
Product-type affinity that broadens the pool beyond the obvious repeats.
The full system uses 17 named sources across these four retrieval families, then preserves source evidence as features for ranking.
How the model
was chosen
LightGBM, XGBoost, and CatBoost were trained on the full candidate pool. I compared them and rank-based blends on chronological out-of-fold weeks, never by mixing future purchase labels into an earlier decision.
It was the most reliable historical choice. Pairwise and three-way rank blends—including a 50/50 XGBoost + CatBoost mix—were tested, but none cleared the stability guardrails consistently enough to replace it.
The final week was evaluated once retrospectively. XGBoost was narrowly higher in that single week, but the serving choice stayed frozen. That separation matters: it prevents a good-looking last result from becoming a hidden tuning input.
| Model | Retrospective MAP@12 | Interpretation |
|---|---|---|
| LightGBM | 0.035425 | Frozen serving model |
| XGBoost | 0.035447 | Retrospective only |
| CatBoost | 0.035241 | Retrospective only |
Verified early model screen
Behaviour beat complexity before the full production run.
Before the later full-population ranking work, I evaluated a seven-family model ladder on a versioned 1,000-customer temporal screen: history through 15 September 2020, then MAP@12 against purchases in the following week.
It reached MAP@12 0.021996, a 2.16× lift over popularity at 0.010177. The more elaborate LightGBM LambdaRank experiment scored 0.004104, so it remained an experiment—not the default serving choice.
| Model family | MAP@12 | Lift | What it showed |
|---|---|---|---|
| Repeat purchase | 0.021996 | 2.16× | Best score; a strong behavioural baseline |
| Content affinity | 0.021599 | 2.12× | Close second through product preferences |
| Item-to-item co-purchase | 0.014222 | 1.40× | Recent-basket similarity |
| LightFM | 0.010712 | 1.05× | Metadata-aware collaborative scorer |
| Popularity | 0.010177 | Baseline | Recent global purchase windows |
| ALS | 0.008072 | 0.79× | Implicit-feedback factorisation |
| LightGBM LambdaRank | 0.004104 | 0.40× | Candidate-ranker experiment |
This is a transparent model-ladder screen, not a fixed-candidate-pool contest: every family shares the time boundary and customer cohort, but its candidate generator can differ. The page therefore keeps this result separate from the later V5 model-selection table above.
Product captures
From ranking evidence to a usable shopping surface.
The prototype turns the evaluation work into two product surfaces: intent-aware discovery and a personalised browse experience. These captures use aggregate catalogue and historical-purchase artifacts only.


No customer names, contact data, or raw customer identifiers are shown.
Production-style
inference
The final run used a 22 September 2020 serving snapshot. It treated that date’s transactions as observed history only—not as labels—and did not read the held-out validation cache while creating recommendations.
The deliverable is a competition-format, batch-inference artifact—not a claim of a live consumer product or a Kaggle submission.
What I learned
The next gain is more likely to come from a better candidate budget than another model.
The next experiment is to quantify each path’s marginal future-purchase recovery, tune its quota on historical windows, freeze that policy, and then compare it fairly. There is no permanent “perfect mix”—only a disciplined way to choose one for a specific customer population and moment in time.