Chapter 4 · Part 2

Recommending movies

A prediction for one movie is nice. A recommendation is the natural next step: predict every movie a user hasn't seen, sort by predicted rating, and hand back the top few. That's the whole product.

Score every blank, then rank

recommender.py (continued)
def recommend(user, n=3):
  unseen = np.where(~seen[user])[0]                  # movies not yet rated
  scored = [(movies[i], predict(user, i)) for i in unseen]
  scored.sort(key=lambda pair: pair[1], reverse=True)  # best first
  return scored[:n]

Recommend for Alice

recommender.py (temporary test)
for title, score in recommend(0):   # Alice is user index 0
  print(f"{score:.2f}  {title}")
4.07  Interstellar
1.55  Love Actually

There it is — a working recommender. Alice's top pick is Interstellar, the sci-fi film she happened to miss, scored well above the rom-com. We never wrote a rule about genres; the ranking came entirely from "people with your taste loved this."

It's personalized — really

The proof that this isn't a fixed "popular movies" list: run it for someone with the opposite taste and the recommendations flip completely.

recommender.py (temporary test)
print("For Alice:", recommend(0, n=1))   # sci-fi fan
print("For Dave: ", recommend(3, n=1))   # rom-com fan
For Alice: [('Interstellar', 4.07)]
For Dave:  [('Pretty Woman', 4.26)]

Same code, same data — but the sci-fi fan is steered to Interstellar and the rom-com fan to Pretty Woman. Each person's recommendations come from their own neighborhood of similar users. That's collaborative filtering working end to end. Next, a different angle on the same idea — one that can explain why.