Skip to content

Machine learning

Book recommender

Pick a book you liked and get ten more. It learned from 280,669 interactions of readers with 2,405 books in the Book-Crossing data. I built the first version by hand in 2025 and the second with Claude Code in 2026: I set the goals, reviewed every change and checked every number. Switch between them to see the difference.

The code on GitHub (opens in a new tab)How v2 was measured (opens in a new tab)v1’s report (PDF) (opens in a new tab)

Try it

Loading 2,405 books…

How well it recommends

Every version was tested the same way. A fifth of each of 2,271 readers’ ratings was held back; a version scores a hit when one of the ten books it recommends to a reader is a held-back book they rated 4 or more out of 10. NDCG also rewards ranking that book higher. v2 finds one for 48.4% of readers.

VersionReaders with a hitNDCG@10Books ever recommended
Most popular books16.3%0.0332.1%
v1 as shipped (user-based CF)28.3%0.08782.0%
v1's API table (dot product)30.7%0.08819.3%
Stage 2: cosine table, clean books28.0%0.09270.2%
Stage 3: EASE, all interactions46.5%0.16254.8%
v2: blend of EASE, RP3beta and text48.4%0.17360.0%

How it was built

v1 · 2025 · by hand

Exploratory analysis of the data; user- and item-based collaborative filtering and a content-based model, in notebooks; a FastAPI service on Fly.io; a 30-page report. Kept exactly as it was, at tag v1.0 (opens in a new tab).

v2 · 2026 · with Claude Code

  1. 1. Measure

    Re-ran v1 from its own code and got every number it had published. Its rating errors came from an averaging bug, while its user-based model, as shipped, ranked books best of its models.

    The report (opens in a new tab)
  2. 2. Clean

    v1 told books apart by their exact title, so editions were different books and different books with one title were one. Identified properly, its 2,508 books are 2,405, each with its details from Open Library.

    The report (opens in a new tab)
  3. 3. Model

    Trained on six times the data, books readers had without rating them included, and tuned EASE, RP3beta and a text model on ratings set aside for it. Their blend doubles v1's NDCG.

    The report (opens in a new tab)
  4. 4. Show

    This page, with no server: each book's ten are worked out ahead of time, from the same model.

Ratings: the Book-Crossing data (Cai-Nicolas Ziegler, 2004), from Kaggle’s Book Recommendation Dataset. Book details and covers: Open Library (opens in a new tab).

v1’s lists are what its API returned, shown with v2’s cleaned titles. Each list shows one edition of a book. v2 never recommends Wild Animus: its publisher gave copies away through BookCrossing by the thousand, so having it says who received one, not who chose it, and it would top every list.