Recommender Systems
Learn how Netflix, Spotify, and Amazon decide what to show you — using cosine similarity, collaborative and content-based filtering, and the maths behind the Netflix Prize — and build a recommender by hand in plain Python.
Learn Recommender Systems in our free AI & Machine Learning course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a…
Part of the free AI & Machine Learning course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Picture the one friend who always nails movie night. Over the years they have learned what you love, so when they say "trust me, watch this," they are usually right. How do they do it? Two ways, really — and those two ways are the two big families of recommender systems.
Sometimes your friend reasons from the movie itself : "you loved the last gritty sci-fi thriller, this one is the same vibe." That is content-based filtering — matching an item's features to what you already liked. Other times they reason from people : "my colleague has the exact same taste as you, and she couldn't stop talking about this one." That is collaborative filtering — borrowing the verdict of users similar to you. The best friend (and the best system, like Netflix or Spotify) blends both.
A recommender system predicts which items you will like and shows you the best ones, usually as a ranked list. There are two core strategies, plus a hybrid that mixes them.
Represent a user as a rating vector — just a list of their scores: [5, 2, 5, 1, 4] . To compare two users, you compare their vectors. The favourite tool is cosine similarity : the angle between the two vectors.
The formula is the dot product (multiply matching positions and add them up) divided by the product of the two vectors' lengths. The result lands between 0 (nothing in common) and 1 (identical direction of taste).
Cosine measures direction , not magnitude. A generous rater who hands out 5s and a stingy rater who hands out 3s can still be a perfect match if they rank things the same way. Cosine sees that; raw distance would wrongly call them far apart.
The worked example below computes it from scratch — no NumPy, just math.sqrt and a loop. Read every comment, then run it.
Collaborative filtering ignores what an item is and looks only at the pattern of ratings. It comes in two flavours:
Find the people most similar to you , then recommend what they liked that you have not seen. Netflix's original approach. Intuitive, but users come and go and there can be millions of them, so it is hard to scale.
Find items rated alike and recommend ones similar to what you already enjoyed — "because you watched Inception." Amazon's approach. Items are more stable than users and their similarities can be precomputed, so it scales far better.
To predict a missing rating, take a similarity-weighted average of your neighbours' ratings: the more similar a neighbour, the more their opinion counts. The worked example fills in the gaps in a small rating matrix and recommends the single best unseen movie for one user.
The user-item rating matrix is huge and mostly empty — millions of users, thousands of items, and almost every cell blank. Comparing shared ratings directly falls apart when two users have barely any items in common. Matrix factorization is the fix that won the Netflix Prize.
The idea: every user and every item secretly lives in a small space of hidden factors — think invisible dials like "how much sci-fi", "how much romance", "how light vs dark". Factorization learns, for each user, how much they want each dial, and for each item, how much of each dial it has. A predicted rating is just the dot product of a user's dials with an item's dials.
Decompose the big rating matrix R into two skinny matrices — one row of factors per user, one row of factors per item — so that multiplying them back together reconstructs the known ratings and fills in the blanks. Those filled-in blanks are your predictions.
You do not implement the training loop here (it is gradient descent over those factors), but the mental model is the payoff: users and items share one hidden taste space, and a dot product scores any pair. That is the same dot product you already coded for cosine similarity.
A recommender hands the user a ranked list , and users only ever look at the top of it. So the right question is not "how accurate are all my predictions" but " how many of my top few were any good? "
precision@k answers exactly that: of the top k items you recommended, what fraction were genuinely relevant to the user? A precision@5 of 0.6 means 3 of your top 5 hit the mark. It is simple, it matches what the user experiences, and it is far more honest than overall rating error.
The worked example builds an item-item recommendation list ("because you watched Inception…") and then scores that list with precision@k for k = 1, 2, 3.
Collaborative filtering needs history. A brand-new user has rated nothing, and a brand-new item has been rated by nobody — so there is nothing to compare. This is the cold-start problem , and it is the single biggest reason a recommender feels useless on day one.
Now you try. Fill in the blanks marked ___ . Cosine similarity is the engine of every example above — finish it and you understand the whole lesson.
Your turn again. Score each unwatched movie against a taste profile and recommend the single best one.
These four mistakes trip up almost everyone building their first recommender:
A brand-new user has rated nothing, so collaborative filtering returns an empty or random list and the product feels broken on first use.
Blockbusters get rated by everyone, so they look "similar" to everyone and end up recommended to everyone. Niche items the user would love never surface.
✅ Fix: down-weight popular items (penalise by how often they are rated) and add a diversity term so the list is not just the global top 10.
A blank cell means "not rated", not "rated zero". Counting missing entries as 0 makes two users who simply have not overlapped look like they disagree.
✅ Fix: compare only positions both users actually rated.
Scoring your recommender on ratings it was trained on (or on items the user already interacted with) makes it look brilliant — then it flops on genuinely unseen items.
✅ Fix: hold out a test set of future or unseen interactions and measure precision@k only on those.
Time to fly with less scaffolding. The starter gives you a taste profile and three unwatched movies plus a comment outline — write the logic yourself. Reuse the cosine similarity you have built twice already.
Lesson 45 complete — you can now build a recommender from scratch!
You can compute cosine similarity by hand, run user-user and item-item collaborative filtering, recommend from item features with content-based filtering, explain the intuition behind matrix factorization, and grade a ranked list with precision@k. You also know the four traps: cold start, popularity bias, treating sparse data as zeros, and leakage in evaluation.
🚀 Up next: Graph Neural Networks — model relationships in social networks and knowledge graphs.
Practice quiz
What does a recommender system do?
- Trains language models
- Compresses images
- Predicts which items a user will like and surfaces the best ones, usually as a ranked list
- Encrypts user data
Answer: Predicts which items a user will like and surfaces the best ones, usually as a ranked list. Netflix rows, Amazon's 'customers also bought', and Spotify's Discover Weekly are recommender systems.
How does content-based filtering make recommendations?
- By matching an item's own features to items you already liked
- By copying what similar users liked
- By picking random items
- By only recommending the most popular item
Answer: By matching an item's own features to items you already liked. Content-based uses item features (genre, tags), so it needs no other users and avoids cold start for new users.
How does collaborative filtering differ from content-based filtering?
- It uses item features only
- It never uses ratings
- They are identical
- It ignores item features and finds patterns across users' ratings
Answer: It ignores item features and finds patterns across users' ratings. Collaborative filtering borrows the verdict of similar users or items, not the item's own features.
What is user-user collaborative filtering?
- Recommend items rated alike
- Find people whose taste matches yours and recommend what those neighbours liked
- Recommend by item genre only
- Recommend the newest items
Answer: Find people whose taste matches yours and recommend what those neighbours liked. User-user CF finds similar users and borrows their ratings to predict yours.
Why is item-item CF often preferred in production?
- Items are more stable than users and their similarities can be precomputed, so it scales better
- Items change more than users
- It needs no ratings
- It ignores similarity
Answer: Items are more stable than users and their similarities can be precomputed, so it scales better. Amazon's 'because you watched X' uses item-item CF; precomputed item similarities scale well.
What does cosine similarity measure between two rating vectors?
- Their total length
- The number of items rated
- The angle (direction) between them, from 0 (unrelated) to 1 (identical direction)
- The average rating
Answer: The angle (direction) between them, from 0 (unrelated) to 1 (identical direction). Cosine = dot product / (product of lengths); it compares direction of taste, ignoring rating scale.
Why is cosine similarity preferred over raw distance for ratings?
- It is faster to compute only
- It compares the direction of taste, so a generous and a stingy rater can still match if they rank things alike
- It always returns 1
- It ignores the dot product
Answer: It compares the direction of taste, so a generous and a stingy rater can still match if they rank things alike. Cosine focuses on direction, not magnitude, so differing rating generosity does not break the match.
What does matrix factorization do?
- Deletes the rating matrix
- Counts shared ratings only
- Sorts users alphabetically
- Decomposes the user-item matrix into smaller latent-factor matrices whose dot product predicts missing ratings
Answer: Decomposes the user-item matrix into smaller latent-factor matrices whose dot product predicts missing ratings. It learns hidden user and item factors; multiplying them fills in the sparse matrix (won the Netflix Prize).
What is the cold-start problem?
- A model that runs too slowly
- The difficulty of recommending for a brand-new user or item with no interaction history
- Too many ratings to process
- A divide-by-zero error
Answer: The difficulty of recommending for a brand-new user or item with no interaction history. With no history, collaborative filtering has nothing to compare; fixes include content-based fallback or popular items.
What does precision@k measure for a recommender?
- The training time
- The total number of users
- Of the top k recommended items, the fraction the user actually found relevant
- The average rating error across all items
Answer: Of the top k recommended items, the fraction the user actually found relevant. precision@5 of 0.6 means 3 of the top 5 were good; ranking metrics matter more than overall RMSE.