Recommenders

Five recommender algorithms, one catalog

Popularity, item-item CF, content-based, BPR matrix factorization and a hybrid, all ranking the same synthetic catalog for the same user — including what happens when the user is brand new.

6 min read recommender systemscollaborative filteringcold start

Every recommender interview eventually arrives at the same question: which algorithm would you use, and why? The answer is never one algorithm, and the reasoning is easier to show than to describe.

So here are five of them, ranking the same catalog for the same user, live.

The setup

Sixty items, forty users, a few hundred interactions. The catalog is synthetic and generated from a seeded random number generator, but not randomly: each item carries one or two topic tags and an intrinsic appeal, each user has a latent taste over tags, and interactions are sampled from taste × appeal.

That last detail is what makes the demonstration work. Because there is real latent structure, the algorithms genuinely disagree — and because appeal is baked in separately from taste, popularity is a real competitor rather than a straw man.

The last two users are deliberate cold-start cases: one with two interactions, one with none at all.

This section trains a matrix factorization model in your browser — it needs JavaScript.

What each column is doing

Popularity

Count interactions per item, sort descending, remove what the user has already seen. No personalization whatsoever.

It is on this page because it is the baseline that embarrasses people. Popular items are popular because many users liked them, which makes them a decent guess for a user you know nothing about. If your personalized model cannot beat popularity on a held-out set, you have not built a recommender — you have built an expensive popularity list with noise on top.

Item-item collaborative filtering

Represent each item by the column of users who interacted with it, then measure cosine similarity between those columns. To score a candidate for a user, average its similarity to everything already in that user’s history :

No training loop, no gradient, no hyperparameters beyond the similarity metric. It reacts to a new interaction the moment you add it, which is why it survives in production long after fancier models arrive. Its weakness is the long tail: an item nobody has touched has an all-zero column and is similar to nothing, so it can never be recommended.

Content-based

Build the user’s profile as the sum of the tag vectors of everything they have consumed, then rank candidates by cosine similarity to that profile.

This is the only column that can recommend an item with zero interactions, because it never looks at the interaction matrix on the item side. The cost is that it can only ever tell you more of the same — it has no mechanism for discovering that people who like this also like something with no tags in common.

Matrix factorization

The one that is actually training. Every user gets a vector , every item a vector , and the predicted affinity is their dot product .

Because the data is implicit — interactions, not ratings — squared error against a matrix of ones and zeros is the wrong objective. It would spend all its capacity explaining the zeros, most of which mean “never saw it” rather than “disliked it”. So this uses BPR, which optimizes a ranking objective instead: for a user , an item they interacted with and an item they did not, push above .

The widget runs 220 epochs of stochastic gradient descent over the observed pairs, sampling a negative for each one, and reports the wall-clock time it took. On this data it is a few tens of milliseconds. Drag the factor count and it retrains on release.

Watch what too few factors does: with two, the model cannot separate the topics and the recommendations drift toward the global average. Watch what too many does: it starts fitting individual quirks of the interaction log rather than the structure underneath it.

Hybrid

A normalized blend of the factor model and the content profile, with a small popularity term. This is what most production systems actually are, and the blend weight is the knob that decides whether the feed feels adventurous or safe.

Cold start, honestly

Select User 40 · brand new. Three columns go blank.

That is not a bug in the widget; it is the truth about those algorithms. Item-CF has an empty basket to sum over. The content profile is the mean of zero vectors. The factor model never saw this user in a single training pair, so their vector is still the random initialization it started with — and a dot product against random noise is noise, not a prediction.

That last one matters more than it looks. A matrix factorization implementation will happily return five confident-looking recommendations for a user it knows nothing about, because nothing in the code says stop. The scores will have plausible magnitudes. They will be sorted. They will be meaningless. Deciding to return nothing, and letting a fallback take over, has to be a decision somebody makes explicitly.

Now select User 39 · almost new, with two interactions. Everything comes back, and most of it is wrong in an interesting way: with two data points, item-CF and the content profile are both effectively recommending “more of these two things”.

The metric nobody looks at

The tail reach readout compares the mean popularity percentile of the popularity baseline’s top five against the hybrid’s. Zero percent means you are recommending the most popular items in the catalog; higher means you are reaching into the tail.

Personalization is supposed to move that number up. It frequently does not, because every component quietly pulls toward popular items: popular items have denser columns so item-CF finds them more similar to everything, and they appear in more training pairs so the factor model sees them more often. You can ship a sophisticated model, watch click-through rise, and still be showing everybody the same twenty items.

Drag the hybrid blend toward content and watch tail reach climb while the recommendations get less safe. That trade is the actual product decision, and no offline metric makes it for you.

What to take from this

The interesting question is not which algorithm wins. On this data the hybrid usually looks best, and on your data it might not.

The useful question is which failure mode you can live with. Popularity is never wrong and never useful. Item-CF is responsive but cannot touch the tail. Content-based reaches the tail but never surprises. Matrix factorization finds structure nobody labeled and falls apart the moment it meets someone new.

A production recommender is a routing decision between these, made per request based on how much you know about the user — not a single model that won an offline bake-off.