Skip to content
statxspherePublic

About

Anime Scout: a hybrid anime recommender (12k anime, 23.7M ratings) and AniMap explorer

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Repository files navigation

The Anime Scout

An anime recommendation engine: tell it a few anime you love and it finds others you're likely to enjoy.

Ever finished an anime and thought to yourself - "I want to watch that exact anime again, except with different characters and a different story."? Well, I have! So I built this.

Site: https://statxsphere.github.io/anime/

Old Streamlit app: https://statxsphere-anime-explore-8o50xg.streamlit.app/

What's new

I made the first version of this in 2021 with an old Kaggle dump, and the Scout needed a 500 MB similarity matrix downloaded from Dropbox. This version:

  • Uses fresh data: 12,037 anime (everything with 1,000+ members on MyAnimeList) from a 2025 scrape, and 23.7 million real user ratings.
  • Has a hybrid Scout. It looks at who likes an anime (user ratings) and what it's about (synopsis, tags, genres, themes, studio), with a small nudge for quality.
  • Takes several anime at once, tells you why it picked each one, and can hide sequels of what you already picked.
  • Groups anime into 20 taste groups (the clustering I'd planned as "next steps" in the EDA notebook) and puts them on a new AniMap.
  • Fits in about 6 MB of JSON (2 MB gzipped), so it runs as a static site on GitHub Pages. explore.py uses the same files now, so the Dropbox download is gone.

What's in here

  • EDA - Anime Recommendation System.ipynb cleans the old MyAnimeList data and looks at how ratings, popularity, episode counts, mediums and genres relate to each other.
  • AniMap - AniMap.ipynb is the original treemap of anime by medium, genre and title.
  • Collaborative filtering - Recommendations Using Collaborative Filtering.ipynb is the original item-based Scout.
  • get_data.py - downloads and cleans the new data.
  • build_recs.py - builds the recommender, tests it, finds the taste groups and writes the site data.
  • docs/ - the site (plain HTML, CSS and JS, no build step). docs/data/ has the JSON it reads.
  • explore.py - the Streamlit app, now on the new data.

The notebooks are kept as they were in 2021, so they still point at the old data in data1/.

Data

  • Anime info - MyAnimeList top anime dataset by lyfesan (MIT licence), scraped from MAL in 2025. Title, English title, type, episodes, season, genres, themes, demographic, studios, score and members.
  • User ratings, posters and tags - User Animelist Dataset by MRamazan (CC BY 4.0). It has 148 million MAL ratings from 1.77 million users, which is way more than I need, so I take 8 evenly spaced slices of it: 23.7 million ratings from 275,484 users.
  • Synopses and franchises - the AniList GraphQL API, for each anime's synopsis and its sequel/prequel/side story links (to group franchises together). The synopses are only used to build the model, they aren't in the repo or on the site.

I kept anime with 1,000+ members that have aired, and left out music videos, ads and hentai. That's 12,037 anime, 11,208 of them with a synopsis.

I wanted to use the Jikan API for this, but it wouldn't connect from my network, so AniList fills the gaps instead. AniList allows 30 requests a minute right now, so get_data.py asks for 50 anime per request, waits a couple of seconds between calls, backs off when it's told to, and saves every response to cache/. If it stops halfway, running it again picks up where it left off. The ratings slices are downloaded with HTTP range requests, so only ~290 MB of the 1.8 GB file comes down.

A huge thank you to MyAnimeList, AniList and the dataset authors!

How the Scout works

  1. Who likes it (collaborative). Like the old Scout, every rating is compared to that user's own average. An anime counts as "liked" if it's rated at or above it, and two anime are similar if the same people liked them (cosine similarity).
  2. What it's about (content). TF-IDF on the synopsis, TF-IDF on the detailed tags, and TF-IDF weighted genres + themes + demographic, and studios. Each block is normalised and weighted (synopsis 0.3, tags 0.3, genres 0.3, studios 0.1), so the similarity is a weighted mix of the four.
  3. Quality. A small prior from popularity (members) and MAL score.
  4. Hybrid. score = 0.2 * content + 0.8 * collaborative + 0.15 * quality.
  5. Neighbours. Each anime keeps its 30 best neighbours. The site adds up your picks' neighbour scores and shows the highest totals. The "why" on each card is the pick it came from, the genres/themes/studio they share, and "same fans" when the two have a strong fan overlap.

I picked the weights on a separate group of validation users. More weight on popularity always scored a tiny bit higher there, but then the lists drift towards the same few big shows. So anything within 1 point of the best counted as a tie, and I took the tie that leans least on popularity.

Does it work?

I split the 275k users: 80% to build the model, 10% to pick the weights and 10% to test it. For each of the 24,806 test users with at least 5 liked anime (rated 8+), I hid 20% of their liked list, gave the Scout some of the rest, and checked if any of the hidden ones made it into the top 10 (hit rate @10).

"New franchises only" doesn't count sequels: anything in the same franchise as a pick is removed from both the recommendations and the hidden list, because guessing Season 2 from Season 1 is too easy.

With 3 picks (like using the site):

Method Hit rate @10 New franchises only
Most popular (baseline) 45.8% 46.2%
Content only 36.7% 8.6%
Old Scout (2021 method: centred ratings) 49.7% 32.0%
Ratings only (liked = above own average) 59.1% 50.3%
Hybrid 59.1% 50.6%
Hybrid, one per franchise (the site's default) 54.7% 50.1%

With the user's whole visible liked list as picks:

Method Hit rate @10 New franchises only
Most popular (baseline) 52.9% 46.2%
Content only 51.3% 11.7%
Old Scout (2021 method) 68.1% 36.9%
Ratings only 75.4% 59.0%
Hybrid 76.2% 60.2%
Hybrid, one per franchise 76.0% 61.9%

The site hides sequels of your picks and shows only the best anime from each franchise by default (otherwise picking Steins;Gate 0 gives you three seasons of Re:Zero in a row). That costs a few points when sequels count as hits, so the number on the site is the honest one for those settings: 50% vs 46% for just showing the most popular anime.

Some honest notes:

  • "Most popular" is a really strong baseline on MAL, since most people's lists are full of the same big shows. The old 2021 method barely beats it, and loses to it once sequels don't count. The new one beats it, but with 3 picks and sequels not counted, only by about 4 points.
  • Content on its own is bad at this test. It finds anime that are about similar things, and those are often obscure ones nobody in the test watched. It doesn't add much to the hit rate, but about half the anime (the 5,961 liked by fewer than 50 people in the sample, including most 2025 ones) have barely any ratings, and for those the content part is what makes the recommendations sensible.
  • The top-10 neighbours share 48% of their genres with the anime they came from (Jaccard), vs 15% for random pairs.

A few examples, straight from build_recs.py:

  • Cowboy Bebop -> the Bebop movie, Samurai Champloo, Gurren Lagann, Evangelion, Code Geass, Ghost in the Shell, Trigun, FLCL, Akira
  • Mushishi -> the Mushishi sequels, then Baccano!, Natsume Yuujinchou, Samurai Champloo, Spice and Wolf
  • Shirobako -> Hibike! Euphonium, New Game!, Gekkan Shoujo Nozaki-kun, Hanasaku Iroha, Sora yori mo Tooi Basho, Sakura Quest
  • Haikyuu!! -> more Haikyuu!!, then Kuroko no Basket and My Hero Academia

Taste groups

build_recs.py squashes the content features down to 60 dimensions (TruncatedSVD, which is PCA for sparse data) and runs K-means with 20 clusters. Each group is named after the genres/themes that are most over-represented in it, like "Mecha · Sci-Fi", "Slice of Life · Iyashikei", "Suspense · Psychological" or "Sports · Team Sports". The AniMap on the site is a treemap of these groups (or of genres), sized by members and shaded by score, and you can click into a group to see its top anime and add them to your picks.

Running it

The site is static, so any web server works:

cd docs
python -m http.server 8623

and open http://localhost:8623.

The Streamlit app:

pip install -r requirements.txt
streamlit run explore.py

To rebuild the data from scratch (about 310 MB of downloads, around 15-20 minutes for the AniList part, and a few GB of RAM for the similarity matrices):

pip install -r requirements-dev.txt
python get_data.py
python build_recs.py

What I'd improve

  1. Ratings - the ratings data stops in mid 2025, so newer anime only get content-based recommendations for now.
  2. Modelling - try a small sentence-embedding model on the synopses instead of TF-IDF.
  3. Users - let people import their MAL list instead of picking anime by hand.

More of my projects are at statxsphere.github.io.

Dattebayo!

About

Anime Scout: a hybrid anime recommender (12k anime, 23.7M ratings) and AniMap explorer

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages