An exploratory analysis of 11,000+ Goodreads books covering titles, authors, ratings, page counts, languages, publishers, and publication years. The notebook answers 21 structured questions for two audiences — readers trying to find what to pick up next, and publishers trying to understand what succeeds. The centerpiece is a hand-crafted composite popularity score that addresses a real flaw in using raw average ratings to rank books.
What makes a book popular — and how do you measure it fairly? Raw average rating rewards obscure books with a handful of perfect scores. Pure read count rewards old blockbusters with millions of accumulated ratings. Neither alone gives a fair picture. The project asks 21 questions about books and authors, with the popularity ranking problem as the analytical core.
Cleaning — The dataset had four issues addressed before analysis:
authors column contained co-author entries separated by / (4,562 books affected) — only the first author was retained to avoid duplicate-identity problems in author-level aggregations.publisher column had the same / pattern — cleaned identically.num_pages had a leading whitespace in the column name — stripped via rename.num_pages ≤ 20 or ratings_count ≤ 100 were filtered as noise (zero-page entries and unreviewed books).Custom popularity score — A key insight: average_rating values cluster around 3.5–4.5, while ratings_count values range from hundreds to millions — they’re on incomparable scales. Rather than normalizing, the score raises average_rating to the 8th power (bringing it to ~65,000 for a 4.0-rated book, competitive with rating counts) then multiplies by ratings_count and scales down by 10⁵:
real_best_books = (average_rating⁸ × ratings_count) / 10⁵
This single formula rewards books that are both widely read and highly rated — neither metric can dominate alone.
21 questions answered, grouped by theme:
Key findings:
The composite scoring formula is the most creative analytical decision in this notebook — and the reasoning behind it (the scale mismatch between ratings and counts, solved by exponentiation rather than normalization) is the kind of problem that doesn’t have a textbook answer. It required thinking about what the metric means rather than just what’s available. The notebook also demonstrates a consistent habit of challenging the obvious answer: when sort_values('average_rating').head(10) produced an implausible list of obscure books, the response was to ask why and redesign the metric rather than accept a misleading result. The outlier investigation on the 1950s read-count spike is another example of the same instinct — a chart anomaly treated as a question to answer, not noise to ignore.