Anime Hybrid Recommendation System¶

Dataset Description¶

Anime Dataset 2023 Dataset¶

Summary:¶

Anime is a popular form of Japanese animated entertainment known for its unique art style, diverse genres, and rich storytelling. It includes TV series, movies, and OVAs that appeal to a wide range of audiences worldwide. With thousands of titles spanning action, romance, fantasy, and more, anime has built a passionate global fanbase. This diversity makes anime data especially suitable for building a great recommendation system. This dataset(Anime Dataset 2023) contains detailed metadata for each anime entry, including identifiers, content details, ratings, and user interaction metrics. The following are the descriptions of each column:


Column Descriptions:¶

  • anime_id: Unique identifier for each anime.
  • Name: Original name of the anime.
  • English name: Official English-translated title.
  • Other name: Alternate titles in native languages (e.g., Japanese, Chinese, Korean).
  • Score: Average user rating for the anime.
  • Genres: Comma-separated list of genres associated with the anime.
  • Synopsis: Brief summary of the anime’s plot.
  • Type: Format of the anime (e.g., TV, Movie, OVA).
  • Episodes: Total number of episodes.
  • Aired: Airing date range (start to end).
  • Premiered: Season and year of initial release.
  • Status: Current airing status (e.g., Finished Airing, Currently Airing).
  • Producers: Companies involved in the production.
  • Licensors: Distribution or licensing companies (e.g., streaming platforms).
  • Studios: Animation studios that created the anime.
  • Source: Origin of the story (e.g., manga, novel, original).
  • Duration: Length of a single episode.
  • Rating: Age restriction or content rating (e.g., PG-13, R).
  • Rank: Position in ranking based on ratings or popularity.
  • Popularity: Popularity rank among all anime.
  • Favorites: Number of users who marked the anime as a favorite.
  • Scored By: Number of users who rated the anime.
  • Members: Total users who added the anime to their list (watching, completed, etc.).
  • Image URL: Link to the anime’s cover image or poster.

Mount Google Drive¶

In [ ]:
from google.colab import drive
drive.mount('/content/drive')
Mounted at /content/drive

Installations¶

In [ ]:
!pip install numpy==1.26.4 --force-reinstall --no-cache-dir
Collecting numpy==1.26.4
  Downloading numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (61 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/61.0 kB ? eta -:--:--
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.0/61.0 kB 33.4 MB/s eta 0:00:00
Downloading numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (18.3 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/18.3 MB ? eta -:--:--
   ━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.0/18.3 MB 32.3 MB/s eta 0:00:01
   ━━━━━━━━━━━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━ 6.9/18.3 MB 101.8 MB/s eta 0:00:01
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╺━━━━━━━━━━ 13.3/18.3 MB 185.2 MB/s eta 0:00:01
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 18.3/18.3 MB 187.5 MB/s eta 0:00:00
Installing collected packages: numpy
  Attempting uninstall: numpy
    Found existing installation: numpy 2.0.2
    Uninstalling numpy-2.0.2:
      Successfully uninstalled numpy-2.0.2
ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
thinc 8.3.6 requires numpy<3.0.0,>=2.0.0, but you have numpy 1.26.4 which is incompatible.
opencv-python-headless 4.12.0.88 requires numpy<2.3.0,>=2; python_version >= "3.9", but you have numpy 1.26.4 which is incompatible.
opencv-python 4.12.0.88 requires numpy<2.3.0,>=2; python_version >= "3.9", but you have numpy 1.26.4 which is incompatible.
opencv-contrib-python 4.12.0.88 requires numpy<2.3.0,>=2; python_version >= "3.9", but you have numpy 1.26.4 which is incompatible.
Successfully installed numpy-1.26.4
In [ ]:
!pip install surprise
Collecting surprise
  Downloading surprise-0.1-py2.py3-none-any.whl.metadata (327 bytes)
Collecting scikit-surprise (from surprise)
  Downloading scikit_surprise-1.1.4.tar.gz (154 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/154.4 kB ? eta -:--:--
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 154.4/154.4 kB 4.4 MB/s eta 0:00:00
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Requirement already satisfied: joblib>=1.2.0 in /usr/local/lib/python3.11/dist-packages (from scikit-surprise->surprise) (1.5.1)
Requirement already satisfied: numpy>=1.19.5 in /usr/local/lib/python3.11/dist-packages (from scikit-surprise->surprise) (1.26.4)
Requirement already satisfied: scipy>=1.6.0 in /usr/local/lib/python3.11/dist-packages (from scikit-surprise->surprise) (1.16.0)
Downloading surprise-0.1-py2.py3-none-any.whl (1.8 kB)
Building wheels for collected packages: scikit-surprise
  Building wheel for scikit-surprise (pyproject.toml) ... done
  Created wheel for scikit-surprise: filename=scikit_surprise-1.1.4-cp311-cp311-linux_x86_64.whl size=2469541 sha256=4435555033e13403a54af1dec61f311298d670776920c86a305030189ace65b9
  Stored in directory: /root/.cache/pip/wheels/2a/8f/6e/7e2899163e2d85d8266daab4aa1cdabec7a6c56f83c015b5af
Successfully built scikit-surprise
Installing collected packages: scikit-surprise, surprise
Successfully installed scikit-surprise-1.1.4 surprise-0.1

Imports¶

In [ ]:
import pandas as pd
import numpy as np
from pathlib import Path
from IPython.display import Image, HTML
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import MultiLabelBinarizer
import re
from collections import defaultdict
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
from scipy.sparse import csr_matrix
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from nltk.stem import WordNetLemmatizer
from nltk import pos_tag
import string
import spacy
from datetime import datetime
import warnings
warnings.filterwarnings('ignore')
from surprise import SVD

Data Understanding¶

Data Loading¶

  • Use pathlib for path safety
In [ ]:
data_path = Path('/content/drive/MyDrive/Anime Recommender System')
  • Loading Anime Data
In [ ]:
anime_df = pd.read_csv(data_path/'anime-dataset-2023.csv')
In [ ]:
anime_df.columns
Out[ ]:
Index(['anime_id', 'Name', 'English name', 'Other name', 'Score', 'Genres',
       'Synopsis', 'Type', 'Episodes', 'Aired', 'Premiered', 'Status',
       'Producers', 'Licensors', 'Studios', 'Source', 'Duration', 'Rating',
       'Rank', 'Popularity', 'Favorites', 'Scored By', 'Members', 'Image URL'],
      dtype='object')
  • Showing first 5 rows
In [ ]:
anime_df.head()
Out[ ]:
anime_id Name English name Other name Score Genres Synopsis Type Episodes Aired ... Studios Source Duration Rating Rank Popularity Favorites Scored By Members Image URL
0 1 Cowboy Bebop Cowboy Bebop カウボーイビバップ 8.75 Action, Award Winning, Sci-Fi Crime is timeless. By the year 2071, humanity ... TV 26.0 Apr 3, 1998 to Apr 24, 1999 ... Sunrise Original 24 min per ep R - 17+ (violence & profanity) 41.0 43 78525 914193.0 1771505 https://cdn.myanimelist.net/images/anime/4/196...
1 5 Cowboy Bebop: Tengoku no Tobira Cowboy Bebop: The Movie カウボーイビバップ 天国の扉 8.38 Action, Sci-Fi Another day, another bounty—such is the life o... Movie 1.0 Sep 1, 2001 ... Bones Original 1 hr 55 min R - 17+ (violence & profanity) 189.0 602 1448 206248.0 360978 https://cdn.myanimelist.net/images/anime/1439/...
2 6 Trigun Trigun トライガン 8.22 Action, Adventure, Sci-Fi Vash the Stampede is the man with a $$60,000,0... TV 26.0 Apr 1, 1998 to Sep 30, 1998 ... Madhouse Manga 24 min per ep PG-13 - Teens 13 or older 328.0 246 15035 356739.0 727252 https://cdn.myanimelist.net/images/anime/7/203...
3 7 Witch Hunter Robin Witch Hunter Robin Witch Hunter ROBIN (ウイッチハンターロビン) 7.25 Action, Drama, Mystery, Supernatural Robin Sena is a powerful craft user drafted in... TV 26.0 Jul 3, 2002 to Dec 25, 2002 ... Sunrise Original 25 min per ep PG-13 - Teens 13 or older 2764.0 1795 613 42829.0 111931 https://cdn.myanimelist.net/images/anime/10/19...
4 8 Bouken Ou Beet Beet the Vandel Buster 冒険王ビィト 6.94 Adventure, Fantasy, Supernatural It is the dark century and the people are suff... TV 52.0 Sep 30, 2004 to Sep 29, 2005 ... Toei Animation Manga 23 min per ep PG - Children 4240.0 5126 14 6413.0 15001 https://cdn.myanimelist.net/images/anime/7/215...

5 rows × 24 columns

  • Loading Ratings Data
In [ ]:
ratings_df = pd.read_csv(data_path/'users-score-2023.csv')[:1000]
  • Showing first 5 rows of the data
In [ ]:
ratings_df.head()
Out[ ]:
user_id Username anime_id Anime Title rating
0 1 Xinil 21 One Piece 9
1 1 Xinil 48 .hack//Sign 7
2 1 Xinil 320 A Kite 5
3 1 Xinil 49 Aa! Megami-sama! 8
4 1 Xinil 304 Aa! Megami-sama! Movie 8

Data Exploration¶

Anime data size¶

In [ ]:
anime_df.shape
Out[ ]:
(24905, 24)
  • The anime dataset contains 24,905 entries (rows) and 24 features (columns)

User Ratings data size¶

In [ ]:
ratings_df.shape
Out[ ]:
(24325191, 5)
  • The ratings dataset contains 24,325,191 records and 5 columns.
  • This large volume of user-anime interaction data provides a strong foundation for Collaborative Filtering and other recommendation techniques. The richness and scale of the dataset make it ideal for training robust models.

Check for Missing Values in Anime Dataset¶

In [ ]:
anime_df.isnull().sum()
Out[ ]:
0
anime_id 0
Name 0
English name 0
Other name 0
Score 0
Genres 0
Synopsis 0
Type 0
Episodes 0
Aired 0
Premiered 0
Status 0
Producers 0
Licensors 0
Studios 0
Source 0
Duration 0
Rating 0
Rank 0
Popularity 0
Favorites 0
Scored By 0
Members 0
Image URL 0

  • No missing values.

Remove commas or other non-numeric characters from Score column (if any)¶

Cleaning the 'Score' and 'Scored By' columns in the anime dataset by removing non-numeric characters using regular expressions:

  • 'Score': Removes any character that is not a digit or a decimal point (e.g., "N/A", text, etc.).
  • 'Scored By': Removes all characters except digits to ensure the field contains only numeric values.
In [ ]:
anime_df['Score'] = anime_df['Score'].replace('[^0-9.]', '', regex=True)
anime_df['Scored By'] = anime_df['Scored By'].replace('[^0-9]', '', regex=True)

Convert to Numeric¶

In [ ]:
anime_df['Score'] = pd.to_numeric(anime_df['Score'], errors='coerce')
anime_df['Scored By'] = pd.to_numeric(anime_df['Scored By'], errors='coerce')

Fill missing values with the median of each column¶

In [ ]:
anime_df['Score'].fillna(anime_df['Score'].median(), inplace=True)
anime_df['Scored By'].fillna(anime_df['Scored By'].median(), inplace=True)

Extract the first 4-digit number from Aired as the release year¶

In [ ]:
anime_df['release_year'] = anime_df['Aired'].str.extract(r'(\d{4})').astype(float)

Split genres, handle Unknown¶

In [ ]:
anime_df['Genres'] = anime_df['Genres'].apply(lambda x: x.split(', ') if x != 'UNKNOWN' else [])

Multi-hot encode¶

In [ ]:
mlb_genres = MultiLabelBinarizer()
genres_encoded = mlb_genres.fit_transform(anime_df['Genres'])

Split studios, handle Unknown¶

In [ ]:
anime_df['Studios'] = anime_df['Studios'].apply(lambda x: x.split(', ') if x != 'UNKNOWN' else [])

Multi-hot encode¶

In [ ]:
mlb_studios = MultiLabelBinarizer()
studios_encoded = mlb_studios.fit_transform(anime_df['Studios'])

Add weighted Rating feature which is the IMDB popularity function quotient¶

In [ ]:
C = anime_df['Score'].mean()
m = anime_df['Scored By'].quantile(0.65)

anime_df['weighted_rating'] = (
    (anime_df['Scored By'] / (anime_df['Scored By'] + m)) * anime_df['Score'] +
    (m / (anime_df['Scored By'] + m)) * C
)

One-hot encode Type feature¶

In [ ]:
ohe_type = OneHotEncoder(sparse_output=False)
type_encoded = ohe_type.fit_transform(anime_df[['Type']])

One-hot encode Source feature¶

In [ ]:
ohe_source = OneHotEncoder(sparse_output=False)
source_encoded = ohe_source.fit_transform(anime_df[['Source']])

Convert to numeric, coercing errors to NaN¶

In [ ]:
anime_df['Episodes'] = pd.to_numeric(anime_df['Episodes'], errors='coerce')

Impute missing values with the median¶

In [ ]:
median_episodes = anime_df['Episodes'].median()
anime_df['Episodes'].fillna(median_episodes, inplace=True)

Bin episodes¶

In [ ]:
bins = [0, 1, 12, 24, 50, np.inf]
labels = ['1', '2-12', '13-24', '25-50', '51+']
anime_df['Episodes_Binned'] = pd.cut(anime_df['Episodes'], bins=bins, labels=labels)

One-hot encode Episodes feature¶

In [ ]:
ohe_episodes = OneHotEncoder(sparse_output=False)
episodes_encoded = ohe_episodes.fit_transform(anime_df[['Episodes_Binned']])

Clean text function¶

In [ ]:
def clean_text(text):
  text = text.lower()
  text = re.sub(r'[^\w\s]', '', text)  # Remove punctuation
  return text

Apply cleaning¶

In [ ]:
anime_df['Synopsis'] = anime_df['Synopsis'].apply(clean_text)

TF-IDF vectorization¶

In [ ]:
tfidf = TfidfVectorizer(stop_words='english')
synopsis_encoded = tfidf.fit_transform(anime_df['Synopsis'])

Feature Selection¶

In [ ]:
anime_df = anime_df[ [
    'anime_id',
    'Name',
    'Score',
    'Genres',
    'Synopsis',
    'Type',
    'Episodes',
    'Aired',
    'Status',
    'Studios',
    'Source',
    'Scored By',
    'Image URL'
]]
  • Save the new df
In [ ]:
# Define the path and filename
output_path = '/content/drive/MyDrive/Anime Recommender System/anime_filtered.csv'

# Save the DataFrame to CSV
anime_df.to_csv(output_path, index=False)

Building Content-Based Recommendation System¶

Compute cosine similarities with sparse matrices¶

Computing cosine similarity matrices for different encoded content features of anime:

  • genres_sim: Measures how similar anime titles are based on genre vectors.
  • studios_sim: Measures similarity based on shared animation studios.
  • synopsis_sim: Measures textual similarity between anime plot summaries (e.g., using TF-IDF).

Cosine similarity returns values between 0 (completely dissimilar) and 1 (identical), making it ideal for comparing sparse or high-dimensional feature encodings.

In [ ]:
genres_sim = cosine_similarity(genres_encoded)
studios_sim = cosine_similarity(studios_encoded)
synopsis_sim = cosine_similarity(synopsis_encoded)

Binary Similarity Match Function¶

This function computes a binary similarity matrix for an encoded dataset using dot product matching:

  • It calculates whether two entries share at least one common feature.
  • If they do, the dot product is non-zero → True → converted to 1.
  • If no match is found → False → converted to 0.

The result is a symmetric binary matrix (1 = match, 0 = no match), useful for exact-match filtering (e.g., genre or studio overlap).

In [ ]:
def match_similarity(encoded_data):
    return (encoded_data @ encoded_data.T).astype(bool).astype(int)

Compute Exact Match Similarities (Type, Source, Episodes)¶

The match_similarity() function to compute binary similarity matrices for the following encoded features:

  • type_sim: Matches anime with the same format (e.g., TV, Movie, OVA).
  • source_sim: Matches anime with the same source material (e.g., Manga, Light Novel, Original).
  • episodes_sim: Matches anime with the same number (or encoded range) of episodes.

Each matrix contains:

  • 1 → at least one shared encoded value (i.e., a match)
  • 0 → no match

These matrices are useful for filtering or boosting recommendations that share structural traits with the input anime.

In [ ]:
type_sim = match_similarity(type_encoded)
source_sim = match_similarity(source_encoded)
episodes_sim = match_similarity(episodes_encoded)

Combine Feature-Based Similarities with Equal Weights¶

Combining multiple similarity matrices into a single composite similarity score by applying equal weights to each of the six selected features:

  • Features used:

    1. genres_sim
    2. synopsis_sim
    3. type_sim
    4. studios_sim
    5. episodes_sim
    6. source_sim
  • Each feature is assigned an equal weight of 1/6, assuming equal importance across all content aspects.

The resulting combined_sim matrix represents a hybrid similarity score that captures both semantic (synopsis, genres) and structural (type, source, etc.) similarities — useful for content-based recommendations.

In [ ]:
# Number of features
num_features = 6

# Equal weights (1/6 for each)
weights = [1 / num_features] * num_features

# Combine similarities
combined_sim = (weights[0] * genres_sim +
                weights[1] * synopsis_sim +
                weights[2] * type_sim +
                weights[3] * studios_sim +
                weights[4] * episodes_sim +
                weights[5] * source_sim)

Hybrid Anime Recommendation Function (Content-Based + Weighted Rating)¶

The followig function, get_recommendations2(), generates personalized anime recommendations based on content similarity and weighted rating scores.

Parameters:¶

  • title (str): Anime title to base the recommendations on.
  • n (int): Number of recommendations to return (default = 10).
  • similarity_weight (float): Controls how much weight to give similarity vs. rating in final scoring.

How it works:¶

  1. Locates the given anime in anime_df.
  2. Computes cosine similarity scores using the combined_sim matrix.
  3. Selects top N most similar titles, excluding the anime itself.
  4. Fetches relevant columns: name, genres, image, scores, etc.
  5. Merges similarity scores with existing weighted ratings.
  6. Calculates a final score using a weighted average: $$\text{final_score} = (1 - w)\cdot\text{weighted_rating} + w \cdot \text{similarity_score}$$
  7. Returns top N results sorted by this final score.
In [ ]:
def get_recommendations2(title, n=10, similarity_weight=0.85):
    """
    Recommend anime based on a given title using cosine similarity and weighted ratings.

    Parameters:
    - title (str): Name of the anime to base recommendations on.
    - n (int): Number of recommendations to return (default: 10).
    - similarity_weight (float): Weight for similarity in final score (default: 0.7).

    Returns:
    - DataFrame: Top N recommended animes with relevant details.

    Raises:
    - ValueError: If the title is not found in anime_df.
    """
    # Check if title exists and get its label index
    matching_animes = anime_df[anime_df['Name'] == title]
    if matching_animes.empty:
        raise ValueError(f"Anime '{title}' not found in the database.")
    label = matching_animes.index[0]

    # Convert label index to positional index
    pos = anime_df.index.get_loc(label)

    # Get pairwise similarity scores
    sim_scores = list(enumerate(combined_sim[pos]))

    # Sort by similarity score in descending order
    sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)

    # Get top-N matches (excluding self), adjust n if fewer animes exist
    max_recommendations = min(102, len(anime_df) - 1)
    top_sim = sim_scores[1:max_recommendations + 1]
    sim_indices = [i for i, _ in top_sim]  # Indices of top similar animes
    sim_scores_top = [score for _, score in top_sim]  # Corresponding similarity scores

    # Fetch recommended animes
    recommended_animes = anime_df.iloc[sim_indices][
        ['Name', 'anime_id', 'weighted_rating', 'Image URL', 'Type', 'Genres', 'Score']
    ].copy()

    # Prepare for merging
    qualified_animes = recommended_animes.copy()
    qualified_animes.reset_index(drop=True, inplace=True)

    # Create similarity DataFrame with correct scores
    similarity_df = pd.DataFrame({
        "anime_id": anime_df.iloc[sim_indices]["anime_id"].values,
        "similarity_score": sim_scores_top
    })

    # Merge on correct column
    qualified_animes = qualified_animes.merge(similarity_df, on="anime_id", how="left")

    # Handle any unexpected NaNs in similarity_score
    qualified_animes["similarity_score"] = qualified_animes["similarity_score"].fillna(
        qualified_animes["similarity_score"].min()
    )

    # Calculate final score
    qualified_animes['final_score'] = (
        (1 - similarity_weight) * qualified_animes['weighted_rating'] +
        similarity_weight * qualified_animes['similarity_score']
    )

    # Return top-N sorted by final score
    return qualified_animes.sort_values('final_score', ascending=False).head(n)[
        ['Name', 'anime_id', 'Image URL', 'similarity_score', 'weighted_rating', 'final_score']
    ]
  • Lets test it.
In [ ]:
get_recommendations2(title='Darling in the FranXX', n=24)
Out[ ]:
Name anime_id Image URL similarity_score weighted_rating final_score
1 Lycoris Recoil 50709 https://cdn.myanimelist.net/images/anime/1392/... 0.684209 8.183950 1.809170
67 Vivy: Fluorite Eye's Song 46095 https://cdn.myanimelist.net/images/anime/1637/... 0.597510 8.394183 1.767011
8 Kill la Kill 18679 https://cdn.myanimelist.net/images/anime/1464/... 0.647670 8.036835 1.756045
77 Psycho-Pass 13601 https://cdn.myanimelist.net/images/anime/5/433... 0.587892 8.335466 1.750028
14 Plastic Memories 27775 https://cdn.myanimelist.net/images/anime/4/727... 0.645286 7.904120 1.734111
30 Senki Zesshou Symphogear XV 32843 https://cdn.myanimelist.net/images/anime/1899/... 0.620386 7.975510 1.723654
12 Texhnolyze 26 https://cdn.myanimelist.net/images/anime/1027/... 0.646544 7.717234 1.707147
33 Carole & Tuesday 37435 https://cdn.myanimelist.net/images/anime/1611/... 0.620216 7.851340 1.704885
53 Mahou Shoujo Lyrical Nanoha A's 77 https://cdn.myanimelist.net/images/anime/4/676... 0.599961 7.889765 1.693432
13 Uchuu Patrol Luluco 32681 https://cdn.myanimelist.net/images/anime/4/790... 0.645950 7.512696 1.675962
7 Guilty Crown 10793 https://cdn.myanimelist.net/images/anime/1566/... 0.648123 7.417078 1.663466
86 Charlotte 28999 https://cdn.myanimelist.net/images/anime/12/74... 0.584486 7.747445 1.658930
25 Senki Zesshou Symphogear AXZ 32836 https://cdn.myanimelist.net/images/anime/3/865... 0.622573 7.472081 1.649999
11 Soukyuu no Fafner: Dead Aggressor - Exodus Part 2 30549 https://cdn.myanimelist.net/images/anime/7/765... 0.647148 7.309665 1.646526
21 Senki Zesshou Symphogear G 15793 https://cdn.myanimelist.net/images/anime/2/866... 0.625689 7.396078 1.641247
61 Re:Creators 34561 https://cdn.myanimelist.net/images/anime/11/85... 0.598739 7.539231 1.639813
50 Noein: Mou Hitori no Kimi e 584 https://cdn.myanimelist.net/images/anime/1/584... 0.600546 7.503532 1.635994
52 Irozuku Sekai no Ashita kara 37497 https://cdn.myanimelist.net/images/anime/1424/... 0.600328 7.504221 1.635912
80 Ima, Soko ni Iru Boku 160 https://cdn.myanimelist.net/images/anime/1094/... 0.585873 7.559278 1.631883
32 Senki Zesshou Symphogear GX 21573 https://cdn.myanimelist.net/images/anime/9/866... 0.620225 7.358336 1.630941
10 Soukyuu no Fafner: Dead Aggressor - Exodus 17080 https://cdn.myanimelist.net/images/anime/5/685... 0.647159 7.177703 1.626741
89 AKB0048: Next Stage 14941 https://cdn.myanimelist.net/images/anime/11/44... 0.583954 7.527017 1.625413
56 Suisei no Gargantia 16524 https://cdn.myanimelist.net/images/anime/11/48... 0.599312 7.439220 1.625298
31 True Tears 2129 https://cdn.myanimelist.net/images/anime/1733/... 0.620261 7.274290 1.618366
In [ ]:
df = get_recommendations2(title='Darling in the FranXX', n=67)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Name anime_id Image URL similarity_score weighted_rating final_score
1 Lycoris Recoil 50709 No description has been provided for this image 0.684209 8.183950 1.809170
67 Vivy: Fluorite Eye's Song 46095 No description has been provided for this image 0.597510 8.394183 1.767011
8 Kill la Kill 18679 No description has been provided for this image 0.647670 8.036835 1.756045
77 Psycho-Pass 13601 No description has been provided for this image 0.587892 8.335466 1.750028
14 Plastic Memories 27775 No description has been provided for this image 0.645286 7.904120 1.734111
30 Senki Zesshou Symphogear XV 32843 No description has been provided for this image 0.620386 7.975510 1.723654
12 Texhnolyze 26 No description has been provided for this image 0.646544 7.717234 1.707147
33 Carole & Tuesday 37435 No description has been provided for this image 0.620216 7.851340 1.704885
53 Mahou Shoujo Lyrical Nanoha A's 77 No description has been provided for this image 0.599961 7.889765 1.693432
13 Uchuu Patrol Luluco 32681 No description has been provided for this image 0.645950 7.512696 1.675962
7 Guilty Crown 10793 No description has been provided for this image 0.648123 7.417078 1.663466
86 Charlotte 28999 No description has been provided for this image 0.584486 7.747445 1.658930
25 Senki Zesshou Symphogear AXZ 32836 No description has been provided for this image 0.622573 7.472081 1.649999
11 Soukyuu no Fafner: Dead Aggressor - Exodus Part 2 30549 No description has been provided for this image 0.647148 7.309665 1.646526
21 Senki Zesshou Symphogear G 15793 No description has been provided for this image 0.625689 7.396078 1.641247
61 Re:Creators 34561 No description has been provided for this image 0.598739 7.539231 1.639813
50 Noein: Mou Hitori no Kimi e 584 No description has been provided for this image 0.600546 7.503532 1.635994
52 Irozuku Sekai no Ashita kara 37497 No description has been provided for this image 0.600328 7.504221 1.635912
80 Ima, Soko ni Iru Boku 160 No description has been provided for this image 0.585873 7.559278 1.631883
32 Senki Zesshou Symphogear GX 21573 No description has been provided for this image 0.620225 7.358336 1.630941
10 Soukyuu no Fafner: Dead Aggressor - Exodus 17080 No description has been provided for this image 0.647159 7.177703 1.626741
89 AKB0048: Next Stage 14941 No description has been provided for this image 0.583954 7.527017 1.625413
56 Suisei no Gargantia 16524 No description has been provided for this image 0.599312 7.439220 1.625298
31 True Tears 2129 No description has been provided for this image 0.620261 7.274290 1.618366
15 Kurau Phantom Memory 483 No description has been provided for this image 0.644687 7.126334 1.616934
0 Engage Kiss 51417 No description has been provided for this image 0.695188 6.829794 1.615379
70 Mahou Shoujo Lyrical Nanoha 76 No description has been provided for this image 0.596609 7.367979 1.612314
62 Vandread: The Second Stage 181 No description has been provided for this image 0.598314 7.336459 1.609036
27 Solty Rei 152 No description has been provided for this image 0.621817 7.159682 1.602497
20 Buddy Complex 21437 No description has been provided for this image 0.625902 7.088736 1.595327
2 Senkou no Night Raid 6973 No description has been provided for this image 0.680460 6.775170 1.594666
4 IGPX: Immortal Grand Prix (2005) 3270 No description has been provided for this image 0.649499 6.950303 1.594620
16 Seikimatsu Occult Gakuin 6974 No description has been provided for this image 0.638213 7.013750 1.594544
9 Classroom☆Crisis 30383 No description has been provided for this image 0.647517 6.949188 1.592768
92 AKB0048 12149 No description has been provided for this image 0.583592 7.302190 1.591382
76 Kemonozume 1454 No description has been provided for this image 0.588238 7.268849 1.590330
18 Senki Zesshou Symphogear 11751 No description has been provided for this image 0.627148 7.004872 1.583807
38 IGPX: Immortal Grand Prix (2005) 2nd Season 1410 No description has been provided for this image 0.617851 7.033195 1.580153
48 Kiddy Grade 274 No description has been provided for this image 0.602237 7.121073 1.580062
66 Vandread 180 No description has been provided for this image 0.597592 7.139197 1.578832
3 Muteki Choujin Zanbot 3 2200 No description has been provided for this image 0.655473 6.752812 1.570074
55 Last Exile: Ginyoku no Fam 10336 No description has been provided for this image 0.599367 7.004832 1.560187
29 Blassreiter 3407 No description has been provided for this image 0.620965 6.861296 1.557015
65 Dual! Parallel Lun-Lun Monogatari 992 No description has been provided for this image 0.597798 6.960033 1.552133
47 Soukou no Strain 1602 No description has been provided for this image 0.604473 6.914741 1.551013
45 Koutetsu Tenshi Kurumi 554 No description has been provided for this image 0.614259 6.695615 1.526463
71 Futakoi Alternative 126 No description has been provided for this image 0.596225 6.797654 1.526439
6 Choujikuu Kidan Southern Cross 4503 No description has been provided for this image 0.648304 6.497439 1.525674
49 Double Decker! Doug & Kirill 37496 No description has been provided for this image 0.600664 6.767241 1.525651
17 M3: Sono Kuroki Hagane 23133 No description has been provided for this image 0.634980 6.553907 1.522819
44 Concrete Revolutio: Choujin Gensou 31147 No description has been provided for this image 0.616619 6.642999 1.520576
69 Kiddy GiRL-AND 3349 No description has been provided for this image 0.596910 6.739195 1.518253
59 Chikyuu Shoujo Arjuna 812 No description has been provided for this image 0.599021 6.725342 1.517969
63 I My Me! Strawberry Eggs 509 No description has been provided for this image 0.597997 6.728957 1.517641
5 Uchuu Kuubo Blue Noah 5763 No description has been provided for this image 0.649470 6.417003 1.514600
22 Cardfight!! Vanguard: overDress Season 2 48862 No description has been provided for this image 0.625543 6.538178 1.512438
19 Chikyuu Bouei Kazoku 1962 No description has been provided for this image 0.626203 6.518807 1.510094
23 Ginga Tetsudou Monogatari: Eien e no Bunkiten 2717 No description has been provided for this image 0.625000 6.498912 1.506087
88 Juubee-chan 2: Siberia Yagyuu no Gyakushuu 636 No description has been provided for this image 0.583973 6.720193 1.504406
93 Shinkon Gattai Godannar!! 2nd Season 1104 No description has been provided for this image 0.583333 6.713147 1.502805
37 Weiß Kreuz Glühen 446 No description has been provided for this image 0.618422 6.483184 1.498136
81 Koutetsushin Jeeg 2157 No description has been provided for this image 0.585548 6.665282 1.497508
95 Fireball Charming 10348 No description has been provided for this image 0.583333 6.646644 1.492830
85 Juubee-chan: Lovely Gantai no Himitsu 635 No description has been provided for this image 0.584569 6.632706 1.491789
97 Godzilla: S.P 43229 No description has been provided for this image 0.583333 6.633579 1.490870
101 Hikari to Mizu no Daphne 1082 No description has been provided for this image 0.576568 6.667648 1.490230
73 Shinkon Gattai Godannar!! 1103 No description has been provided for this image 0.593183 6.571968 1.490001
In [ ]:
get_recommendations2(title='Detective Conan', n=24)
Out[ ]:
Name anime_id Image URL similarity_score weighted_rating final_score
2 Dr. Stone: New World 48549 https://cdn.myanimelist.net/images/anime/1316/... 0.777778 8.205729 1.891970
1 Dr. Stone: Stone Wars 40852 https://cdn.myanimelist.net/images/anime/1711/... 0.778460 8.164181 1.886318
10 Kamisama Hajimemashita◎ 25681 https://cdn.myanimelist.net/images/anime/8/691... 0.724089 8.194550 1.844658
53 Mushishi Zoku Shou 2nd Season 24701 https://cdn.myanimelist.net/images/anime/9/680... 0.599115 8.689948 1.812740
70 Mushishi Zoku Shou 21939 https://cdn.myanimelist.net/images/anime/13/58... 0.598093 8.664767 1.808094
49 Kaguya-sama wa Kokurasetai? Tensai-tachi no Re... 40591 https://cdn.myanimelist.net/images/anime/1764/... 0.599410 8.635077 1.804760
58 Grand Blue 37105 https://cdn.myanimelist.net/images/anime/1302/... 0.598806 8.420849 1.772112
39 Kaguya-sama wa Kokurasetai: Tensai-tachi no Re... 37999 https://cdn.myanimelist.net/images/anime/1295/... 0.600087 8.406546 1.771056
64 Karakai Jouzu no Takagi-san 3 49721 https://cdn.myanimelist.net/images/anime/1861/... 0.598334 8.382613 1.765976
94 Tensei shitara Slime Datta Ken 2nd Season 39551 https://cdn.myanimelist.net/images/anime/1271/... 0.596752 8.382957 1.764683
26 Dr. Stone 38691 https://cdn.myanimelist.net/images/anime/1613/... 0.611544 8.286605 1.762803
63 Tensei shitara Slime Datta Ken 2nd Season Part 2 41487 https://cdn.myanimelist.net/images/anime/1033/... 0.598389 8.321181 1.756808
57 Gin no Saji 2nd Season 19363 https://cdn.myanimelist.net/images/anime/8/579... 0.598812 8.232757 1.743904
24 Eizouken ni wa Te wo Dasu na! 39792 https://cdn.myanimelist.net/images/anime/1680/... 0.613046 8.106870 1.737120
67 Asobi Asobase 37171 https://cdn.myanimelist.net/images/anime/1139/... 0.598220 8.175252 1.734775
80 Kuragehime 8129 https://cdn.myanimelist.net/images/anime/3/248... 0.597555 8.082057 1.720231
43 Gin no Saji 16918 https://cdn.myanimelist.net/images/anime/6/492... 0.599737 8.066827 1.719801
47 Komi-san wa, Comyushou desu. 2nd Season 50631 https://cdn.myanimelist.net/images/anime/1108/... 0.599512 8.055599 1.717925
73 Kuroshitsuji: Book of Circus 22145 https://cdn.myanimelist.net/images/anime/6/648... 0.597837 8.055676 1.716513
92 Kanata no Astra 39198 https://cdn.myanimelist.net/images/anime/1784/... 0.596770 8.058838 1.716080
93 Karakai Jouzu no Takagi-san 2 38993 https://cdn.myanimelist.net/images/anime/1393/... 0.596756 8.043034 1.713698
0 Meitantei Conan: Hannin no Hanzawa-san 50010 https://cdn.myanimelist.net/images/anime/1560/... 0.838107 6.668162 1.712615
46 Kakushigoto 40716 https://cdn.myanimelist.net/images/anime/1048/... 0.599589 7.969162 1.705025
34 High Score Girl II 39570 https://cdn.myanimelist.net/images/anime/1560/... 0.600566 7.934028 1.700585
In [ ]:
df = get_recommendations2(title='Hunter x Hunter (2011)', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Name anime_id Image URL similarity_score weighted_rating final_score
22 Fullmetal Alchemist: Brotherhood 5114 No description has been provided for this image 0.647648 9.097636 1.915146
17 Monster 19 No description has been provided for this image 0.666667 8.858186 1.895395
2 Hunter x Hunter 136 No description has been provided for this image 0.731087 8.397139 1.880995
9 Hajime no Ippo 263 No description has been provided for this image 0.667818 8.744465 1.879315
1 Cardcaptor Sakura 232 No description has been provided for this image 0.756345 8.145421 1.864706
35 Yuu☆Yuu☆Hakusho 392 No description has been provided for this image 0.641396 8.448490 1.812460
6 Naruto: Shippuuden 1735 No description has been provided for this image 0.669019 8.257899 1.807351
5 Diamond no Ace: Act II 38731 No description has been provided for this image 0.669196 8.184648 1.796514
28 Dragon Ball Z 813 No description has been provided for this image 0.644659 8.156166 1.771385
14 D.Gray-man 1482 No description has been provided for this image 0.666992 8.009810 1.768414
12 Naruto 20 No description has been provided for this image 0.667359 7.988501 1.765530
48 Diamond no Ace: Second Season 30230 No description has been provided for this image 0.619072 8.255112 1.764478
15 Bleach 269 No description has been provided for this image 0.666977 7.917476 1.754552
62 Trigun 6 No description has been provided for this image 0.612214 8.210988 1.752030
47 Fullmetal Alchemist 121 No description has been provided for this image 0.629099 8.106510 1.750711
84 Rurouni Kenshin: Meiji Kenkaku Romantan 45 No description has been provided for this image 0.596837 8.275545 1.748643
24 Dragon Ball 223 No description has been provided for this image 0.646483 7.955681 1.742863
65 Black Clover 34572 No description has been provided for this image 0.611341 8.136070 1.740051
49 Diamond no Ace 18689 No description has been provided for this image 0.617851 8.073270 1.736164
88 Black Lagoon: The Second Barrage 1519 No description has been provided for this image 0.596225 8.159754 1.730754
25 InuYasha 249 No description has been provided for this image 0.646463 7.853153 1.727466
11 Claymore 1818 No description has been provided for this image 0.667495 7.732521 1.727249
7 Fairy Tail (2014) 22043 No description has been provided for this image 0.667871 7.645865 1.714570
8 Dragon Quest: Dai no Daibouken (2020) 40906 No description has been provided for this image 0.667840 7.643075 1.714126

Conclusion¶

The recommendation results for Darling in the FranXX and Detective Conan show that the system effectively identifies thematically similar anime by combining content similarity and weighted user ratings. The suggestions align well with genre, tone, and narrative style, demonstrating that the hybrid model captures both semantic and structural relevance. However, most of the top results tend to favor well-established and popular titles.

To improve diversity and promote discovery, the system can be enhanced by giving priority to newer anime titles, such as by adjusting the weighting formula to favor recent release years or applying a novelty/recency boost to the final score.

Lets do some improvements¶

Generate Recency Score Based on Release Year¶

This helper function adds a recency_score column to a DataFrame using the anime's release year:

  • It creates a numeric score between 0 and 1, where:

    • 0 represents the oldest anime
    • 1 represents the most recent anime
  • Missing values in release_year are replaced with the minimum year to avoid distortion.

  • This normalized score can be used to boost newer anime in recommendation results, helping balance popularity with recency and discovery.

This is a key step in promoting fresh or underrated titles within the system.

In [ ]:
def _apply_recency_boost(df):
    """
    Uses the numeric 'release_year' column to create a 0–1 scaled 'recency_score'.
    """
    # Use 'release_year' directly
    df['year'] = df['release_year']

    # Fallback for missing years (fill with oldest year)
    df['year'] = df['year'].fillna(df['year'].min())

    # Scale to [0, 1]
    min_year = df['year'].min()
    max_year = df['year'].max()
    year_range = max_year - min_year if max_year != min_year else 1

    df['recency_score'] = (df['year'] - min_year) / year_range

    return df

Hybrid Recommendation Function with Recency Boost¶

This enhanced version of the recommendation function combines:

  1. Content similarity (from hybrid features like genres, synopsis, etc.)
  2. Weighted user ratings
  3. Recency score (based on the anime's release year)

How It Works:¶

  • Computes similarity scores using combined_sim

  • Applies _apply_recency_boost() to normalize the anime's release year to a recency_score (0–1)

  • Combines:

    • similarity_score (e.g., 85%)
    • weighted_rating (remaining weight)
    • recency_score (separate weight layered on top)

This setup promotes newer titles while still prioritizing relevance and quality.

Returns:¶

A DataFrame with:

  • Anime name, ID, image
  • Similarity score, weighted rating, recency score, final score, and release year
In [ ]:
def get_recommendations3(title, n=10, similarity_weight=0.85, recency_weight=0.3):
    """
    Recommend anime based on a given title using cosine similarity, weighted ratings, and recency.

    Parameters:
    - title (str): Name of the anime to base recommendations on.
    - n (int): Number of recommendations to return (default: 10).
    - similarity_weight (float): Weight for similarity in final score (default: 0.85).
    - recency_weight (float): Weight for recency in final score (default: 0.1).

    Returns:
    - DataFrame: Top N recommended animes with relevant details.

    Raises:
    - ValueError: If the title is not found in anime_df or weights are invalid.
    """
    # Check if title exists and get its label index
    matching_animes = anime_df[anime_df['Name'] == title]
    if matching_animes.empty:
        raise ValueError(f"Anime '{title}' not found in the database.")
    label = matching_animes.index[0]

    # Convert label index to positional index
    pos = anime_df.index.get_loc(label)

    # Get pairwise similarity scores
    sim_scores = list(enumerate(combined_sim[pos]))

    # Sort by similarity score in descending order
    sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)

    # Get top-N matches (excluding self), adjust n if fewer animes exist
    max_recommendations = min(102, len(anime_df) - 1)
    top_sim = sim_scores[1:max_recommendations + 1]
    sim_indices = [i for i, _ in top_sim]  # Indices of top similar animes
    sim_scores_top = [score for _, score in top_sim]  # Corresponding similarity scores

    # Fetch recommended animes, including Release_date for recency
    recommended_animes = anime_df.iloc[sim_indices][
        ['Name', 'anime_id', 'weighted_rating', 'Image URL', 'Type', 'Genres', 'Score', 'release_year']
    ].copy()

    # Apply recency boost to add recency_score
    recommended_animes = _apply_recency_boost(recommended_animes)

    # Prepare for merging
    qualified_animes = recommended_animes.copy()
    qualified_animes.reset_index(drop=True, inplace=True)

    # Create similarity DataFrame with correct scores
    similarity_df = pd.DataFrame({
        "anime_id": anime_df.iloc[sim_indices]["anime_id"].values,
        "similarity_score": sim_scores_top
    })

    # Merge on correct column
    qualified_animes = qualified_animes.merge(similarity_df, on="anime_id", how="left")

    # Handle any unexpected NaNs in similarity_score
    qualified_animes["similarity_score"] = qualified_animes["similarity_score"].fillna(
        qualified_animes["similarity_score"].min()
    )

    # Calculate the weight for weighted_rating
    rating_weight = 1 - similarity_weight
    if rating_weight < 0:
        raise ValueError("The sum of similarity_weight and recency_weight must be less than or equal to 1.")

    # Calculate final score with recency
    qualified_animes['final_score'] = (
        rating_weight * qualified_animes['weighted_rating'] +
        similarity_weight * qualified_animes['similarity_score'])

    qualified_animes['recency_score'] = recency_weight * qualified_animes['recency_score'] + (1 - recency_weight) * qualified_animes['final_score']

    # Return top-N sorted by final score
    return qualified_animes.sort_values('final_score', ascending=False).head(n)[
        ['Name', 'anime_id', 'Image URL', 'similarity_score', 'weighted_rating', 'recency_score','release_year', 'final_score']
    ]

Lets show some tests.¶

In [ ]:
df = get_recommendations3(title='Hunter x Hunter (2011)', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Name anime_id Image URL similarity_score weighted_rating recency_score release_year final_score
22 Fullmetal Alchemist: Brotherhood 5114 No description has been provided for this image 0.647648 9.097636 1.570602 2009.0 1.915146
17 Monster 19 No description has been provided for this image 0.666667 8.858186 1.531776 2004.0 1.895395
2 Hunter x Hunter 136 No description has been provided for this image 0.731087 8.397139 1.496697 1999.0 1.880995
9 Hajime no Ippo 263 No description has been provided for this image 0.667818 8.744465 1.500521 2000.0 1.879315
1 Cardcaptor Sakura 232 No description has been provided for this image 0.756345 8.145421 1.480294 1998.0 1.864706
35 Yuu☆Yuu☆Hakusho 392 No description has been provided for this image 0.641396 8.448490 1.413722 1992.0 1.812460
6 Naruto: Shippuuden 1735 No description has been provided for this image 0.669019 8.257899 1.485146 2007.0 1.807351
5 Diamond no Ace: Act II 38731 No description has been provided for this image 0.669196 8.184648 1.537560 2019.0 1.796514
28 Dragon Ball Z 813 No description has been provided for this image 0.644659 8.156166 1.369969 1989.0 1.771385
14 D.Gray-man 1482 No description has been provided for this image 0.666992 8.009810 1.452890 2006.0 1.768414
12 Naruto 20 No description has been provided for this image 0.667359 7.988501 1.430871 2002.0 1.765530
48 Diamond no Ace: Second Season 30230 No description has been provided for this image 0.619072 8.255112 1.495135 2015.0 1.764478
15 Bleach 269 No description has been provided for this image 0.666977 7.917476 1.433186 2004.0 1.754552
62 Trigun 6 No description has been provided for this image 0.612214 8.210988 1.401421 1998.0 1.752030
47 Fullmetal Alchemist 121 No description has been provided for this image 0.629099 8.106510 1.425498 2003.0 1.750711
84 Rurouni Kenshin: Meiji Kenkaku Romantan 45 No description has been provided for this image 0.596837 8.275545 1.389050 1996.0 1.748643
24 Dragon Ball 223 No description has been provided for this image 0.646483 7.955681 1.335004 1986.0 1.742863
65 Black Clover 34572 No description has been provided for this image 0.611341 8.136070 1.488035 2017.0 1.740051
49 Diamond no Ace 18689 No description has been provided for this image 0.617851 8.073270 1.465315 2013.0 1.736164
88 Black Lagoon: The Second Barrage 1519 No description has been provided for this image 0.596225 8.159754 1.426528 2006.0 1.730754
25 InuYasha 249 No description has been provided for this image 0.646463 7.853153 1.394226 2000.0 1.727466
11 Claymore 1818 No description has been provided for this image 0.667495 7.732521 1.429074 2007.0 1.727249
7 Fairy Tail (2014) 22043 No description has been provided for this image 0.667871 7.645865 1.455199 2014.0 1.714570
8 Dragon Quest: Dai no Daibouken (2020) 40906 No description has been provided for this image 0.667840 7.643075 1.484888 2020.0 1.714126
In [ ]:
get_recommendations3(title='Hunter x Hunter (2011)', n=24)
Out[ ]:
Name anime_id Image URL similarity_score weighted_rating recency_score release_year final_score
22 Fullmetal Alchemist: Brotherhood 5114 https://cdn.myanimelist.net/images/anime/1208/... 0.647648 9.097636 1.570602 2009.0 1.915146
17 Monster 19 https://cdn.myanimelist.net/images/anime/10/18... 0.666667 8.858186 1.531776 2004.0 1.895395
2 Hunter x Hunter 136 https://cdn.myanimelist.net/images/anime/1305/... 0.731087 8.397139 1.496697 1999.0 1.880995
9 Hajime no Ippo 263 https://cdn.myanimelist.net/images/anime/4/863... 0.667818 8.744465 1.500521 2000.0 1.879315
1 Cardcaptor Sakura 232 https://cdn.myanimelist.net/images/anime/8/607... 0.756345 8.145421 1.480294 1998.0 1.864706
35 Yuu☆Yuu☆Hakusho 392 https://cdn.myanimelist.net/images/anime/1228/... 0.641396 8.448490 1.413722 1992.0 1.812460
6 Naruto: Shippuuden 1735 https://cdn.myanimelist.net/images/anime/1565/... 0.669019 8.257899 1.485146 2007.0 1.807351
5 Diamond no Ace: Act II 38731 https://cdn.myanimelist.net/images/anime/1153/... 0.669196 8.184648 1.537560 2019.0 1.796514
28 Dragon Ball Z 813 https://cdn.myanimelist.net/images/anime/1607/... 0.644659 8.156166 1.369969 1989.0 1.771385
14 D.Gray-man 1482 https://cdn.myanimelist.net/images/anime/13/75... 0.666992 8.009810 1.452890 2006.0 1.768414
12 Naruto 20 https://cdn.myanimelist.net/images/anime/13/17... 0.667359 7.988501 1.430871 2002.0 1.765530
48 Diamond no Ace: Second Season 30230 https://cdn.myanimelist.net/images/anime/9/743... 0.619072 8.255112 1.495135 2015.0 1.764478
15 Bleach 269 https://cdn.myanimelist.net/images/anime/3/404... 0.666977 7.917476 1.433186 2004.0 1.754552
62 Trigun 6 https://cdn.myanimelist.net/images/anime/7/203... 0.612214 8.210988 1.401421 1998.0 1.752030
47 Fullmetal Alchemist 121 https://cdn.myanimelist.net/images/anime/10/75... 0.629099 8.106510 1.425498 2003.0 1.750711
84 Rurouni Kenshin: Meiji Kenkaku Romantan 45 https://cdn.myanimelist.net/images/anime/1346/... 0.596837 8.275545 1.389050 1996.0 1.748643
24 Dragon Ball 223 https://cdn.myanimelist.net/images/anime/1887/... 0.646483 7.955681 1.335004 1986.0 1.742863
65 Black Clover 34572 https://cdn.myanimelist.net/images/anime/2/883... 0.611341 8.136070 1.488035 2017.0 1.740051
49 Diamond no Ace 18689 https://cdn.myanimelist.net/images/anime/5/542... 0.617851 8.073270 1.465315 2013.0 1.736164
88 Black Lagoon: The Second Barrage 1519 https://cdn.myanimelist.net/images/anime/3/837... 0.596225 8.159754 1.426528 2006.0 1.730754
25 InuYasha 249 https://cdn.myanimelist.net/images/anime/1589/... 0.646463 7.853153 1.394226 2000.0 1.727466
11 Claymore 1818 https://cdn.myanimelist.net/images/anime/3/218... 0.667495 7.732521 1.429074 2007.0 1.727249
7 Fairy Tail (2014) 22043 https://cdn.myanimelist.net/images/anime/3/605... 0.667871 7.645865 1.455199 2014.0 1.714570
8 Dragon Quest: Dai no Daibouken (2020) 40906 https://cdn.myanimelist.net/images/anime/1499/... 0.667840 7.643075 1.484888 2020.0 1.714126

Conclusion:¶

Adding a recency score to the recommendation system introduces a valuable balance between relevance and novelty. While traditional hybrid models tend to favor older, highly rated classics, integrating recency allows newer anime to surface more prominently without sacrificing quality. This improves content discovery, keeps recommendations timely, and better reflects user interest in modern trends.

To further enhance the quality of recommendations, it is essential to fine-tune the weights assigned to each content feature (e.g., genres, synopsis, studio, type). While equal weighting provides a neutral baseline, not all features contribute equally to user preferences. For instance, genres and synopsis often carry more semantic relevance than production studios or episode count. By adjusting these weights based on empirical performance or user feedback, the system can better align with real-world viewing behavior, resulting in more accurate, engaging, and personalized recommendations.

lets adjust the weights of the features¶

In [ ]:
# New weights based on user preference
weights = [0.35, 0.25, 0.15, 0.10, 0.075, 0.075, 0.05]

# Combine similarities
combined_sim2 = (weights[0] * synopsis_sim +
                weights[1] * genres_sim +
                weights[2] * type_sim +
                weights[3] * studios_sim +
                weights[4] * episodes_sim +
                weights[5] * source_sim)

This function refines anime recommendations by introducing a flexible weighting scheme for similarity, rating, and recency. It uses a new similarity matrix (combined_sim2) generated from custom-weighted feature similarities, allowing more control over what influences the recommendations.

How It Works:¶

  1. Retrieves anime similar to the given title using the custom similarity matrix.

  2. Calculates a recency_score scaled from 0–1 based on release year.

  3. Computes a final score based on:

    • similarity_weight (semantic closeness)
    • weighted_rating (user consensus)
    • recency_weight (favoring newer content)
  4. Applies a composite scoring formula:

    $$\text{final_score} = \left[ \text{rating} \cdot w_r + \text{similarity} \cdot w_s \right] \cdot (1 - w_{rec}) + \text{recency} \cdot w_{rec}$$

    where $w_r + w_s + w_{rec} = 1$

Explaination:¶

Feature importance isn't uniform—genres and synopsis usually reflect content better than studio or type. By customizing the weights used in the similarity matrix (combined_sim2), the system can prioritize features that align more closely with user preferences, improving both accuracy and relevance of recommendations.

In [ ]:
def get_recommendations4(title, n=10, similarity_weight=0.7, recency_weight=0.1):
    # Check if title exists and get its label index
    matching_animes = anime_df[anime_df['Name'] == title]
    if matching_animes.empty:
        raise ValueError(f"Anime '{title}' not found in the database.")
    label = matching_animes.index[0]

    pos = anime_df.index.get_loc(label)
    sim_scores = list(enumerate(combined_sim2[pos]))
    sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)

    max_recommendations = min(102, len(anime_df) - 1)
    top_sim = sim_scores[1:max_recommendations + 1]
    sim_indices = [i for i, _ in top_sim]
    sim_scores_top = [score for _, score in top_sim]

    recommended_animes = anime_df.iloc[sim_indices][
        ['Name', 'anime_id', 'weighted_rating', 'Image URL', 'Type', 'Genres', 'Score', 'release_year']
    ].copy()

    recommended_animes = _apply_recency_boost(recommended_animes)
    qualified_animes = recommended_animes.copy()
    qualified_animes.reset_index(drop=True, inplace=True)

    similarity_df = pd.DataFrame({
        "anime_id": anime_df.iloc[sim_indices]["anime_id"].values,
        "similarity_score": sim_scores_top
    })

    qualified_animes = qualified_animes.merge(similarity_df, on="anime_id", how="left")
    qualified_animes["similarity_score"] = qualified_animes["similarity_score"].fillna(
        qualified_animes["similarity_score"].min()
    )

    rating_weight = 1 - similarity_weight - recency_weight
    if rating_weight < 0:
        raise ValueError("The sum of similarity_weight and recency_weight must be less than or equal to 1.")

    qualified_animes['final_score'] = (
        rating_weight * qualified_animes['weighted_rating'] +
        similarity_weight * qualified_animes['similarity_score'])*(1-recency_weight) +(
        recency_weight * qualified_animes['recency_score']
    )

    return qualified_animes.sort_values('final_score', ascending=False).head(n)[
        ['Image URL', 'Name', 'anime_id',  'similarity_score', 'weighted_rating', 'recency_score', 'release_year', 'final_score']
    ]
  • lets do somme tests
In [ ]:
df = get_recommendations4(title='Hunter x Hunter', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id similarity_score weighted_rating recency_score release_year final_score
0 No description has been provided for this image Hunter x Hunter (2011) 11061 0.685284 9.037173 0.793103 2011.0 2.137730
23 No description has been provided for this image Fullmetal Alchemist: Brotherhood 5114 0.518537 9.097636 0.758621 2009.0 2.040115
49 No description has been provided for this image Bleach: Sennen Kessen-hen 41467 0.483582 9.048079 0.982759 2022.0 2.031586
45 No description has been provided for this image One Piece 21 0.487591 8.686696 0.586207 1999.0 1.929409
7 No description has been provided for this image Naruto: Shippuuden 1735 0.553618 8.257899 0.724138 2007.0 1.907615
36 No description has been provided for this image Yuu☆Yuu☆Hakusho 392 0.505619 8.448490 0.465517 1992.0 1.885820
67 No description has been provided for this image Jigokuraku 46569 0.476893 8.224549 1.000000 2023.0 1.880862
9 No description has been provided for this image D.Gray-man 1482 0.552713 8.009810 0.706897 2006.0 1.860664
73 No description has been provided for this image Magi: The Kingdom of Magic 18115 0.475000 8.212752 0.827586 2013.0 1.860304
53 No description has been provided for this image Hunter x Hunter: Original Video Animation 137 0.481455 8.258539 0.637931 2002.0 1.853647
83 No description has been provided for this image Black Clover 34572 0.471095 8.136070 0.896552 2017.0 1.850938
8 No description has been provided for this image Naruto 20 0.553181 7.988501 0.637931 2002.0 1.850228
3 No description has been provided for this image Bleach 269 0.556985 7.917476 0.672414 2004.0 1.843288
82 No description has been provided for this image Hunter x Hunter: Greed Island Final 139 0.471418 8.207576 0.672414 2004.0 1.841598
25 No description has been provided for this image Dragon Ball Z 813 0.517795 8.156166 0.413793 1989.0 1.835700
43 No description has been provided for this image Fullmetal Alchemist 121 0.493649 8.106510 0.655172 2003.0 1.835688
62 No description has been provided for this image Hunter x Hunter: Greed Island 138 0.477618 8.142559 0.655172 2003.0 1.832077
63 No description has been provided for this image Magi: The Labyrinth of Magic 14513 0.477189 8.014632 0.810345 2012.0 1.824297
2 No description has been provided for this image Dragon Quest: Dai no Daibouken (2020) 40906 0.559280 7.643075 0.948276 2020.0 1.822927
5 No description has been provided for this image Fairy Tail (2014) 22043 0.554866 7.645865 0.844828 2014.0 1.810304
20 No description has been provided for this image InuYasha 249 0.522848 7.853153 0.603448 2000.0 1.803306
6 No description has been provided for this image Fairy Tail: Final Series 35972 0.554754 7.561180 0.913793 2018.0 1.801886
60 No description has been provided for this image Magi: Sinbad no Bouken (TV) 31741 0.478409 7.839802 0.879310 2016.0 1.800493
22 No description has been provided for this image Dragon Ball 223 0.520077 7.955681 0.362069 1986.0 1.795878
In [ ]:
df = get_recommendations4(title='Darling in the FranXX', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id similarity_score weighted_rating recency_score release_year final_score
52 No description has been provided for this image Shigatsu wa Kimi no Uso 23273 0.465837 8.646914 0.808511 2014.0 1.930773
99 No description has been provided for this image Vivy: Fluorite Eye's Song 46095 0.447036 8.394183 0.957447 2021.0 1.888330
18 No description has been provided for this image Lycoris Recoil 50709 0.492501 8.183950 0.978723 2022.0 1.881259
83 No description has been provided for this image Kidou Senshi Gundam: Tekketsu no Orphans 2nd Season 33051 0.450011 8.188491 0.851064 2016.0 1.842542
9 No description has been provided for this image Plastic Memories 27775 0.518499 7.904120 0.829787 2015.0 1.832374
29 No description has been provided for this image Senki Zesshou Symphogear XV 32843 0.482099 7.975510 0.914894 2019.0 1.830804
32 No description has been provided for this image Carole & Tuesday 37435 0.481744 7.851340 0.914894 2019.0 1.808229
85 No description has been provided for this image Kidou Senshi Gundam 00 2581 0.449888 8.084751 0.659574 2007.0 1.804642
63 No description has been provided for this image Kidou Senshi Gundam 00 Second Season 3927 0.455764 8.048096 0.680851 2008.0 1.803874
8 No description has been provided for this image Texhnolyze 26 0.521140 7.717234 0.574468 2003.0 1.774867
72 No description has been provided for this image Mahou Shoujo Lyrical Nanoha A's 77 0.452184 7.889765 0.617021 2005.0 1.766736
78 No description has been provided for this image Terra e... (TV) 2158 0.450818 7.748906 0.659574 2007.0 1.744776
4 No description has been provided for this image Guilty Crown 10793 0.524456 7.417078 0.744681 2011.0 1.739949
22 No description has been provided for this image Senki Zesshou Symphogear AXZ 32836 0.486692 7.472081 0.872340 2017.0 1.738824
64 No description has been provided for this image Kidou Senshi Gundam SEED 93 0.454633 7.724560 0.553191 2002.0 1.732159
13 No description has been provided for this image Kiznaiver 31798 0.501954 7.374965 0.851064 2016.0 1.728831
7 No description has been provided for this image Soukyuu no Fafner: Dead Aggressor - Exodus Part 2 30549 0.522408 7.309665 0.829787 2015.0 1.727836
86 No description has been provided for this image Re:Creators 34561 0.449618 7.539231 0.872340 2017.0 1.727555
71 No description has been provided for this image Irozuku Sekai no Ashita kara 37497 0.452954 7.504221 0.893617 2018.0 1.725483
16 No description has been provided for this image Senki Zesshou Symphogear G 15793 0.493236 7.396078 0.787234 2013.0 1.720756
49 No description has been provided for this image SSSS.Dynazenon 40870 0.467888 7.375668 0.957447 2021.0 1.718134
60 No description has been provided for this image Kidou Senshi Zeta Gundam 85 0.457266 7.828992 0.191489 1985.0 1.716445
59 No description has been provided for this image Macross 1088 0.458960 7.828247 0.127660 1982.0 1.710995
31 No description has been provided for this image Senki Zesshou Symphogear GX 21573 0.481761 7.358336 0.829787 2015.0 1.710989
In [ ]:
get_recommendations4(title='Darling in the FranXX', n=24)
Out[ ]:
Image URL Name anime_id similarity_score weighted_rating recency_score release_year final_score
52 https://cdn.myanimelist.net/images/anime/3/671... Shigatsu wa Kimi no Uso 23273 0.465837 8.646914 0.808511 2014.0 1.930773
99 https://cdn.myanimelist.net/images/anime/1637/... Vivy: Fluorite Eye's Song 46095 0.447036 8.394183 0.957447 2021.0 1.888330
18 https://cdn.myanimelist.net/images/anime/1392/... Lycoris Recoil 50709 0.492501 8.183950 0.978723 2022.0 1.881259
83 https://cdn.myanimelist.net/images/anime/6/808... Kidou Senshi Gundam: Tekketsu no Orphans 2nd S... 33051 0.450011 8.188491 0.851064 2016.0 1.842542
9 https://cdn.myanimelist.net/images/anime/4/727... Plastic Memories 27775 0.518499 7.904120 0.829787 2015.0 1.832374
29 https://cdn.myanimelist.net/images/anime/1899/... Senki Zesshou Symphogear XV 32843 0.482099 7.975510 0.914894 2019.0 1.830804
32 https://cdn.myanimelist.net/images/anime/1611/... Carole & Tuesday 37435 0.481744 7.851340 0.914894 2019.0 1.808229
85 https://cdn.myanimelist.net/images/anime/3/132... Kidou Senshi Gundam 00 2581 0.449888 8.084751 0.659574 2007.0 1.804642
63 https://cdn.myanimelist.net/images/anime/9/127... Kidou Senshi Gundam 00 Second Season 3927 0.455764 8.048096 0.680851 2008.0 1.803874
8 https://cdn.myanimelist.net/images/anime/1027/... Texhnolyze 26 0.521140 7.717234 0.574468 2003.0 1.774867
72 https://cdn.myanimelist.net/images/anime/4/676... Mahou Shoujo Lyrical Nanoha A's 77 0.452184 7.889765 0.617021 2005.0 1.766736
78 https://cdn.myanimelist.net/images/anime/1013/... Terra e... (TV) 2158 0.450818 7.748906 0.659574 2007.0 1.744776
4 https://cdn.myanimelist.net/images/anime/1566/... Guilty Crown 10793 0.524456 7.417078 0.744681 2011.0 1.739949
22 https://cdn.myanimelist.net/images/anime/3/865... Senki Zesshou Symphogear AXZ 32836 0.486692 7.472081 0.872340 2017.0 1.738824
64 https://cdn.myanimelist.net/images/anime/1792/... Kidou Senshi Gundam SEED 93 0.454633 7.724560 0.553191 2002.0 1.732159
13 https://cdn.myanimelist.net/images/anime/6/784... Kiznaiver 31798 0.501954 7.374965 0.851064 2016.0 1.728831
7 https://cdn.myanimelist.net/images/anime/7/765... Soukyuu no Fafner: Dead Aggressor - Exodus Part 2 30549 0.522408 7.309665 0.829787 2015.0 1.727836
86 https://cdn.myanimelist.net/images/anime/11/85... Re:Creators 34561 0.449618 7.539231 0.872340 2017.0 1.727555
71 https://cdn.myanimelist.net/images/anime/1424/... Irozuku Sekai no Ashita kara 37497 0.452954 7.504221 0.893617 2018.0 1.725483
16 https://cdn.myanimelist.net/images/anime/2/866... Senki Zesshou Symphogear G 15793 0.493236 7.396078 0.787234 2013.0 1.720756
49 https://cdn.myanimelist.net/images/anime/1880/... SSSS.Dynazenon 40870 0.467888 7.375668 0.957447 2021.0 1.718134
60 https://cdn.myanimelist.net/images/anime/6/111... Kidou Senshi Zeta Gundam 85 0.457266 7.828992 0.191489 1985.0 1.716445
59 https://cdn.myanimelist.net/images/anime/1/244... Macross 1088 0.458960 7.828247 0.127660 1982.0 1.710995
31 https://cdn.myanimelist.net/images/anime/9/866... Senki Zesshou Symphogear GX 21573 0.481761 7.358336 0.829787 2015.0 1.710989

Conclusion:¶

Effect of Fine-Tuned Feature Weights and Recency in get_recommendations4

The updated results for Darling in the FranXX using get_recommendations4() demonstrate the impact of fine-tuning feature similarity weights and applying a recency-aware scoring formula.

🔍 Key Improvements:¶

  • The top results now prioritize recent anime (e.g., Lycoris Recoil (2022), Vivy (2021), Plastic Memories (2015), SSSS.Dynazenon (2021)).
  • Older but highly relevant series (like Texhnolyze or Gundam titles) are still present, but appear lower than in earlier versions — showing a more balanced mix of new and classic titles.
  • The final scores reflect this trade-off: titles with moderate similarity but high recency and rating (like Shigatsu wa Kimi no Uso or Vivy) outperform older titles with similar genres but less recency impact.

By tuning the similarity matrix (combined_sim2) and adjusting the final score formula to incorporate recency, the system produces more modern, user-relevant recommendations while maintaining thematic consistency. This approach increases discovery of newer anime without disregarding high-quality classics — striking a thoughtful balance between relevance and freshness.

Lets adjust the weifhts one more time to get more satidying results¶

Combine Similarities Using Fine-Tuned Feature Weights¶

This cell creates a new hybrid content similarity matrix (combined_sim3) by assigning custom weights to each encoded feature, based on assumed or collected user preferences:

  • Genres: 30% — important for thematic alignment
  • Synopsis: 35% — most descriptive of plot and tone
  • Type: 15% — format (e.g., TV vs. Movie) moderately impacts relevance
  • Studios: 10% — aesthetic/style influence
  • Episodes: 5% — minor but helpful for pacing or length matching
  • Source: 5% — light effect (e.g., manga vs. original)

These weights reflect the relative importance of each feature in shaping user preferences, resulting in a more personalized similarity matrix.

In [ ]:
# Fine-tuned weights based on user preferences
weights = [0.30, 0.35, 0.15, 0.10, 0.05, 0.05]

# Combine similarities
combined_sim3 = (weights[0] * genres_sim +  # Genres: 0.30
                weights[1] * synopsis_sim +  # Synopsis: 0.35
                weights[2] * type_sim +      # Type: 0.15
                weights[3] * studios_sim +   # Studios: 0.10
                weights[4] * episodes_sim +  # Episodes: 0.05
                weights[5] * source_sim  # Source: 0.05
                )

Create Normalized Recency Score from Release Year¶

This utility function creates a recency_score ranging from 0 to 1 based on the anime's release year. It helps prioritize newer titles during recommendation scoring.

Methodology:¶

  • Reads the anime's release_year column.

  • Fills missing years with the minimum known year (to avoid boosting incomplete data).

  • Applies min-max normalization:

    $$\text{recency_score} = \frac{(\text{year} - \text{min})}{(\text{max}-\text{ min})}$$

  • Returns the same DataFrame with a new column: recency_score

This allows the system to boost newer anime titles when computing the final recommendation score.

In [ ]:
def _apply_recency_boost(df):
    """
    Uses the numeric 'release_year' column to create a 0–1 scaled 'recency_score'.
    """
    # Use 'release_year' directly
    df['year'] = df['release_year']

    # Fallback for missing years (fill with oldest year)
    df['year'] = df['year'].fillna(df['year'].min())

    # Scale to [0, 1]
    min_year = df['year'].min()
    max_year = df['year'].max()
    year_range = max_year - min_year if max_year != min_year else 1

    df['recency_score'] = (df['year'] - min_year) / year_range

    return df

Final Hybrid Recommendation Function with Fine-Tuned Weights and Recency Boost¶

  • get_recommendations101() delivers anime recommendations by combining:

    1. Fine-tuned similarity scores from combined_sim3, based on weighted feature similarity (genres, synopsis, type, etc.)
    2. Weighted user ratings for quality assessment
    3. Recency scoring to boost newer releases
  • Methodology:

    • Finds the input title in anime_df.
    • Retrieves the most similar anime using combined_sim3, which includes custom-tuned feature weights.
    • Applies _apply_recency_boost() to normalize each anime’s release year into a recency_score (0–1).
    • Calculates a composite score:

    $$ \text{final_score} = \left[ \text{rating} \cdot (1 - w_s) + \text{similarity} \cdot w_s \right] \cdot (1 - w_r) + \text{recency} \cdot w_r $$

    Where:

    • $w_s$: similarity weight (default 0.85)
    • $w_r$: recency weight (default 0.20)
  • Output:

    Returns the top N recommendations, sorted by the final_score, including:

    • Anime name, type, image, rating, similarity, recency score, and release year
In [ ]:
def get_recommendations101(title, n=10, similarity_weight=0.85, recency_weight=0.2):
    # Check if title exists and get its label index
    matching_animes = anime_df[anime_df['Name'] == title]
    if matching_animes.empty:
        raise ValueError(f"Anime '{title}' not found in the database.")
    label = matching_animes.index[0]

    pos = anime_df.index.get_loc(label)
    sim_scores = list(enumerate(combined_sim3[pos]))
    sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)

    max_recommendations = min(52, len(anime_df) - 1)
    top_sim = sim_scores[1:max_recommendations + 1]
    sim_indices = [i for i, _ in top_sim]
    sim_scores_top = [score for _, score in top_sim]

    recommended_animes = anime_df.iloc[sim_indices][
        ['Name', 'anime_id', 'weighted_rating', 'Image URL', 'Type', 'Genres', 'Score', 'release_year']
    ].copy()

    recommended_animes = _apply_recency_boost(recommended_animes)
    qualified_animes = recommended_animes.copy()
    qualified_animes.reset_index(drop=True, inplace=True)

    similarity_df = pd.DataFrame({
        "anime_id": anime_df.iloc[sim_indices]["anime_id"].values,
        "similarity_score": sim_scores_top
    })

    qualified_animes = qualified_animes.merge(similarity_df, on="anime_id", how="left")
    qualified_animes["similarity_score"] = qualified_animes["similarity_score"].fillna(
        qualified_animes["similarity_score"].min()
    )

    rating_weight = 1 - similarity_weight
    if rating_weight < 0:
        raise ValueError("The sum of similarity_weight and recency_weight must be less than or equal to 1.")

    qualified_animes['final_score'] = (
        rating_weight * qualified_animes['weighted_rating'] +
        similarity_weight * qualified_animes['similarity_score'])* (1-recency_weight) + (recency_weight * qualified_animes['recency_score'])

    return qualified_animes.sort_values('final_score', ascending=False).head(n)[
        ['Image URL', 'Name','Type', 'anime_id',  'similarity_score', 'weighted_rating', 'recency_score', 'release_year', 'final_score']
    ]
  • Lets do some tests
In [ ]:
df = get_recommendations101(title='Darling in the FranXX', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name Type anime_id similarity_score weighted_rating recency_score release_year final_score
37 No description has been provided for this image 86 Part 2 TV 48569 0.474157 8.692836 0.977778 2021.0 1.561122
32 No description has been provided for this image Shigatsu wa Kimi no Uso TV 23273 0.476193 8.646914 0.822222 2014.0 1.525885
30 No description has been provided for this image 86 TV 41457 0.477333 8.270491 0.977778 2021.0 1.512601
10 No description has been provided for this image Plastic Memories TV 27775 0.511800 7.904120 0.844444 2015.0 1.465407
38 No description has been provided for this image Kidou Senshi Gundam 00 Second Season TV 3927 0.474065 8.048096 0.688889 2008.0 1.425914
3 No description has been provided for this image Kiznaiver TV 31798 0.520255 7.374965 0.866667 2016.0 1.412103
26 No description has been provided for this image SSSS.Dynazenon TV 40870 0.478243 7.375668 0.977778 2021.0 1.405841
8 No description has been provided for this image Soukyuu no Fafner: Dead Aggressor - Exodus Part 2 TV 30549 0.515709 7.309665 0.844444 2015.0 1.396731
43 No description has been provided for this image Senki Zesshou Symphogear AXZ TV 32836 0.472047 7.472081 0.888889 2017.0 1.395420
5 No description has been provided for this image Guilty Crown TV 10793 0.517757 7.417078 0.755556 2011.0 1.393235
9 No description has been provided for this image Texhnolyze TV 26 0.514441 7.717234 0.577778 2003.0 1.391444
50 No description has been provided for this image Terra e... (TV) TV 2158 0.469119 7.748906 0.666667 2007.0 1.382203
7 No description has been provided for this image Soukyuu no Fafner: Dead Aggressor - Exodus TV 17080 0.515733 7.177703 0.844444 2015.0 1.380912
16 No description has been provided for this image Grancrest Senki TV 34279 0.488715 7.208601 0.911111 2018.0 1.379580
24 No description has been provided for this image Senki Zesshou Symphogear G TV 15793 0.478591 7.396078 0.800000 2013.0 1.372971
36 No description has been provided for this image Kidou Senshi Gundam SEED TV 93 0.474354 7.724560 0.555556 2002.0 1.360619
48 No description has been provided for this image Macross Δ TV 28013 0.469734 7.213781 0.866667 2016.0 1.358406
6 No description has been provided for this image Classroom☆Crisis TV 30383 0.516485 6.949188 0.844444 2015.0 1.354001
17 No description has been provided for this image Engage Kiss TV 51417 0.486690 6.829794 1.000000 2022.0 1.350524
23 No description has been provided for this image Buddy Complex TV 21437 0.479038 7.088736 0.822222 2014.0 1.340838
19 No description has been provided for this image Star Driver: Kagayaki no Takuto TV 8934 0.484278 7.159537 0.733333 2010.0 1.335120
28 No description has been provided for this image Hypnosis Mic: Division Rap Battle - Rhyme Anima TV 40803 0.477640 6.764323 0.955556 2020.0 1.327625
12 No description has been provided for this image Kidou Senshi Gundam SEED Destiny TV 94 0.507264 7.158412 0.600000 2004.0 1.323949
21 No description has been provided for this image Senki Zesshou Symphogear TV 11751 0.481656 7.004872 0.777778 2012.0 1.323666
In [ ]:
df = get_recommendations101(title='Jujutsu Kaisen', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name Type anime_id similarity_score weighted_rating recency_score release_year final_score
2 No description has been provided for this image Chainsaw Man TV 44511 0.553409 8.584003 0.974359 2022.0 1.601270
19 No description has been provided for this image Bleach: Sennen Kessen-hen TV 41467 0.462662 9.048079 0.974359 2022.0 1.595251
17 No description has been provided for this image Shingeki no Kyojin: The Final Season TV 40028 0.474939 8.796520 0.923077 2020.0 1.563156
4 No description has been provided for this image Jigokuraku TV 46569 0.551048 8.224549 1.000000 2023.0 1.561658
36 No description has been provided for this image Vinland Saga Season 2 TV 49387 0.452953 8.771356 1.000000 2023.0 1.560571
34 No description has been provided for this image Kimetsu no Yaiba: Yuukaku-hen TV 47778 0.453753 8.794506 0.948718 2021.0 1.553637
7 No description has been provided for this image Kimetsu no Yaiba TV 38000 0.506242 8.498085 0.897436 2019.0 1.543502
27 No description has been provided for this image Kimetsu no Yaiba: Katanakaji no Sato-hen TV 51019 0.457070 8.467293 1.000000 2023.0 1.526882
25 No description has been provided for this image Kimetsu no Yaiba: Mugen Ressha-hen TV 49926 0.457433 8.380549 0.948718 2021.0 1.506464
16 No description has been provided for this image Dorohedoro TV 38668 0.481031 8.048611 0.923077 2020.0 1.477550
13 No description has been provided for this image Noragami Aragoto TV 30503 0.497718 8.156397 0.794872 2015.0 1.476190
10 No description has been provided for this image Heion Sedai no Idaten-tachi TV 42625 0.501803 7.609725 0.948718 2021.0 1.444137
29 No description has been provided for this image Toaru Kagaku no Railgun S TV 16049 0.456802 8.005639 0.743590 2013.0 1.420020
26 No description has been provided for this image Magi: Sinbad no Bouken (TV) TV 31741 0.457099 7.839802 0.820513 2016.0 1.415706
42 No description has been provided for this image Noragami TV 20507 0.451205 7.947757 0.769231 2014.0 1.414397
1 No description has been provided for this image The God of High School TV 41353 0.553590 7.067536 0.923077 2020.0 1.409161
5 No description has been provided for this image Garo: Honoo no Kokuin TV 23311 0.547912 7.317473 0.769231 2014.0 1.404523
6 No description has been provided for this image Shingeki no Bahamut: Virgin Soul TV 30736 0.509020 7.409368 0.846154 2017.0 1.404489
18 No description has been provided for this image Nanatsu no Taizai: Imashime no Fukkatsu TV 34577 0.464332 7.586863 0.871795 2018.0 1.400528
30 No description has been provided for this image D.Gray-man Hallow TV 32370 0.456173 7.671143 0.820513 2016.0 1.394837
15 No description has been provided for this image Akame ga Kill! TV 22199 0.494949 7.468480 0.769231 2014.0 1.386629
20 No description has been provided for this image Maou Gakuin no Futekigousha: Shijou Saikyou no Maou no Shiso, Tensei shite Shison-tachi no Gakkou e Kayou TV 40496 0.458735 7.375983 0.923077 2020.0 1.381673
41 No description has been provided for this image Nanatsu no Taizai TV 23755 0.451250 7.668250 0.769231 2014.0 1.380887
22 No description has been provided for this image Shingeki no Bahamut: Genesis TV 21843 0.458067 7.607811 0.769231 2014.0 1.378269
In [ ]:
df = get_recommendations101(title='Naruto: Shippuuden', n=10)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name Type anime_id similarity_score weighted_rating recency_score release_year final_score
3 No description has been provided for this image Bleach: Sennen Kessen-hen TV 41467 0.608061 9.048079 0.976744 2022.0 1.694600
15 No description has been provided for this image Hunter x Hunter (2011) TV 11061 0.554940 9.037173 0.720930 2011.0 1.606006
0 No description has been provided for this image Naruto TV 20 0.774972 7.988501 0.511628 2002.0 1.587927
38 No description has been provided for this image Fullmetal Alchemist: Brotherhood TV 5114 0.517224 9.097636 0.674419 2009.0 1.578312
17 No description has been provided for this image Black Clover TV 34572 0.554523 8.136070 0.860465 2017.0 1.525497
8 No description has been provided for this image Akatsuki no Yona TV 25013 0.566378 8.022766 0.790698 2014.0 1.506009
2 No description has been provided for this image Bleach TV 269 0.652481 7.917476 0.558140 2004.0 1.505412
29 No description has been provided for this image Magi: The Kingdom of Magic TV 18115 0.521890 8.212752 0.767442 2013.0 1.493904
13 No description has been provided for this image Dragon Quest: Dai no Daibouken (2020) TV 40906 0.555825 7.643075 0.930233 2020.0 1.481176
41 No description has been provided for this image One Piece TV 21 0.514408 8.686696 0.441860 1999.0 1.480573
In [ ]:
get_recommendations101(title='Naruto: Shippuuden', n=24)
Out[ ]:
Image URL Name Type anime_id similarity_score weighted_rating recency_score release_year final_score
3 https://cdn.myanimelist.net/images/anime/1908/... Bleach: Sennen Kessen-hen TV 41467 0.608061 9.048079 0.976744 2022.0 1.694600
15 https://cdn.myanimelist.net/images/anime/1337/... Hunter x Hunter (2011) TV 11061 0.554940 9.037173 0.720930 2011.0 1.606006
0 https://cdn.myanimelist.net/images/anime/13/17... Naruto TV 20 0.774972 7.988501 0.511628 2002.0 1.587927
38 https://cdn.myanimelist.net/images/anime/1208/... Fullmetal Alchemist: Brotherhood TV 5114 0.517224 9.097636 0.674419 2009.0 1.578312
17 https://cdn.myanimelist.net/images/anime/2/883... Black Clover TV 34572 0.554523 8.136070 0.860465 2017.0 1.525497
8 https://cdn.myanimelist.net/images/anime/9/642... Akatsuki no Yona TV 25013 0.566378 8.022766 0.790698 2014.0 1.506009
2 https://cdn.myanimelist.net/images/anime/3/404... Bleach TV 269 0.652481 7.917476 0.558140 2004.0 1.505412
29 https://cdn.myanimelist.net/images/anime/13/55... Magi: The Kingdom of Magic TV 18115 0.521890 8.212752 0.767442 2013.0 1.493904
13 https://cdn.myanimelist.net/images/anime/1499/... Dragon Quest: Dai no Daibouken (2020) TV 40906 0.555825 7.643075 0.930233 2020.0 1.481176
41 https://cdn.myanimelist.net/images/anime/6/732... One Piece TV 21 0.514408 8.686696 0.441860 1999.0 1.480573
4 https://cdn.myanimelist.net/images/anime/1228/... Yuu☆Yuu☆Hakusho TV 392 0.601279 8.448490 0.279070 1992.0 1.478502
19 https://cdn.myanimelist.net/images/anime/1305/... Hunter x Hunter TV 136 0.553618 8.397139 0.441860 1999.0 1.472489
11 https://cdn.myanimelist.net/images/anime/1536/... Fairy Tail: Final Series TV 35972 0.556090 7.561180 0.883721 2018.0 1.462227
7 https://cdn.myanimelist.net/images/anime/3/605... Fairy Tail (2014) TV 22043 0.567061 7.645865 0.790698 2014.0 1.461245
10 https://cdn.myanimelist.net/images/anime/13/75... D.Gray-man TV 1482 0.556384 8.009810 0.604651 2006.0 1.460448
39 https://cdn.myanimelist.net/images/anime/10/78... Magi: Sinbad no Bouken (TV) TV 31741 0.516638 7.839802 0.837209 2016.0 1.459532
22 https://cdn.myanimelist.net/images/anime/1620/... Naruto: Shippuuden Movie 6 - Road to Ninja Movie 13667 0.549877 7.668692 0.744186 2012.0 1.442996
42 https://cdn.myanimelist.net/images/anime/1498/... Tokyo Ghoul TV 22319 0.513830 7.788620 0.790698 2014.0 1.442179
36 https://cdn.myanimelist.net/images/anime/12/80... D.Gray-man Hallow TV 32370 0.518820 7.671143 0.837209 2016.0 1.440776
26 https://cdn.myanimelist.net/images/anime/10/59... Dragon Ball Kai (2014) TV 22777 0.524658 7.658538 0.790698 2014.0 1.433931
20 https://cdn.myanimelist.net/images/anime/6/508... Juuni Kokuki TV 153 0.550869 7.957254 0.511628 2002.0 1.431787
18 https://cdn.myanimelist.net/images/anime/5/181... Fairy Tail TV 6702 0.554407 7.567877 0.674419 2009.0 1.420026
1 https://cdn.myanimelist.net/images/anime/1091/... Boruto: Naruto Next Generations TV 34566 0.764856 6.061365 0.860465 2017.0 1.419559
25 https://cdn.myanimelist.net/images/anime/1102/... Dragon Ball Kai TV 6033 0.525941 7.719814 0.674419 2009.0 1.418901

**Final Analysis of get_recommendations101() for *Naruto: Shippuuden***¶

The output of get_recommendations101() demonstrates the most balanced and refined results compared to previous recommendation versions. It effectively integrates:

  • Semantic relevance through a finely tuned similarity matrix (combined_sim3)
  • Quality assurance via weighted user ratings
  • Freshness bias using a normalized recency score

Why These Are the Best Results Yet¶

1. Relevance & Genre Alignment¶

The top recommendations (e.g., Bleach: Sennen Kessen-hen, Hunter x Hunter, Naruto, Fullmetal Alchemist: Brotherhood) are deeply thematically aligned with Naruto: Shippuuden. They all:

  • Fall within the shounen, action, fantasy, or adventure genres
  • Include strong narratives, ensemble casts, and character development arcs

This confirms that the custom similarity weights are functioning well — giving priority to genres and plot structure (e.g., synopsis_weight = 0.35, genre_weight = 0.30).

2. Quality Scores Still Matter¶

Highly rated titles (e.g., Hunter x Hunter (2011), Fullmetal Alchemist: Brotherhood) appear prominently — despite being older — thanks to their exceptional user scores.

This proves the system does not over-prioritize recency, maintaining a strong quality bias through weighted_rating.

3. Smart Recency Boost¶

Newer anime like:

  • Bleach: Sennen Kessen-hen (2022)
  • Black Clover (2017)
  • Dragon Quest: Dai no Daibouken (2020) appear near the top of the list, showing that modern titles are correctly being elevated in the ranking — without overshadowing the all-time greats.

This affirms that the recency weight (0.2) strikes the right balance between discovery and classic appeal.


Conclusion: Best Results So Far¶

Compared to previous versions (v2, v3, and v4):

  • The results here are more current, more contextually aligned, and less biased toward only legacy titles
  • The hybrid scoring formula allows older masterpieces and modern hits to coexist fairly
  • The tuning of content feature weights in combined_sim3 allows the system to understand what truly matters to the viewer

Lets put them into a class¶

The AnimeRecommender class is a content-based hybrid recommendation system that suggests similar anime using genre, synopsis, type, studio, episode, and source features. It preprocesses data, computes weighted similarities, and enhances results with a recency boost to favor newer titles. It supports both item-based and user-based recommendations with optimized performance using sparse matrices.

In [ ]:
class AnimeRecommender:
    def __init__(self, anime_df, ratings_df):
        # Data loading and type optimization
        self.anime_df = anime_df.copy()
        self.ratings_df = ratings_df.copy()
        self._preprocess_data()
        self._create_feature_matrices()

        # Similarity weights
        self.weights = {
            'genres': 0.30,
            'synopsis': 0.35,
            'type': 0.15,
            'studios': 0.10,
            'episodes': 0.05,
            'source': 0.05
        }

    def _preprocess_data(self):
        """Data cleaning and feature engineering with memory optimization"""
        # Handle missing values
        self.anime_df['Score'] = self.anime_df['Score'].replace('[^0-9.]', '', regex=True)
        self.anime_df['Scored By'] = self.anime_df['Scored By'].replace('[^0-9]', '', regex=True)

        self.anime_df['Score'] = pd.to_numeric(self.anime_df['Score'], errors='coerce')
        self.anime_df['Scored By'] = pd.to_numeric(self.anime_df['Scored By'], errors='coerce')

        self.anime_df['Score'].fillna(self.anime_df['Score'].median(), inplace=True)
        self.anime_df['Scored By'].fillna(self.anime_df['Scored By'].median(), inplace=True)

        self.anime_df['release_year'] = self.anime_df['Aired'].str.extract(r'(\d{4})').astype(float)

        self.anime_df['Genres'] = self.anime_df['Genres'].apply(lambda x: x.split(', ') if x != 'UNKNOWN' else [])
        self.anime_df['Studios'] = self.anime_df['Studios'].apply(lambda x: x.split(', ') if x != 'UNKNOWN' else [])

        # Weighted rating
        C = self.anime_df['Score'].mean()
        m = self.anime_df['Scored By'].quantile(0.65)
        self.anime_df['weighted_rating'] = (
            (self.anime_df['Scored By'] / (self.anime_df['Scored By'] + m)) * self.anime_df['Score'] +
            (m / (self.anime_df['Scored By'] + m)) * C
        )


    def _create_feature_matrices(self):
        """Create sparse feature matrices for fast similarity calculations"""

        # Multi-label genres and studios
        self.mlb_genres = MultiLabelBinarizer(sparse_output=True)
        self.genres_encoded = self.mlb_genres.fit_transform(self.anime_df['Genres'])

        self.mlb_studios = MultiLabelBinarizer(sparse_output=True)
        self.studios_encoded = self.mlb_studios.fit_transform(self.anime_df['Studios'])

        self.ohe_type = OneHotEncoder(sparse_output=True)
        self.type_encoded = self.ohe_type.fit_transform(self.anime_df[['Type']])

        self.ohe_source = OneHotEncoder(sparse_output=True)
        self.source_encoded = self.ohe_source.fit_transform(self.anime_df[['Source']])

        self.anime_df['Episodes'] = pd.to_numeric(self.anime_df['Episodes'], errors='coerce')
        self.median_episodes = self.anime_df['Episodes'].median()
        self.anime_df['Episodes'].fillna(self.median_episodes, inplace=True)


        self.bins = [0, 1, 12, 24, 50, np.inf]
        self.labels = ['1', '2-12', '13-24', '25-50', '51+']
        self.anime_df['Episodes_Binned'] = pd.cut(self.anime_df['Episodes'], bins=self.bins, labels=self.labels)
        self.ohe_episodes = OneHotEncoder(sparse_output=True)
        self.episodes_encoded = self.ohe_episodes.fit_transform(self.anime_df[['Episodes_Binned']])

        # TF-IDF for synopsis
        self.anime_df['Synopsis'] = self._clean_text(self.anime_df['Synopsis'])
        self.tfidf = TfidfVectorizer(stop_words='english')
        self.synopsis_encoded = self.tfidf.fit_transform(self.anime_df['Synopsis'])

    def _clean_text(self, text_series: pd.Series) -> pd.Series:
        """Clean text data by lowercasing and removing punctuation.

        Args:
            text_series: Series of text to clean.

        Returns:
            Cleaned text Series.
        """
        text = text_series.str.lower()
        text = text.str.replace(r'[^\w\s]', '', regex=True)
        return text

    def _calculate_anime_similarity(self, idx: int) -> tuple[np.ndarray, np.ndarray]:
        """Calculate weighted similarity for a single anime using sparse operations.

        Args:
            idx: Index of the target anime.

        Returns:
            Tuple of similarity scores and corresponding indices.
        """
        genres_sim = cosine_similarity(self.genres_encoded[idx:idx+1], self.genres_encoded)[0]
        studios_sim = cosine_similarity(self.studios_encoded[idx:idx+1], self.studios_encoded)[0]
        synopsis_sim = cosine_similarity(self.synopsis_encoded[idx:idx+1], self.synopsis_encoded)[0]
        type_sim = (self.anime_df['Type'] == self.anime_df.iloc[idx]['Type']).astype(float).values
        source_sim = (self.anime_df['Source'] == self.anime_df.iloc[idx]['Source']).astype(float).values
        episodes_sim = (self.anime_df['Episodes_Binned'] == self.anime_df.iloc[idx]['Episodes_Binned']).astype(float).values

        combined_sim = (
            self.weights['genres'] * genres_sim +
            self.weights['synopsis'] * synopsis_sim +
            self.weights['type'] * type_sim +
            self.weights['studios'] * studios_sim +
            self.weights['episodes'] * episodes_sim +
            self.weights['source'] * source_sim
        )

        sim_scores = np.array(list(enumerate(combined_sim)))
        top_indices = sim_scores[:, 1].argsort()[-(52):-1][::-1]
        sim_scores_top = sim_scores[top_indices, 1]
        return sim_scores_top, top_indices

    def _apply_recency_boost(self, df):
        df['year'] = df['release_year']
        df['year'] = df['year'].fillna(df['year'].min())
        min_year = df['year'].min()
        max_year = df['year'].max()
        year_range = max_year - min_year if max_year != min_year else 1
        df['recency_score'] = (df['year'] - min_year) / year_range
        # current_year = 2025.0
        # age = current_year - df['year']
        # df['recency_score'] = 1 / (1 + np.exp(-(10 - age) / 2))
        return df

    def get_anime_recommendations(self, title, n=10, similarity_weight=0.85, recency_weight=0.2):
        matching_animes = self.anime_df[self.anime_df['Name'] == title]
        if matching_animes.empty:
            raise ValueError(f"Anime '{title}' not found in the database.")
        idx = matching_animes.index[0]

        # Compute similarity vectors
        sim_scores_top, top_indices = self._calculate_anime_similarity(idx)

        # Fetch recommended anime
        recommended_animes = self.anime_df.iloc[top_indices][
            ['Image URL', 'Name', 'anime_id',  'Type', 'Genres', 'Score', 'weighted_rating', 'release_year']
        ].copy()
        recommended_animes = self._apply_recency_boost(recommended_animes)
        recommended_animes['similarity_score'] = sim_scores_top

        # Compute final score
        recommended_animes['final_score'] = (
            (1-similarity_weight) * recommended_animes['weighted_rating'] +
            similarity_weight * recommended_animes['similarity_score'])* (1-recency_weight) + (recency_weight * recommended_animes['recency_score'])

        return recommended_animes.sort_values('final_score', ascending=False).head(n)
  • create an inastance from it
In [ ]:
recommender = AnimeRecommender(anime_df, ratings_df)

Lets test the recommendations

In [ ]:
df = recommender.get_anime_recommendations('Kimetsu no Yaiba', n=10)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating release_year year recency_score similarity_score final_score
20430 No description has been provided for this image Kimetsu no Yaiba: Yuukaku-hen 47778 TV [Action, Fantasy] 8.80 8.794506 2021.0 2021.0 0.948718 0.606117 1.657244
22048 No description has been provided for this image Kimetsu no Yaiba: Katanakaji no Sato-hen 51019 TV [Action, Fantasy] 8.49 8.467293 2023.0 2023.0 1.000000 0.642217 1.652783
21533 No description has been provided for this image Kimetsu no Yaiba: Mugen Ressha-hen 49926 TV [Action, Fantasy] 8.39 8.380549 2021.0 2021.0 0.948718 0.604693 1.606601
16236 No description has been provided for this image Jujutsu Kaisen 40748 TV [Action, Award Winning, Fantasy] 8.64 8.637287 2020.0 2020.0 0.923077 0.506242 1.565335
18172 No description has been provided for this image Chainsaw Man 44511 TV [Action, Fantasy] 8.59 8.584003 2022.0 2022.0 0.974359 0.454961 1.534326
16060 No description has been provided for this image Kimetsu no Yaiba Movie: Mugen Ressha-hen 40456 Movie [Action, Fantasy] 8.62 8.615747 2020.0 2020.0 0.923077 0.453053 1.526581
6589 No description has been provided for this image Fate/Zero 2nd Season 11741 TV [Action, Fantasy, Supernatural] 8.55 8.544452 2012.0 2012.0 0.717949 0.456234 1.479163
14835 No description has been provided for this image Toaru Kagaku no Railgun T 38481 TV [Action, Fantasy, Sci-Fi] 8.17 8.134640 2020.0 2020.0 0.923077 0.450000 1.466772
9821 No description has been provided for this image Fate/stay night: Unlimited Blade Works 2nd Season 28701 TV [Action, Fantasy, Supernatural] 8.32 8.313739 2015.0 2015.0 0.794872 0.454354 1.465584
10527 No description has been provided for this image Noragami Aragoto 30503 TV [Action, Fantasy] 8.16 8.156397 2015.0 2015.0 0.794872 0.449720 1.443551
In [ ]:
df = recommender.get_anime_recommendations('Jujutsu Kaisen', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating release_year year recency_score similarity_score final_score
18172 No description has been provided for this image Chainsaw Man 44511 TV [Action, Fantasy] 8.59 8.584003 2022.0 2022.0 0.974359 0.553409 1.601270
16617 No description has been provided for this image Bleach: Sennen Kessen-hen 41467 TV [Action, Adventure, Fantasy] 9.07 9.048079 2022.0 2022.0 0.974359 0.462662 1.595251
15822 No description has been provided for this image Shingeki no Kyojin: The Final Season 40028 TV [Action, Drama] 8.80 8.796520 2020.0 2020.0 0.923077 0.474939 1.563156
19600 No description has been provided for this image Jigokuraku 46569 TV [Action, Adventure, Fantasy] 8.26 8.224549 2023.0 2023.0 1.000000 0.551048 1.561658
21303 No description has been provided for this image Vinland Saga Season 2 49387 TV [Action, Adventure, Drama] 8.81 8.771356 2023.0 2023.0 1.000000 0.452953 1.560571
20430 No description has been provided for this image Kimetsu no Yaiba: Yuukaku-hen 47778 TV [Action, Fantasy] 8.80 8.794506 2021.0 2021.0 0.948718 0.453753 1.553637
14539 No description has been provided for this image Kimetsu no Yaiba 38000 TV [Action, Award Winning, Fantasy] 8.50 8.498085 2019.0 2019.0 0.897436 0.506242 1.543502
22048 No description has been provided for this image Kimetsu no Yaiba: Katanakaji no Sato-hen 51019 TV [Action, Fantasy] 8.49 8.467293 2023.0 2023.0 1.000000 0.457070 1.526882
21533 No description has been provided for this image Kimetsu no Yaiba: Mugen Ressha-hen 49926 TV [Action, Fantasy] 8.39 8.380549 2021.0 2021.0 0.948718 0.457433 1.506464
14942 No description has been provided for this image Dorohedoro 38668 TV [Action, Comedy, Fantasy, Horror] 8.06 8.048611 2020.0 2020.0 0.923077 0.481031 1.477550
10527 No description has been provided for this image Noragami Aragoto 30503 TV [Action, Fantasy] 8.16 8.156397 2015.0 2015.0 0.794872 0.497718 1.476190
17060 No description has been provided for this image Heion Sedai no Idaten-tachi 42625 TV [Action, Adventure, Fantasy] 7.64 7.609725 2021.0 2021.0 0.948718 0.501803 1.444137
7354 No description has been provided for this image Toaru Kagaku no Railgun S 16049 TV [Action, Fantasy, Sci-Fi] 8.02 8.005639 2013.0 2013.0 0.743590 0.456802 1.420020
11043 No description has been provided for this image Magi: Sinbad no Bouken (TV) 31741 TV [Action, Adventure, Fantasy] 7.85 7.839802 2016.0 2016.0 0.820513 0.457099 1.415706
8268 No description has been provided for this image Noragami 20507 TV [Action, Fantasy] 7.95 7.947757 2014.0 2014.0 0.769231 0.451205 1.414397
16560 No description has been provided for this image The God of High School 41353 TV [Action, Fantasy] 7.07 7.067536 2020.0 2020.0 0.923077 0.553590 1.409161
8868 No description has been provided for this image Garo: Honoo no Kokuin 23311 TV [Action, Fantasy] 7.35 7.317473 2014.0 2014.0 0.769231 0.547912 1.404523
10588 No description has been provided for this image Shingeki no Bahamut: Virgin Soul 30736 TV [Action, Adventure, Fantasy] 7.43 7.409368 2017.0 2017.0 0.846154 0.509020 1.404489
12429 No description has been provided for this image Nanatsu no Taizai: Imashime no Fukkatsu 34577 TV [Action, Adventure, Fantasy] 7.59 7.586863 2018.0 2018.0 0.871795 0.464332 1.400528
11291 No description has been provided for this image D.Gray-man Hallow 32370 TV [Action, Adventure, Fantasy] 7.70 7.671143 2016.0 2016.0 0.820513 0.456173 1.394837
8598 No description has been provided for this image Akame ga Kill! 22199 TV [Action, Fantasy] 7.47 7.468480 2014.0 2014.0 0.769231 0.494949 1.386629
16089 No description has been provided for this image Maou Gakuin no Futekigousha: Shijou Saikyou no Maou no Shiso, Tensei shite Shison-tachi no Gakkou e Kayou 40496 TV [Action, Fantasy] 7.38 7.375983 2020.0 2020.0 0.923077 0.458735 1.381673
8981 No description has been provided for this image Nanatsu no Taizai 23755 TV [Action, Adventure, Fantasy] 7.67 7.668250 2014.0 2014.0 0.769231 0.451250 1.380887
8512 No description has been provided for this image Shingeki no Bahamut: Genesis 21843 TV [Action, Adventure, Fantasy] 7.62 7.607811 2014.0 2014.0 0.769231 0.458067 1.378269
In [ ]:
df = recommender.get_anime_recommendations('Darling in the FranXX', n=10)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating release_year year recency_score similarity_score final_score
20964 No description has been provided for this image 86 Part 2 48569 TV [Action, Drama, Sci-Fi] 8.71 8.692836 2021.0 2021.0 0.977778 0.474157 1.561122
8855 No description has been provided for this image Shigatsu wa Kimi no Uso 23273 TV [Drama, Romance] 8.65 8.646914 2014.0 2014.0 0.822222 0.476193 1.525885
16608 No description has been provided for this image 86 41457 TV [Action, Drama, Sci-Fi] 8.28 8.270491 2021.0 2021.0 0.977778 0.477333 1.512601
9604 No description has been provided for this image Plastic Memories 27775 TV [Drama, Romance, Sci-Fi] 7.91 7.904120 2015.0 2015.0 0.844444 0.511800 1.465407
3375 No description has been provided for this image Kidou Senshi Gundam 00 Second Season 3927 TV [Action, Drama, Sci-Fi] 8.08 8.048096 2008.0 2008.0 0.688889 0.474065 1.425914
11072 No description has been provided for this image Kiznaiver 31798 TV [Drama, Romance, Sci-Fi] 7.38 7.374965 2016.0 2016.0 0.866667 0.520255 1.412103
16309 No description has been provided for this image SSSS.Dynazenon 40870 TV [Action, Sci-Fi] 7.42 7.375668 2021.0 2021.0 0.977778 0.478243 1.405841
10540 No description has been provided for this image Soukyuu no Fafner: Dead Aggressor - Exodus Part 2 30549 TV [Action, Drama, Sci-Fi] 7.61 7.309665 2015.0 2015.0 0.844444 0.515709 1.396731
11508 No description has been provided for this image Senki Zesshou Symphogear AXZ 32836 TV [Action, Sci-Fi] 7.60 7.472081 2017.0 2017.0 0.888889 0.472047 1.395420
6358 No description has been provided for this image Guilty Crown 10793 TV [Action, Drama, Sci-Fi] 7.42 7.417078 2011.0 2011.0 0.755556 0.517757 1.393235

Despite offering functional recommendations, the earlier version of the AnimeRecommender class suffered from a notable limitation in how it processed anime synopses. Specifically, the system applied only basic text normalization—lowercasing and punctuation removal—before generating TF-IDF vectors. This naive approach overlooked crucial linguistic elements such as synonyms, verb/noun variations, and context-specific word usage. As a result, the system often failed to capture the deeper semantic similarity between anime plots, especially when two shows shared core themes but used different vocabulary. This limitation diluted the effectiveness of synopsis-based matching, which is arguably one of the most important content features. To address these shortcomings, the updated class integrates a full NLP pipeline—leveraging tokenization, stopword removal, POS tagging, and lemmatization—to produce cleaner and more semantically rich representations, enabling more accurate and meaningful recommendations.

In [ ]:
nltk.download('punkt')
nltk.download('stopwords')
nltk.download('wordnet')
nltk.download('averaged_perceptron_tagger_eng')
nltk.download('universal_tagset')


class AnimeRecommender:
    def __init__(self, anime_df, ratings_df):
        """Initialize the recommender with anime and ratings data."""
        self.anime_df = anime_df.copy()
        self.ratings_df = ratings_df.copy()
        # Initialize NLP tools
        self.lemmatizer = WordNetLemmatizer()
        self.stop_words = set(stopwords.words('english'))
        self._preprocess_data()
        self._create_feature_matrices()

        # Similarity weights
        self.weights = {
            'genres': 0.30,
            'synopsis': 0.35,
            'type': 0.15,
            'studios': 0.10,
            'episodes': 0.05,
            'source': 0.05
        }

    def _preprocess_data(self):
        """Data cleaning and feature engineering with memory optimization."""
        # Handle missing values
        self.anime_df['Score'] = self.anime_df['Score'].replace('[^0-9.]', '', regex=True)
        self.anime_df['Scored By'] = self.anime_df['Scored By'].replace('[^0-9]', '', regex=True)

        self.anime_df['Score'] = pd.to_numeric(self.anime_df['Score'], errors='coerce')
        self.anime_df['Scored By'] = pd.to_numeric(self.anime_df['Scored By'], errors='coerce')

        self.anime_df['Score'].fillna(self.anime_df['Score'].median(), inplace=True)
        self.anime_df['Scored By'].fillna(self.anime_df['Scored By'].median(), inplace=True)

        self.anime_df['Release_year'] = self.anime_df['Aired'].str.extract(r'(\d{4})').astype(float)

        self.anime_df['Genres'] = self.anime_df['Genres'].apply(lambda x: x.split(', ') if x != 'UNKNOWN' else [])
        self.anime_df['Studios'] = self.anime_df['Studios'].apply(lambda x: x.split(', ') if x != 'UNKNOWN' else [])

        # Weighted rating
        C = self.anime_df['Score'].mean()
        m = self.anime_df['Scored By'].quantile(0.65)
        self.anime_df['weighted_rating'] = (
            (self.anime_df['Scored By'] / (self.anime_df['Scored By'] + m)) * self.anime_df['Score'] +
            (m / (self.anime_df['Scored By'] + m)) * C
        )

    def _create_feature_matrices(self):
        """Create sparse feature matrices for fast similarity calculations."""
        # Multi-label genres and studios
        self.mlb_genres = MultiLabelBinarizer(sparse_output=True)
        self.genres_encoded = self.mlb_genres.fit_transform(self.anime_df['Genres'])

        self.mlb_studios = MultiLabelBinarizer(sparse_output=True)
        self.studios_encoded = self.mlb_studios.fit_transform(self.anime_df['Studios'])

        self.ohe_type = OneHotEncoder(sparse_output=True)
        self.type_encoded = self.ohe_type.fit_transform(self.anime_df[['Type']])

        self.ohe_source = OneHotEncoder(sparse_output=True)
        self.source_encoded = self.ohe_source.fit_transform(self.anime_df[['Source']])

        self.anime_df['Episodes'] = pd.to_numeric(self.anime_df['Episodes'], errors='coerce')
        self.median_episodes = self.anime_df['Episodes'].median()
        self.anime_df['Episodes'].fillna(self.median_episodes, inplace=True)

        self.bins = [0, 1, 12, 24, 50, np.inf]
        self.labels = ['1', '2-12', '13-24', '25-50', '51+']
        self.anime_df['Episodes_Binned'] = pd.cut(self.anime_df['Episodes'], bins=self.bins, labels=self.labels)
        self.ohe_episodes = OneHotEncoder(sparse_output=True)
        self.episodes_encoded = self.ohe_episodes.fit_transform(self.anime_df[['Episodes_Binned']])

        # TF-IDF for synopsis with enhanced cleaning
        self.anime_df['Synopsis'] = self._clean_text(self.anime_df['Synopsis'].fillna(''))
        self.tfidf = TfidfVectorizer(stop_words='english')
        self.synopsis_encoded = self.tfidf.fit_transform(self.anime_df['Synopsis'])

    @staticmethod
    def get_wordnet_pos(tag):
        """Map NLTK POS tag to WordNet POS tag for lemmatization.

        Args:
            tag: NLTK POS tag (e.g., 'NN', 'VB').

        Returns:
            WordNet POS tag ('n', 'v', 'a', 'r').
        """
        if tag.startswith('J'):
            return 'a'  # adjective
        elif tag.startswith('V'):
            return 'v'  # verb
        elif tag.startswith('N'):
            return 'n'  # noun
        elif tag.startswith('R'):
            return 'r'  # adverb
        else:
            return 'n'  # default to noun

    def _lemmatize_text(self, text: str) -> str:
        """Lemmatize and clean a single text string.

        Args:
            text: Input text to clean.

        Returns:
            Cleaned and lemmatized text as a string.
        """
        text = text.lower()
        tokens = word_tokenize(text)
        tagged_tokens = nltk.pos_tag(tokens, tagset='universal')
        cleaned_tokens = []
        for token, tag in tagged_tokens:
            if token not in string.punctuation and token not in self.stop_words:
                wordnet_pos = self.get_wordnet_pos(tag)
                lemma = self.lemmatizer.lemmatize(token, pos=wordnet_pos)
                cleaned_tokens.append(lemma)
        return ' '.join(cleaned_tokens)

    def _clean_text(self, text_series: pd.Series) -> pd.Series:
        """Clean text data by lowercasing, tokenizing, removing punctuation and stopwords, and lemmatizing.

        Args:
            text_series: Series of text to clean.

        Returns:
            Cleaned text Series.
        """
        return text_series.apply(self._lemmatize_text)

    def _calculate_anime_similarity(self, idx: int) -> tuple[np.ndarray, np.ndarray]:
        """Calculate weighted similarity for a single anime using sparse operations.

        Args:
            idx: Index of the target anime.

        Returns:
            Tuple of similarity scores and corresponding indices.
        """
        genres_sim = cosine_similarity(self.genres_encoded[idx:idx+1], self.genres_encoded)[0]
        studios_sim = cosine_similarity(self.studios_encoded[idx:idx+1], self.studios_encoded)[0]
        synopsis_sim = cosine_similarity(self.synopsis_encoded[idx:idx+1], self.synopsis_encoded)[0]
        type_sim = (self.anime_df['Type'] == self.anime_df.iloc[idx]['Type']).astype(float).values
        source_sim = (self.anime_df['Source'] == self.anime_df.iloc[idx]['Source']).astype(float).values
        episodes_sim = (self.anime_df['Episodes_Binned'] == self.anime_df.iloc[idx]['Episodes_Binned']).astype(float).values

        combined_sim = (
            self.weights['genres'] * genres_sim +
            self.weights['synopsis'] * synopsis_sim +
            self.weights['type'] * type_sim +
            self.weights['studios'] * studios_sim +
            self.weights['episodes'] * episodes_sim +
            self.weights['source'] * source_sim
        )

        sim_scores = np.array(list(enumerate(combined_sim)))
        top_indices = sim_scores[:, 1].argsort()[-(52):-1][::-1]
        sim_scores_top = sim_scores[top_indices, 1]
        return sim_scores_top, top_indices

    def _apply_recency_boost(self, df):
        """Apply a recency boost based on release year."""
        df['year'] = df['Release_year']
        df['year'] = df['year'].fillna(df['year'].min())
        min_year = df['year'].min()
        max_year = df['year'].max()
        year_range = max_year - min_year if max_year != min_year else 1
        df['recency_score'] = (df['year'] - min_year) / year_range
        return df

    def get_anime_recommendations(self, title, n=10, similarity_weight=0.85, recency_weight=0.2):
        """Generate anime recommendations based on a given title."""
        matching_animes = self.anime_df[self.anime_df['Name'] == title]
        if matching_animes.empty:
            raise ValueError(f"Anime '{title}' not found in the database.")
        idx = matching_animes.index[0]

        sim_scores_top, top_indices = self._calculate_anime_similarity(idx)

        recommended_animes = self.anime_df.iloc[top_indices][
            ['Image URL', 'Name', 'anime_id', 'Type', 'Genres', 'Score', 'weighted_rating', 'Release_year']
        ].copy()
        recommended_animes = self._apply_recency_boost(recommended_animes)
        recommended_animes['similarity_score'] = sim_scores_top

        recommended_animes['final_score'] = (
            (1 - similarity_weight) * recommended_animes['weighted_rating'] +
            similarity_weight * recommended_animes['similarity_score']
        ) * (1 - recency_weight) + (recency_weight * recommended_animes['recency_score'])

        return recommended_animes.sort_values('final_score', ascending=False).head(n)
[nltk_data] Downloading package punkt to /root/nltk_data...
[nltk_data]   Package punkt is already up-to-date!
[nltk_data] Downloading package stopwords to /root/nltk_data...
[nltk_data]   Package stopwords is already up-to-date!
[nltk_data] Downloading package wordnet to /root/nltk_data...
[nltk_data]   Package wordnet is already up-to-date!
[nltk_data] Downloading package averaged_perceptron_tagger_eng to
[nltk_data]     /root/nltk_data...
[nltk_data]   Package averaged_perceptron_tagger_eng is already up-to-
[nltk_data]       date!
[nltk_data] Downloading package universal_tagset to /root/nltk_data...
[nltk_data]   Package universal_tagset is already up-to-date!
  • Lets make and instance of the new class then test it...
In [ ]:
recommender = AnimeRecommender(anime_df, ratings_df)
df = recommender.get_anime_recommendations('Bakemonogatari', n=10)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating Release_year year recency_score similarity_score final_score
12861 No description has been provided for this image Owarimonogatari 2nd Season 35247 TV [Comedy, Mystery, Supernatural] 8.88 8.856249 2017.0 2017.0 0.76 0.642811 1.651861
7556 No description has been provided for this image Monogatari Series: Second Season 17074 TV [Comedy, Mystery, Romance, Supernatural] 8.77 8.757932 2013.0 2013.0 0.60 0.652100 1.614380
10808 No description has been provided for this image Owarimonogatari 31181 TV [Comedy, Mystery, Supernatural] 8.45 8.434069 2015.0 2015.0 0.68 0.606948 1.560813
11052 No description has been provided for this image Kizumonogatari III: Reiketsu-hen 31758 Movie [Action, Mystery, Supernatural] 8.79 8.773543 2017.0 2017.0 0.76 0.475048 1.527858
6553 No description has been provided for this image Nisemonogatari 11597 TV [Comedy, Mystery, Supernatural, Ecchi] 8.14 8.132676 2012.0 2012.0 0.56 0.636405 1.520676
7281 No description has been provided for this image Nekomonogatari: Kuro 15689 TV [Comedy, Romance, Supernatural, Ecchi] 7.93 7.921766 2012.0 2012.0 0.56 0.634826 1.494293
13907 No description has been provided for this image Zoku Owarimonogatari 36999 Movie [Comedy, Mystery, Supernatural] 8.45 8.414520 2018.0 2018.0 0.80 0.468357 1.488225
14179 No description has been provided for this image Seishun Buta Yarou wa Bunny Girl Senpai no Yume wo Minai 37450 TV [Drama, Romance, Supernatural] 8.24 8.236870 2018.0 2018.0 0.80 0.476443 1.472405
9660 No description has been provided for this image Tsukimonogatari 28025 TV [Comedy, Mystery, Supernatural, Ecchi] 8.09 8.077023 2014.0 2014.0 0.64 0.550759 1.471759
5670 No description has been provided for this image Kizumonogatari I: Tekketsu-hen 9260 Movie [Action, Mystery, Supernatural] 8.37 8.357224 2016.0 2016.0 0.72 0.473680 1.468969
In [ ]:
df = recommender.get_anime_recommendations('Darling in the FranXX', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating Release_year year recency_score similarity_score final_score
20964 No description has been provided for this image 86 Part 2 48569 TV [Action, Drama, Sci-Fi] 8.71 8.692836 2021.0 2021.0 0.977778 0.476150 1.562478
8855 No description has been provided for this image Shigatsu wa Kimi no Uso 23273 TV [Drama, Romance] 8.65 8.646914 2014.0 2014.0 0.822222 0.479830 1.528358
16608 No description has been provided for this image 86 41457 TV [Action, Drama, Sci-Fi] 8.28 8.270491 2021.0 2021.0 0.977778 0.477433 1.512669
21948 No description has been provided for this image Lycoris Recoil 50709 TV [Action] 8.20 8.183950 2022.0 2022.0 1.000000 0.472867 1.503623
9604 No description has been provided for this image Plastic Memories 27775 TV [Drama, Romance, Sci-Fi] 7.91 7.904120 2015.0 2015.0 0.844444 0.517298 1.469146
3375 No description has been provided for this image Kidou Senshi Gundam 00 Second Season 3927 TV [Action, Drama, Sci-Fi] 8.08 8.048096 2008.0 2008.0 0.688889 0.480428 1.430240
11072 No description has been provided for this image Kiznaiver 31798 TV [Drama, Romance, Sci-Fi] 7.38 7.374965 2016.0 2016.0 0.866667 0.522201 1.413426
16309 No description has been provided for this image SSSS.Dynazenon 40870 TV [Action, Sci-Fi] 7.42 7.375668 2021.0 2021.0 0.977778 0.479599 1.406763
10540 No description has been provided for this image Soukyuu no Fafner: Dead Aggressor - Exodus Part 2 30549 TV [Action, Drama, Sci-Fi] 7.61 7.309665 2015.0 2015.0 0.844444 0.515613 1.396666
16 No description has been provided for this image Texhnolyze 26 TV [Action, Drama, Sci-Fi] 7.76 7.717234 2003.0 2003.0 0.577778 0.517278 1.393373
6358 No description has been provided for this image Guilty Crown 10793 TV [Action, Drama, Sci-Fi] 7.42 7.417078 2011.0 2011.0 0.755556 0.517905 1.393336
7558 No description has been provided for this image Soukyuu no Fafner: Dead Aggressor - Exodus 17080 TV [Action, Drama, Sci-Fi] 7.37 7.177703 2015.0 2015.0 0.844444 0.519534 1.383496
12271 No description has been provided for this image Grancrest Senki 34279 TV [Action, Drama, Fantasy, Romance] 7.22 7.208601 2018.0 2018.0 0.911111 0.489675 1.380234
7299 No description has been provided for this image Senki Zesshou Symphogear G 15793 TV [Action, Sci-Fi] 7.46 7.396078 2013.0 2013.0 0.800000 0.477679 1.372351
9655 No description has been provided for this image Macross Δ 28013 TV [Action, Romance, Sci-Fi] 7.27 7.213781 2016.0 2016.0 0.866667 0.481872 1.366660
72 No description has been provided for this image Kidou Senshi Gundam SEED 93 TV [Action, Award Winning, Drama, Romance, Sci-Fi] 7.75 7.724560 2002.0 2002.0 0.555556 0.476327 1.361961
10460 No description has been provided for this image Classroom☆Crisis 30383 TV [Drama, Romance, Sci-Fi] 6.97 6.949188 2015.0 2015.0 0.844444 0.517915 1.354973
22263 No description has been provided for this image Engage Kiss 51417 TV [Action, Comedy, Romance] 6.84 6.829794 2022.0 2022.0 1.000000 0.488282 1.351607
8424 No description has been provided for this image Buddy Complex 21437 TV [Action, Sci-Fi] 7.12 7.088736 2014.0 2014.0 0.822222 0.481030 1.342193
5559 No description has been provided for this image Star Driver: Kagayaki no Takuto 8934 TV [Action, Romance, Sci-Fi] 7.19 7.159537 2010.0 2010.0 0.733333 0.484168 1.335045
16266 No description has been provided for this image Hypnosis Mic: Division Rap Battle - Rhyme Anima 40803 TV [Action, Sci-Fi] 6.80 6.764323 2020.0 2020.0 0.955556 0.481011 1.329917
113 No description has been provided for this image Gunslinger Girl 134 TV [Action, Drama, Sci-Fi] 7.39 7.367269 2003.0 2003.0 0.577778 0.480128 1.326115
73 No description has been provided for this image Kidou Senshi Gundam SEED Destiny 94 TV [Action, Drama, Romance, Sci-Fi] 7.18 7.158412 2004.0 2004.0 0.600000 0.510245 1.325976
69 No description has been provided for this image Shin Kidou Senki Gundam Wing 90 TV [Action, Drama, Sci-Fi] 7.69 7.664281 1995.0 1995.0 0.400000 0.475999 1.323393
In [ ]:
df = recommender.get_anime_recommendations('One Piece', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating Release_year year recency_score similarity_score final_score
14699 No description has been provided for this image One Piece Movie 14: Stampede 38234 Movie [Action, Adventure, Fantasy] 8.22 8.190025 2019.0 2019.0 0.868421 0.578450 1.549833
16329 No description has been provided for this image Dragon Quest: Dai no Daibouken (2020) 40906 TV [Action, Adventure, Fantasy] 7.74 7.643075 2020.0 2020.0 0.894737 0.615499 1.514656
13409 No description has been provided for this image One Piece: Episode of East Blue - Luffy to 4-nin no Nakama no Daibouken 36215 Special [Action, Adventure, Fantasy] 7.88 7.758384 2017.0 2017.0 0.815789 0.600029 1.502183
6823 No description has been provided for this image One Piece Film: Z 12859 Movie [Action, Adventure, Fantasy] 8.14 8.121859 2012.0 2012.0 0.684211 0.574520 1.502139
17060 No description has been provided for this image Heion Sedai no Idaten-tachi 42625 TV [Action, Adventure, Fantasy] 7.64 7.609725 2021.0 2021.0 0.921053 0.558974 1.477480
10865 No description has been provided for this image Drifters 31339 TV [Action, Adventure, Comedy, Fantasy] 7.90 7.889898 2016.0 2016.0 0.789474 0.520367 1.458532
3514 No description has been provided for this image One Piece Film: Strong World 4155 Movie [Action, Adventure, Fantasy] 8.08 8.060354 2009.0 2009.0 0.605263 0.542080 1.456910
1574 No description has been provided for this image Naruto: Shippuuden 1735 TV [Action, Adventure, Fantasy] 8.26 8.257899 2007.0 2007.0 0.552632 0.519085 1.454452
11043 No description has been provided for this image Magi: Sinbad no Bouken (TV) 31741 TV [Action, Adventure, Fantasy] 7.85 7.839802 2016.0 2016.0 0.789474 0.522789 1.454167
7119 No description has been provided for this image Magi: The Labyrinth of Magic 14513 TV [Action, Adventure, Fantasy] 8.02 8.014632 2012.0 2012.0 0.684211 0.517040 1.450185
8747 No description has been provided for this image Dragon Ball Kai (2014) 22777 TV [Action, Adventure, Comedy, Fantasy] 7.68 7.658538 2014.0 2014.0 0.736842 0.559808 1.447062
8104 No description has been provided for this image Kyousou Giga (TV) 19703 TV [Action, Fantasy] 7.71 7.666199 2013.0 2013.0 0.710526 0.550316 1.436264
4416 No description has been provided for this image Dragon Ball Kai 6033 TV [Action, Adventure, Comedy, Fantasy] 7.73 7.719814 2009.0 2009.0 0.605263 0.568661 1.434120
10577 No description has been provided for this image Dragon Ball Super 30694 TV [Action, Adventure, Comedy, Fantasy] 7.43 7.426386 2015.0 2015.0 0.763158 0.569198 1.430852
115 No description has been provided for this image Hunter x Hunter 136 TV [Action, Adventure, Fantasy] 8.41 8.397139 1999.0 1999.0 0.342105 0.520165 1.429790
8558 No description has been provided for this image Fairy Tail (2014) 22043 TV [Action, Adventure, Fantasy] 7.65 7.645865 2014.0 2014.0 0.736842 0.521548 1.419525
23543 No description has been provided for this image Hirogaru Sky! Precure 53716 TV [Action, Fantasy] 7.69 6.923455 2023.0 2023.0 0.973684 0.560162 1.406462
21578 No description has been provided for this image Edens Zero 2nd Season 50002 TV [Action, Adventure, Fantasy, Sci-Fi] 7.43 7.164798 2023.0 2023.0 0.973684 0.517489 1.406405
22235 No description has been provided for this image Orient: Awajishima Gekitou-hen 51368 TV [Action, Adventure, Fantasy] 7.04 6.978657 2022.0 2022.0 0.947368 0.550000 1.400913
6018 No description has been provided for this image Toriko 10033 TV [Action, Adventure, Comedy, Fantasy, Gourmet] 7.52 7.481460 2011.0 2011.0 0.657895 0.546293 1.400833
734 No description has been provided for this image Dragon Ball Z 813 TV [Action, Adventure, Comedy, Fantasy] 8.16 8.156166 1989.0 1989.0 0.078947 0.570347 1.382365
11036 No description has been provided for this image Nanatsu no Taizai: Seisen no Shirushi 31722 TV [Action, Adventure, Fantasy] 6.98 6.977496 2016.0 2016.0 0.789474 0.557771 1.374478
4038 No description has been provided for this image One Piece: Romance Dawn Story 5252 OVA [Action, Adventure, Fantasy] 7.34 7.278879 2008.0 2008.0 0.578947 0.563277 1.372283
18914 No description has been provided for this image Orient 45560 TV [Action, Adventure, Fantasy] 6.60 6.590130 2022.0 2022.0 0.947368 0.557117 1.359129
In [ ]:
df = recommender.get_anime_recommendations('Sankarea', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating Release_year year recency_score similarity_score final_score
7481 No description has been provided for this image Kami nomi zo Shiru Sekai: Megami-hen 16706 TV [Comedy, Romance, Supernatural] 8.00 7.985126 2013.0 2013.0 0.756098 0.488362 1.441521
6356 No description has been provided for this image Kore wa Zombie desu ka? of the Dead 10790 TV [Action, Comedy, Supernatural, Ecchi] 7.49 7.480967 2012.0 2012.0 0.731707 0.557525 1.423175
6042 No description has been provided for this image Kami nomi zo Shiru Sekai II 10080 TV [Comedy, Romance, Supernatural] 7.88 7.868894 2011.0 2011.0 0.707317 0.484432 1.415144
10393 No description has been provided for this image Prison School 30240 TV [Comedy, Romance, Ecchi] 7.61 7.606261 2015.0 2015.0 0.804878 0.491384 1.407868
9339 No description has been provided for this image Junjou Romantica 3 25649 TV [Boys Love, Comedy, Drama, Romance] 7.62 7.585614 2015.0 2015.0 0.804878 0.493986 1.407160
11346 No description has been provided for this image Sakamoto desu ga? 32542 TV [Comedy] 7.55 7.544551 2016.0 2016.0 0.829268 0.488381 1.403299
6868 No description has been provided for this image Sankarea OVA 13055 OVA [Comedy, Horror, Romance, Supernatural, Ecchi] 7.20 7.176518 2012.0 2012.0 0.731707 0.578102 1.400633
101 No description has been provided for this image Full Moon wo Sagashite 122 TV [Comedy, Drama, Romance, Supernatural] 7.94 7.883657 2002.0 2002.0 0.487805 0.507293 1.388559
5400 No description has been provided for this image Kami nomi zo Shiru Sekai 8525 TV [Comedy, Romance, Supernatural] 7.66 7.653154 2010.0 2010.0 0.682927 0.489389 1.387748
5528 No description has been provided for this image Kore wa Zombie desu ka? 8841 TV [Action, Comedy, Supernatural, Ecchi] 7.35 7.344986 2011.0 2011.0 0.707317 0.534388 1.386245
3825 No description has been provided for this image Junjou Romantica 2 4814 TV [Boys Love, Comedy, Drama, Romance] 7.71 7.688145 2008.0 2008.0 0.634146 0.484164 1.378638
13735 No description has been provided for this image Yuragi-sou no Yuuna-san 36726 TV [Comedy, Romance, Supernatural, Ecchi] 7.01 7.001053 2018.0 2018.0 0.878049 0.525513 1.373085
7477 No description has been provided for this image Sankarea: Wagahai mo... Zombie de Aru... 16694 Special [Comedy, Horror, Romance, Supernatural, Ecchi] 7.21 7.180576 2012.0 2012.0 0.731707 0.533066 1.370496
6447 No description has been provided for this image Inu x Boku SS 11013 TV [Comedy, Romance, Supernatural] 7.39 7.382382 2012.0 2012.0 0.731707 0.490564 1.365811
2803 No description has been provided for this image Junjou Romantica 3092 TV [Boys Love, Comedy, Drama, Romance] 7.50 7.486325 2008.0 2008.0 0.634146 0.493713 1.360913
23138 No description has been provided for this image Megami no Café Terrace 52973 TV [Comedy, Romance, Ecchi] 7.00 6.920619 2023.0 2023.0 1.000000 0.484855 1.360176
8260 No description has been provided for this image Inari, Konkon, Koi Iroha. 20457 TV [Comedy, Romance, Supernatural] 7.20 7.177983 2014.0 2014.0 0.780488 0.487832 1.349181
801 No description has been provided for this image Amaenaide yo!! Katsu!! 886 TV [Comedy, Romance, Supernatural, Ecchi] 6.65 6.633160 2006.0 2006.0 0.585366 0.623298 1.336895
10872 No description has been provided for this image Tonkatsu DJ Agetarou 31370 TV [Comedy] 7.13 6.967501 2016.0 2016.0 0.829268 0.491784 1.336367
15019 No description has been provided for this image Midara na Ao-chan wa Benkyou ga Dekinai 38778 TV [Comedy, Romance, Ecchi] 6.72 6.715492 2019.0 2019.0 0.902439 0.492061 1.320949
554 No description has been provided for this image Amaenaide yo!! 591 TV [Comedy, Romance, Supernatural, Ecchi] 6.45 6.446868 2005.0 2005.0 0.560976 0.621510 1.308446
16752 No description has been provided for this image Megami-ryou no Ryoubo-kun. 41812 TV [Comedy, Romance, Ecchi] 6.52 6.516778 2021.0 2021.0 0.951220 0.493035 1.307521
4541 No description has been provided for this image Omamori Himari 6324 TV [Action, Comedy, Romance, Supernatural, Ecchi] 6.84 6.833340 2010.0 2010.0 0.682927 0.502122 1.298029
2932 No description has been provided for this image Hatenkou Yuugi 3298 TV [Adventure, Comedy, Drama, Fantasy, Romance] 7.11 7.037438 2008.0 2008.0 0.634146 0.480274 1.297908
In [ ]:
df = recommender.get_anime_recommendations('Kimetsu no Yaiba', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating Release_year year recency_score similarity_score final_score
22048 No description has been provided for this image Kimetsu no Yaiba: Katanakaji no Sato-hen 51019 TV [Action, Fantasy] 8.49 8.467293 2023.0 2023.0 1.000000 0.675826 1.675637
20430 No description has been provided for this image Kimetsu no Yaiba: Yuukaku-hen 47778 TV [Action, Fantasy] 8.80 8.794506 2021.0 2021.0 0.948718 0.627257 1.671619
21533 No description has been provided for this image Kimetsu no Yaiba: Mugen Ressha-hen 49926 TV [Action, Fantasy] 8.39 8.380549 2021.0 2021.0 0.948718 0.627586 1.622168
16236 No description has been provided for this image Jujutsu Kaisen 40748 TV [Action, Award Winning, Fantasy] 8.64 8.637287 2020.0 2020.0 0.923077 0.510968 1.568548
16060 No description has been provided for this image Kimetsu no Yaiba Movie: Mugen Ressha-hen 40456 Movie [Action, Fantasy] 8.62 8.615747 2020.0 2020.0 0.923077 0.493573 1.554134
18172 No description has been provided for this image Chainsaw Man 44511 TV [Action, Fantasy] 8.59 8.584003 2022.0 2022.0 0.974359 0.456532 1.535394
6589 No description has been provided for this image Fate/Zero 2nd Season 11741 TV [Action, Fantasy, Supernatural] 8.55 8.544452 2012.0 2012.0 0.717949 0.460878 1.482321
14835 No description has been provided for this image Toaru Kagaku no Railgun T 38481 TV [Action, Fantasy, Sci-Fi] 8.17 8.134640 2020.0 2020.0 0.923077 0.454360 1.469737
9821 No description has been provided for this image Fate/stay night: Unlimited Blade Works 2nd Season 28701 TV [Action, Fantasy, Supernatural] 8.32 8.313739 2015.0 2015.0 0.794872 0.453259 1.464839
10527 No description has been provided for this image Noragami Aragoto 30503 TV [Action, Fantasy] 8.16 8.156397 2015.0 2015.0 0.794872 0.449990 1.443735
7799 No description has been provided for this image Magi: The Kingdom of Magic 18115 TV [Action, Adventure, Fantasy] 8.22 8.212752 2013.0 2013.0 0.743590 0.454806 1.443516
6044 No description has been provided for this image Fate/Zero 10087 TV [Action, Fantasy, Supernatural] 8.28 8.275991 2011.0 2011.0 0.692308 0.457940 1.442980
8617 No description has been provided for this image Fate/stay night: Unlimited Blade Works 22297 TV [Action, Fantasy, Supernatural] 8.19 8.185116 2014.0 2014.0 0.769231 0.450000 1.442060
8268 No description has been provided for this image Noragami 20507 TV [Action, Fantasy] 7.95 7.947757 2014.0 2014.0 0.769231 0.452160 1.415046
7119 No description has been provided for this image Magi: The Labyrinth of Magic 14513 TV [Action, Adventure, Fantasy] 8.02 8.014632 2012.0 2012.0 0.717949 0.452839 1.413276
438 No description has been provided for this image Koukaku Kidoutai: Stand Alone Complex 467 TV [Action, Award Winning, Sci-Fi] 8.42 8.397903 2002.0 2002.0 0.461538 0.456112 1.410212
5958 No description has been provided for this image Ao no Exorcist 9919 TV [Action, Fantasy] 7.50 7.498247 2011.0 2011.0 0.692308 0.526891 1.396537
13644 No description has been provided for this image Hug tto! Precure 36593 TV [Action, Fantasy] 7.85 7.459017 2018.0 2018.0 0.871795 0.454490 1.378495
368 No description has been provided for this image Yuu☆Yuu☆Hakusho 392 TV [Action, Fantasy] 8.46 8.448490 1992.0 1992.0 0.205128 0.462824 1.369565
1654 No description has been provided for this image Claymore 1818 TV [Action, Adventure, Fantasy] 7.74 7.732521 2007.0 2007.0 0.589744 0.472259 1.366987
8598 No description has been provided for this image Akame ga Kill! 22199 TV [Action, Fantasy] 7.47 7.468480 2014.0 2014.0 0.769231 0.460057 1.362903
11869 No description has been provided for this image Ao no Exorcist: Kyoto Fujouou-hen 33506 TV [Action, Fantasy] 7.35 7.345707 2017.0 2017.0 0.846154 0.452590 1.358477
10662 No description has been provided for this image Tales of Zestiria the Cross 30911 TV [Action, Adventure, Fantasy] 7.24 7.229445 2016.0 2016.0 0.820513 0.469140 1.350651
12175 No description has been provided for this image Tales of Zestiria the Cross 2nd Season 34086 TV [Action, Adventure, Fantasy] 7.31 7.288806 2017.0 2017.0 0.846154 0.450000 1.349888
In [ ]:
df = recommender.get_anime_recommendations('Jujutsu Kaisen', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating Release_year year recency_score similarity_score final_score
18172 No description has been provided for this image Chainsaw Man 44511 TV [Action, Fantasy] 8.59 8.584003 2022.0 2022.0 0.974359 0.550663 1.599403
16617 No description has been provided for this image Bleach: Sennen Kessen-hen 41467 TV [Action, Adventure, Fantasy] 9.07 9.048079 2022.0 2022.0 0.974359 0.462249 1.594971
15822 No description has been provided for this image Shingeki no Kyojin: The Final Season 40028 TV [Action, Drama] 8.80 8.796520 2020.0 2020.0 0.923077 0.478012 1.565246
21303 No description has been provided for this image Vinland Saga Season 2 49387 TV [Action, Adventure, Drama] 8.81 8.771356 2023.0 2023.0 1.000000 0.455136 1.562055
19600 No description has been provided for this image Jigokuraku 46569 TV [Action, Adventure, Fantasy] 8.26 8.224549 2023.0 2023.0 1.000000 0.551210 1.561769
20430 No description has been provided for this image Kimetsu no Yaiba: Yuukaku-hen 47778 TV [Action, Fantasy] 8.80 8.794506 2021.0 2021.0 0.948718 0.453632 1.553554
14539 No description has been provided for this image Kimetsu no Yaiba 38000 TV [Action, Award Winning, Fantasy] 8.50 8.498085 2019.0 2019.0 0.897436 0.510968 1.546716
22048 No description has been provided for this image Kimetsu no Yaiba: Katanakaji no Sato-hen 51019 TV [Action, Fantasy] 8.49 8.467293 2023.0 2023.0 1.000000 0.457350 1.527073
21533 No description has been provided for this image Kimetsu no Yaiba: Mugen Ressha-hen 49926 TV [Action, Fantasy] 8.39 8.380549 2021.0 2021.0 0.948718 0.458439 1.507148
14942 No description has been provided for this image Dorohedoro 38668 TV [Action, Comedy, Fantasy, Horror] 8.06 8.048611 2020.0 2020.0 0.923077 0.487813 1.482162
10527 No description has been provided for this image Noragami Aragoto 30503 TV [Action, Fantasy] 8.16 8.156397 2015.0 2015.0 0.794872 0.498468 1.476700
17060 No description has been provided for this image Heion Sedai no Idaten-tachi 42625 TV [Action, Adventure, Fantasy] 7.64 7.609725 2021.0 2021.0 0.948718 0.511230 1.450547
11043 No description has been provided for this image Magi: Sinbad no Bouken (TV) 31741 TV [Action, Adventure, Fantasy] 7.85 7.839802 2016.0 2016.0 0.820513 0.462403 1.419313
7354 No description has been provided for this image Toaru Kagaku no Railgun S 16049 TV [Action, Fantasy, Sci-Fi] 8.02 8.005639 2013.0 2013.0 0.743590 0.453568 1.417821
8268 No description has been provided for this image Noragami 20507 TV [Action, Fantasy] 7.95 7.947757 2014.0 2014.0 0.769231 0.454787 1.416833
10588 No description has been provided for this image Shingeki no Bahamut: Virgin Soul 30736 TV [Action, Adventure, Fantasy] 7.43 7.409368 2017.0 2017.0 0.846154 0.525272 1.415540
16560 No description has been provided for this image The God of High School 41353 TV [Action, Fantasy] 7.07 7.067536 2020.0 2020.0 0.923077 0.555402 1.410393
8868 No description has been provided for this image Garo: Honoo no Kokuin 23311 TV [Action, Fantasy] 7.35 7.317473 2014.0 2014.0 0.769231 0.553839 1.408553
12429 No description has been provided for this image Nanatsu no Taizai: Imashime no Fukkatsu 34577 TV [Action, Adventure, Fantasy] 7.59 7.586863 2018.0 2018.0 0.871795 0.466171 1.401779
11291 No description has been provided for this image D.Gray-man Hallow 32370 TV [Action, Adventure, Fantasy] 7.70 7.671143 2016.0 2016.0 0.820513 0.459543 1.397129
8598 No description has been provided for this image Akame ga Kill! 22199 TV [Action, Fantasy] 7.47 7.468480 2014.0 2014.0 0.769231 0.496125 1.387429
16089 No description has been provided for this image Maou Gakuin no Futekigousha: Shijou Saikyou no Maou no Shiso, Tensei shite Shison-tachi no Gakkou e Kayou 40496 TV [Action, Fantasy] 7.38 7.375983 2020.0 2020.0 0.923077 0.464245 1.385420
8981 No description has been provided for this image Nanatsu no Taizai 23755 TV [Action, Adventure, Fantasy] 7.67 7.668250 2014.0 2014.0 0.769231 0.452539 1.381763
8512 No description has been provided for this image Shingeki no Bahamut: Genesis 21843 TV [Action, Adventure, Fantasy] 7.62 7.607811 2014.0 2014.0 0.769231 0.462259 1.381119
In [ ]:
df = recommender.get_anime_recommendations('Akame ga Kill!', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating Release_year year recency_score similarity_score final_score
20430 No description has been provided for this image Kimetsu no Yaiba: Yuukaku-hen 47778 TV [Action, Fantasy] 8.80 8.794506 2021.0 2021.0 0.948718 0.505584 1.588881
18172 No description has been provided for this image Chainsaw Man 44511 TV [Action, Fantasy] 8.59 8.584003 2022.0 2022.0 0.974359 0.505496 1.568690
22048 No description has been provided for this image Kimetsu no Yaiba: Katanakaji no Sato-hen 51019 TV [Action, Fantasy] 8.49 8.467293 2023.0 2023.0 1.000000 0.515085 1.566333
21533 No description has been provided for this image Kimetsu no Yaiba: Mugen Ressha-hen 49926 TV [Action, Fantasy] 8.39 8.380549 2021.0 2021.0 0.948718 0.505834 1.539376
19600 No description has been provided for this image Jigokuraku 46569 TV [Action, Adventure, Fantasy] 8.26 8.224549 2023.0 2023.0 1.000000 0.501412 1.527906
10527 No description has been provided for this image Noragami Aragoto 30503 TV [Action, Fantasy] 8.16 8.156397 2015.0 2015.0 0.794872 0.551604 1.512833
11043 No description has been provided for this image Magi: Sinbad no Bouken (TV) 31741 TV [Action, Adventure, Fantasy] 7.85 7.839802 2016.0 2016.0 0.820513 0.512621 1.453461
8268 No description has been provided for this image Noragami 20507 TV [Action, Fantasy] 7.95 7.947757 2014.0 2014.0 0.769231 0.508175 1.453136
7354 No description has been provided for this image Toaru Kagaku no Railgun S 16049 TV [Action, Fantasy, Sci-Fi] 8.02 8.005639 2013.0 2013.0 0.743590 0.503693 1.451906
11291 No description has been provided for this image D.Gray-man Hallow 32370 TV [Action, Adventure, Fantasy] 7.70 7.671143 2016.0 2016.0 0.820513 0.509217 1.430907
12429 No description has been provided for this image Nanatsu no Taizai: Imashime no Fukkatsu 34577 TV [Action, Adventure, Fantasy] 7.59 7.586863 2018.0 2018.0 0.871795 0.502224 1.426295
16139 No description has been provided for this image Utawarerumono: Futari no Hakuoro 40590 TV [Action, Drama, Fantasy] 7.53 7.267058 2022.0 2022.0 0.974359 0.521446 1.421502
8981 No description has been provided for this image Nanatsu no Taizai 23755 TV [Action, Adventure, Fantasy] 7.67 7.668250 2014.0 2014.0 0.769231 0.502232 1.415554
14114 No description has been provided for this image Goblin Slayer 37349 TV [Action, Adventure, Fantasy] 7.42 7.417105 2018.0 2018.0 0.871795 0.513614 1.413669
9652 No description has been provided for this image K: Return of Kings 27991 TV [Action, Fantasy] 7.56 7.546610 2015.0 2015.0 0.794872 0.510923 1.411995
16089 No description has been provided for this image Maou Gakuin no Futekigousha: Shijou Saikyou no Maou no Shiso, Tensei shite Shison-tachi no Gakkou e Kayou 40496 TV [Action, Fantasy] 7.38 7.375983 2020.0 2020.0 0.923077 0.500714 1.410219
368 No description has been provided for this image Yuu☆Yuu☆Hakusho 392 TV [Action, Fantasy] 8.46 8.448490 1992.0 1992.0 0.205128 0.505614 1.398662
11869 No description has been provided for this image Ao no Exorcist: Kyoto Fujouou-hen 33506 TV [Action, Fantasy] 7.35 7.345707 2017.0 2017.0 0.846154 0.505658 1.394563
5958 No description has been provided for this image Ao no Exorcist 9919 TV [Action, Fantasy] 7.50 7.498247 2011.0 2011.0 0.692308 0.504723 1.381463
16560 No description has been provided for this image The God of High School 41353 TV [Action, Fantasy] 7.07 7.067536 2020.0 2020.0 0.923077 0.507955 1.378129
7271 No description has been provided for this image Hakkenden: Touhou Hakken Ibun 15613 TV [Action, Fantasy, Mystery] 7.39 7.350037 2013.0 2013.0 0.743590 0.507876 1.376078
8868 No description has been provided for this image Garo: Honoo no Kokuin 23311 TV [Action, Fantasy] 7.35 7.317473 2014.0 2014.0 0.769231 0.503839 1.374554
22625 No description has been provided for this image Yuusha Party wo Tsuihou sareta Beast Tamer, Saikyoushu no Nekomimi Shoujo to Deau 52046 TV [Action, Fantasy] 6.94 6.927540 2022.0 2022.0 0.974359 0.506214 1.370402
8641 No description has been provided for this image Break Blade 22433 TV [Action, Fantasy] 7.25 7.210151 2014.0 2014.0 0.769231 0.512079 1.367278
In [ ]:
df = recommender.get_anime_recommendations('Detective Conan', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating Release_year year recency_score similarity_score final_score
20949 No description has been provided for this image Dr. Stone: New World 48549 TV [Adventure, Comedy, Sci-Fi] 8.25 8.205729 2023.0 2023.0 1.000000 0.552148 1.560148
16299 No description has been provided for this image Dr. Stone: Stone Wars 40852 TV [Adventure, Comedy, Sci-Fi] 8.17 8.164181 2021.0 2021.0 0.948718 0.553571 1.545874
14959 No description has been provided for this image Dr. Stone 38691 TV [Adventure, Comedy, Sci-Fi] 8.29 8.286605 2019.0 2019.0 0.897436 0.502220 1.515390
12160 No description has been provided for this image Detective Conan: Episode One - The Great Detective Turned Small 34036 Special [Adventure, Comedy, Mystery] 8.24 8.034132 2016.0 2016.0 0.820513 0.518734 1.480937
5985 No description has been provided for this image Detective Conan Movie 15: Quarter of Silence 9963 Movie [Adventure, Comedy, Mystery] 8.00 7.900168 2011.0 2011.0 0.692308 0.547287 1.458637
21584 No description has been provided for this image Meitantei Conan: Hannin no Hanzawa-san 50010 TV [Comedy, Mystery] 6.80 6.668162 2022.0 2022.0 0.974359 0.668725 1.449785
1368 No description has been provided for this image Detective Conan Movie 10: Requiem of the Detectives 1506 Movie [Adventure, Comedy, Mystery] 8.04 7.951632 2006.0 2006.0 0.564103 0.551315 1.441911
1233 No description has been provided for this image Detective Conan Movie 05: Countdown to Heaven 1364 Movie [Adventure, Comedy, Mystery] 8.12 8.040221 2001.0 2001.0 0.435897 0.554862 1.429312
7148 No description has been provided for this image Detective Conan Movie 17: Private Eye in the Distant Sea 14735 Movie [Adventure, Comedy, Mystery] 7.67 7.569965 2013.0 2013.0 0.743590 0.541679 1.425456
1236 No description has been provided for this image Detective Conan Movie 08: Magician of the Silver Sky 1367 Movie [Adventure, Comedy, Mystery] 8.06 7.972434 2004.0 2004.0 0.512821 0.538254 1.425269
21157 No description has been provided for this image Lupin III: Part 6 49040 TV [Action, Adventure, Comedy, Mystery] 7.17 6.964761 2021.0 2021.0 0.948718 0.570820 1.413673
1232 No description has been provided for this image Detective Conan Movie 04: Captured in Her Eyes 1363 Movie [Adventure, Comedy, Mystery] 8.03 7.953159 2000.0 2000.0 0.410256 0.534993 1.400226
709 No description has been provided for this image Detective Conan Movie 01: The Timed Skyscraper 779 Movie [Adventure, Comedy, Mystery] 7.85 7.792512 1997.0 1997.0 0.333333 0.583547 1.398580
4584 No description has been provided for this image Detective Conan OVA 09: The Stranger in 10 Years... 6438 OVA [Adventure, Comedy, Mystery] 7.91 7.695124 2009.0 2009.0 0.641026 0.504250 1.394510
6672 No description has been provided for this image Detective Conan Movie 16: The Eleventh Striker 12117 Movie [Adventure, Comedy, Mystery, Sports] 7.71 7.620433 2012.0 2012.0 0.717949 0.494738 1.394464
710 No description has been provided for this image Detective Conan Movie 02: The Fourteenth Target 780 Movie [Adventure, Comedy, Mystery] 7.88 7.813251 1998.0 1998.0 0.358974 0.565530 1.393945
1367 No description has been provided for this image Detective Conan Movie 09: Strategy Above the Depths 1505 Movie [Adventure, Comedy, Mystery] 7.79 7.706469 2005.0 2005.0 0.538462 0.512610 1.381043
8519 No description has been provided for this image The Disappearance of Conan Edogawa: The Worst Two Days in History 21867 Special [Adventure, Comedy, Mystery] 7.77 7.469457 2014.0 2014.0 0.769231 0.486419 1.380946
5428 No description has been provided for this image Detective Conan OVA 10: Kid in Trap Island 8609 OVA [Adventure, Comedy, Mystery] 7.76 7.527941 2010.0 2010.0 0.666667 0.495336 1.373515
711 No description has been provided for this image Detective Conan Movie 03: The Last Wizard of the Century 781 Movie [Adventure, Comedy, Mystery] 8.03 7.958093 1999.0 1999.0 0.384615 0.497186 1.369981
1235 No description has been provided for this image Detective Conan Movie 07: Crossroad in the Ancient Capital 1366 Movie [Adventure, Comedy, Mystery] 7.80 7.720456 2003.0 2003.0 0.487179 0.507417 1.368934
12306 No description has been provided for this image Alice to Zouroku 34350 TV [Adventure, Mystery] 7.10 7.074564 2017.0 2017.0 0.846154 0.502045 1.359569
16290 No description has been provided for this image Kanojo, Okarishimasu 40839 TV [Comedy, Romance] 7.06 7.057983 2020.0 2020.0 0.923077 0.477707 1.356414
1988 No description has been provided for this image Detective Conan Movie 11: Jolly Roger in the Deep Azure 2171 Movie [Adventure, Comedy, Mystery] 7.43 7.361065 2007.0 2007.0 0.589744 0.516618 1.352577
In [ ]:
df = recommender.get_anime_recommendations('Tensei shitara Slime Datta Ken', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating Release_year year recency_score similarity_score final_score
15568 No description has been provided for this image Tensei shitara Slime Datta Ken 2nd Season 39551 TV [Action, Adventure, Comedy, Fantasy] 8.39 8.382957 2021.0 2021.0 0.943396 0.667592 1.648596
16626 No description has been provided for this image Tensei shitara Slime Datta Ken 2nd Season Part 2 41487 TV [Action, Adventure, Comedy, Fantasy] 8.33 8.321181 2021.0 2021.0 0.943396 0.649520 1.628894
16617 No description has been provided for this image Bleach: Sennen Kessen-hen 41467 TV [Action, Adventure, Fantasy] 9.07 9.048079 2022.0 2022.0 0.962264 0.514879 1.628340
19600 No description has been provided for this image Jigokuraku 46569 TV [Action, Adventure, Fantasy] 8.26 8.224549 2023.0 2023.0 0.981132 0.523541 1.539180
16627 No description has been provided for this image Tensura Nikki: Tensei shitara Slime Datta Ken 41488 TV [Comedy, Fantasy] 7.59 7.574482 2021.0 2021.0 0.943396 0.561880 1.479696
11043 No description has been provided for this image Magi: Sinbad no Bouken (TV) 31741 TV [Action, Adventure, Fantasy] 7.85 7.839802 2016.0 2016.0 0.849057 0.520858 1.464771
13221 No description has been provided for this image Lupin III: Part 5 35857 TV [Action, Adventure, Comedy, Mystery] 8.13 7.955901 2018.0 2018.0 0.886792 0.483682 1.460971
10865 No description has been provided for this image Drifters 31339 TV [Action, Adventure, Comedy, Fantasy] 7.90 7.889898 2016.0 2016.0 0.849057 0.506194 1.460811
12429 No description has been provided for this image Nanatsu no Taizai: Imashime no Fukkatsu 34577 TV [Action, Adventure, Fantasy] 7.59 7.586863 2018.0 2018.0 0.886792 0.525673 1.445240
11291 No description has been provided for this image D.Gray-man Hallow 32370 TV [Action, Adventure, Fantasy] 7.70 7.671143 2016.0 2016.0 0.849057 0.516394 1.441496
12531 No description has been provided for this image Mahoujin Guruguru (2017) 34745 TV [Adventure, Comedy, Fantasy] 7.81 7.597635 2017.0 2017.0 0.867925 0.523176 1.441061
21510 No description has been provided for this image Tensei shitara Slime Datta Ken Movie: Guren no Kizuna-hen 49877 Movie [Action, Adventure, Comedy, Fantasy] 7.63 7.587295 2022.0 2022.0 0.962264 0.496722 1.440699
8981 No description has been provided for this image Nanatsu no Taizai 23755 TV [Action, Adventure, Fantasy] 7.67 7.668250 2014.0 2014.0 0.811321 0.516120 1.433416
13124 No description has been provided for this image Yama no Susume Third Season 35672 TV [Adventure, Comedy, Slice of Life] 7.59 7.401887 2018.0 2018.0 0.886792 0.528555 1.425003
4416 No description has been provided for this image Dragon Ball Kai 6033 TV [Action, Adventure, Comedy, Fantasy] 7.73 7.719814 2009.0 2009.0 0.716981 0.517971 1.421994
8747 No description has been provided for this image Dragon Ball Kai (2014) 22777 TV [Action, Adventure, Comedy, Fantasy] 7.68 7.658538 2014.0 2014.0 0.811321 0.500000 1.421289
14524 No description has been provided for this image Kumo desu ga, Nani ka? 37984 TV [Action, Adventure, Comedy, Fantasy, Mystery] 7.45 7.441162 2021.0 2021.0 0.943396 0.499163 1.421050
11801 No description has been provided for this image Cardcaptor Sakura: Clear Card-hen 33354 TV [Adventure, Comedy, Fantasy, Romance] 7.65 7.600925 2018.0 2018.0 0.886792 0.480401 1.416142
15029 No description has been provided for this image Tensei shitara Slime Datta Ken OVA 38793 OVA [Action, Adventure, Comedy, Fantasy] 7.49 7.472148 2019.0 2019.0 0.905660 0.494457 1.414021
8423 No description has been provided for this image Yama no Susume Second Season 21435 TV [Adventure, Comedy, Slice of Life] 7.56 7.433861 2014.0 2014.0 0.811321 0.528944 1.414009
10577 No description has been provided for this image Dragon Ball Super 30694 TV [Action, Adventure, Comedy, Fantasy] 7.43 7.426386 2015.0 2015.0 0.830189 0.509236 1.403485
734 No description has been provided for this image Dragon Ball Z 813 TV [Action, Adventure, Comedy, Fantasy] 8.16 8.156166 1989.0 1989.0 0.339623 0.513078 1.395558
7347 No description has been provided for this image Tokyo Ravens 16011 TV [Action, Fantasy, Romance] 7.43 7.421522 2013.0 2013.0 0.792453 0.480625 1.375898
12183 No description has been provided for this image Knight's & Magic 34104 TV [Action, Fantasy] 7.08 7.070405 2017.0 2017.0 0.867925 0.518234 1.374433
In [ ]:
df = recommender.get_anime_recommendations('Darling in the FranXX', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating Release_year year recency_score similarity_score final_score
20964 No description has been provided for this image 86 Part 2 48569 TV [Action, Drama, Sci-Fi] 8.71 8.692836 2021.0 2021.0 0.977778 0.476150 1.562478
8855 No description has been provided for this image Shigatsu wa Kimi no Uso 23273 TV [Drama, Romance] 8.65 8.646914 2014.0 2014.0 0.822222 0.479830 1.528358
16608 No description has been provided for this image 86 41457 TV [Action, Drama, Sci-Fi] 8.28 8.270491 2021.0 2021.0 0.977778 0.477433 1.512669
21948 No description has been provided for this image Lycoris Recoil 50709 TV [Action] 8.20 8.183950 2022.0 2022.0 1.000000 0.472867 1.503623
9604 No description has been provided for this image Plastic Memories 27775 TV [Drama, Romance, Sci-Fi] 7.91 7.904120 2015.0 2015.0 0.844444 0.517298 1.469146
3375 No description has been provided for this image Kidou Senshi Gundam 00 Second Season 3927 TV [Action, Drama, Sci-Fi] 8.08 8.048096 2008.0 2008.0 0.688889 0.480428 1.430240
11072 No description has been provided for this image Kiznaiver 31798 TV [Drama, Romance, Sci-Fi] 7.38 7.374965 2016.0 2016.0 0.866667 0.522201 1.413426
16309 No description has been provided for this image SSSS.Dynazenon 40870 TV [Action, Sci-Fi] 7.42 7.375668 2021.0 2021.0 0.977778 0.479599 1.406763
10540 No description has been provided for this image Soukyuu no Fafner: Dead Aggressor - Exodus Part 2 30549 TV [Action, Drama, Sci-Fi] 7.61 7.309665 2015.0 2015.0 0.844444 0.515613 1.396666
16 No description has been provided for this image Texhnolyze 26 TV [Action, Drama, Sci-Fi] 7.76 7.717234 2003.0 2003.0 0.577778 0.517278 1.393373
6358 No description has been provided for this image Guilty Crown 10793 TV [Action, Drama, Sci-Fi] 7.42 7.417078 2011.0 2011.0 0.755556 0.517905 1.393336
7558 No description has been provided for this image Soukyuu no Fafner: Dead Aggressor - Exodus 17080 TV [Action, Drama, Sci-Fi] 7.37 7.177703 2015.0 2015.0 0.844444 0.519534 1.383496
12271 No description has been provided for this image Grancrest Senki 34279 TV [Action, Drama, Fantasy, Romance] 7.22 7.208601 2018.0 2018.0 0.911111 0.489675 1.380234
7299 No description has been provided for this image Senki Zesshou Symphogear G 15793 TV [Action, Sci-Fi] 7.46 7.396078 2013.0 2013.0 0.800000 0.477679 1.372351
9655 No description has been provided for this image Macross Δ 28013 TV [Action, Romance, Sci-Fi] 7.27 7.213781 2016.0 2016.0 0.866667 0.481872 1.366660
72 No description has been provided for this image Kidou Senshi Gundam SEED 93 TV [Action, Award Winning, Drama, Romance, Sci-Fi] 7.75 7.724560 2002.0 2002.0 0.555556 0.476327 1.361961
10460 No description has been provided for this image Classroom☆Crisis 30383 TV [Drama, Romance, Sci-Fi] 6.97 6.949188 2015.0 2015.0 0.844444 0.517915 1.354973
22263 No description has been provided for this image Engage Kiss 51417 TV [Action, Comedy, Romance] 6.84 6.829794 2022.0 2022.0 1.000000 0.488282 1.351607
8424 No description has been provided for this image Buddy Complex 21437 TV [Action, Sci-Fi] 7.12 7.088736 2014.0 2014.0 0.822222 0.481030 1.342193
5559 No description has been provided for this image Star Driver: Kagayaki no Takuto 8934 TV [Action, Romance, Sci-Fi] 7.19 7.159537 2010.0 2010.0 0.733333 0.484168 1.335045
16266 No description has been provided for this image Hypnosis Mic: Division Rap Battle - Rhyme Anima 40803 TV [Action, Sci-Fi] 6.80 6.764323 2020.0 2020.0 0.955556 0.481011 1.329917
113 No description has been provided for this image Gunslinger Girl 134 TV [Action, Drama, Sci-Fi] 7.39 7.367269 2003.0 2003.0 0.577778 0.480128 1.326115
73 No description has been provided for this image Kidou Senshi Gundam SEED Destiny 94 TV [Action, Drama, Romance, Sci-Fi] 7.18 7.158412 2004.0 2004.0 0.600000 0.510245 1.325976
69 No description has been provided for this image Shin Kidou Senki Gundam Wing 90 TV [Action, Drama, Sci-Fi] 7.69 7.664281 1995.0 1995.0 0.400000 0.475999 1.323393
In [ ]:
df = recommender.get_anime_recommendations('Kimetsu no Yaiba', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating Release_year year recency_score similarity_score final_score
22048 No description has been provided for this image Kimetsu no Yaiba: Katanakaji no Sato-hen 51019 TV [Action, Fantasy] 8.49 8.467293 2023.0 2023.0 1.000000 0.675826 1.675637
20430 No description has been provided for this image Kimetsu no Yaiba: Yuukaku-hen 47778 TV [Action, Fantasy] 8.80 8.794506 2021.0 2021.0 0.948718 0.627257 1.671619
21533 No description has been provided for this image Kimetsu no Yaiba: Mugen Ressha-hen 49926 TV [Action, Fantasy] 8.39 8.380549 2021.0 2021.0 0.948718 0.627586 1.622168
16236 No description has been provided for this image Jujutsu Kaisen 40748 TV [Action, Award Winning, Fantasy] 8.64 8.637287 2020.0 2020.0 0.923077 0.510968 1.568548
16060 No description has been provided for this image Kimetsu no Yaiba Movie: Mugen Ressha-hen 40456 Movie [Action, Fantasy] 8.62 8.615747 2020.0 2020.0 0.923077 0.493573 1.554134
18172 No description has been provided for this image Chainsaw Man 44511 TV [Action, Fantasy] 8.59 8.584003 2022.0 2022.0 0.974359 0.456532 1.535394
6589 No description has been provided for this image Fate/Zero 2nd Season 11741 TV [Action, Fantasy, Supernatural] 8.55 8.544452 2012.0 2012.0 0.717949 0.460878 1.482321
14835 No description has been provided for this image Toaru Kagaku no Railgun T 38481 TV [Action, Fantasy, Sci-Fi] 8.17 8.134640 2020.0 2020.0 0.923077 0.454360 1.469737
9821 No description has been provided for this image Fate/stay night: Unlimited Blade Works 2nd Season 28701 TV [Action, Fantasy, Supernatural] 8.32 8.313739 2015.0 2015.0 0.794872 0.453259 1.464839
10527 No description has been provided for this image Noragami Aragoto 30503 TV [Action, Fantasy] 8.16 8.156397 2015.0 2015.0 0.794872 0.449990 1.443735
7799 No description has been provided for this image Magi: The Kingdom of Magic 18115 TV [Action, Adventure, Fantasy] 8.22 8.212752 2013.0 2013.0 0.743590 0.454806 1.443516
6044 No description has been provided for this image Fate/Zero 10087 TV [Action, Fantasy, Supernatural] 8.28 8.275991 2011.0 2011.0 0.692308 0.457940 1.442980
8617 No description has been provided for this image Fate/stay night: Unlimited Blade Works 22297 TV [Action, Fantasy, Supernatural] 8.19 8.185116 2014.0 2014.0 0.769231 0.450000 1.442060
8268 No description has been provided for this image Noragami 20507 TV [Action, Fantasy] 7.95 7.947757 2014.0 2014.0 0.769231 0.452160 1.415046
7119 No description has been provided for this image Magi: The Labyrinth of Magic 14513 TV [Action, Adventure, Fantasy] 8.02 8.014632 2012.0 2012.0 0.717949 0.452839 1.413276
438 No description has been provided for this image Koukaku Kidoutai: Stand Alone Complex 467 TV [Action, Award Winning, Sci-Fi] 8.42 8.397903 2002.0 2002.0 0.461538 0.456112 1.410212
5958 No description has been provided for this image Ao no Exorcist 9919 TV [Action, Fantasy] 7.50 7.498247 2011.0 2011.0 0.692308 0.526891 1.396537
13644 No description has been provided for this image Hug tto! Precure 36593 TV [Action, Fantasy] 7.85 7.459017 2018.0 2018.0 0.871795 0.454490 1.378495
368 No description has been provided for this image Yuu☆Yuu☆Hakusho 392 TV [Action, Fantasy] 8.46 8.448490 1992.0 1992.0 0.205128 0.462824 1.369565
1654 No description has been provided for this image Claymore 1818 TV [Action, Adventure, Fantasy] 7.74 7.732521 2007.0 2007.0 0.589744 0.472259 1.366987
8598 No description has been provided for this image Akame ga Kill! 22199 TV [Action, Fantasy] 7.47 7.468480 2014.0 2014.0 0.769231 0.460057 1.362903
11869 No description has been provided for this image Ao no Exorcist: Kyoto Fujouou-hen 33506 TV [Action, Fantasy] 7.35 7.345707 2017.0 2017.0 0.846154 0.452590 1.358477
10662 No description has been provided for this image Tales of Zestiria the Cross 30911 TV [Action, Adventure, Fantasy] 7.24 7.229445 2016.0 2016.0 0.820513 0.469140 1.350651
12175 No description has been provided for this image Tales of Zestiria the Cross 2nd Season 34086 TV [Action, Adventure, Fantasy] 7.31 7.288806 2017.0 2017.0 0.846154 0.450000 1.349888

While the earlier version of the recommender provided reasonable content-based recommendations, it lacked nuanced control over temporal relevance and user-perceived freshness of anime titles. Specifically, although a recency boost was introduced, it treated all past anime equally without factoring in the anime's current airing status or episode count. This led to scenarios where long-running or still-airing shows were penalized unfairly, and older titles with high episode counts were underrepresented despite still holding popularity. Moreover, there was no mechanism to discourage the system from over-recommending outdated or short-lived anime. To resolve these issues, the updated class introduces a refined age penalty mechanism, dynamically adjusting scores based on whether the anime is currently airing and how many episodes it has. This creates a fairer scoring environment where timeless titles aren't overly suppressed, and still-airing or large-episode anime retain their momentum in the recommendation list. As a result, recommendations now better reflect both content similarity and user-relevant freshness, offering a more practical and satisfying user experience.

AnimeRecommender Class – Advanced Multi-Factor Hybrid Recommendation System¶

Summary:¶

The AnimeRecommender class implements an intelligent, multi-layered recommendation system for anime titles. It integrates content-based similarity, recency weighting, user behavior, and temporal penalty modeling to deliver personalized and high-quality results.


Methodology Overview:¶

The system follows a structured content-based recommendation approach with natural language processing, multi-hot encoding, and temporal scoring. Its major components include:


Core Components & Workflow:¶

1. Initialization & Data Assignment¶

  • Accepts two dataframes:

    • anime_df: Metadata about anime titles.
    • ratings_df: User rating data.
  • Initializes key NLP tools:

    • NLTK-based WordNetLemmatizer
    • stopwords, tokenizers, and POS taggers

2. Data Preprocessing (_preprocess_data)¶

  • Cleans and converts:

    • Score, Scored By, and Episodes columns to numeric.
  • Extracts:

    • Release year from Aired.
    • Multi-label fields: Genres, Studios.
  • Computes:

    • IMDb-style weighted rating:

    $$ \text{weighted_rating} = \frac{v}{v + m}R + \frac{m}{v + m}C $$


3. Feature Engineering (_create_feature_matrices)¶

Encodes core features into machine-readable format:

Feature Encoding Method
Genres, Studios MultiLabelBinarizer
Type, Source OneHotEncoder
Episodes (Binned) Binned + OneHotEncoder
Synopsis TF-IDF with NLTK preprocessing
  • Text cleaning uses:

    • Tokenization
    • Stopword removal
    • POS tagging
    • Lemmatization

4. Similarity Calculation (_calculate_anime_similarity)¶

Calculates weighted cosine similarity between all anime using:

Feature Weight
Genres 0.30
Synopsis (TF-IDF) 0.35
Type 0.15
Studios 0.10
Episodes 0.05
Source 0.05

Returns top N most similar anime based on the composite similarity score.


5. Recency Boost (_calculate_recency_boost)¶

Scales anime by how recent they are:

$$ \text{recency_boost} = \frac{(\text{year} - \text{min})}{\text{max} - \text{min}} $$

Used to amplify new titles in final score.


6. Age Penalty (in get_anime_recommendations1/2)¶

Introduced to penalize:

  • Old, short, completed series
  • While rewarding long or currently airing ones

7. Final Score Combination¶

The final score formula blends:

  • similarity_score
  • weighted_rating
  • recency_score
  • Age penalty (divides or subtracts)

🔍 Available Recommendation Modes:¶

Method Description
get_anime_recommendations Basic similarity + recency weighting
get_anime_recommendations1 Adds age penalty for smarter ranking
get_anime_recommendations2 Alternative penalty scoring logic
get_recommendations_by_genres Genre-driven recommendations with IMDb-style popularity sorting
In [ ]:
nltk.download('punkt')
nltk.download('stopwords')
nltk.download('wordnet')
nltk.download('averaged_perceptron_tagger_eng')
nltk.download('universal_tagset')
nltk.download('punkt_tab')

class AnimeRecommender:
    def __init__(self, anime_df, ratings_df):
        """Initialize the recommender with anime and ratings data."""
        self.anime_df = anime_df.copy()
        self.ratings_df = ratings_df.copy()
        # Initialize NLP tools
        self.lemmatizer = WordNetLemmatizer()
        self.stop_words = set(stopwords.words('english'))
        self._preprocess_data()
        self._create_feature_matrices()

        # Similarity weights
        self.weights = {
            'genres': 0.30,
            'synopsis': 0.35,
            'type': 0.15,
            'studios': 0.10,
            'episodes': 0.05,
            'source': 0.05
        }

    def _preprocess_data(self):
        """Data cleaning and feature engineering with memory optimization."""
        # Handle missing values
        self.anime_df['Score'] = self.anime_df['Score'].replace('[^0-9.]', '', regex=True)
        self.anime_df['Scored By'] = self.anime_df['Scored By'].replace('[^0-9]', '', regex=True)

        self.anime_df['Score'] = pd.to_numeric(self.anime_df['Score'], errors='coerce')
        self.anime_df['Scored By'] = pd.to_numeric(self.anime_df['Scored By'], errors='coerce')

        self.anime_df['Score'].fillna(self.anime_df['Score'].median(), inplace=True)
        self.anime_df['Scored By'].fillna(self.anime_df['Scored By'].median(), inplace=True)

        self.anime_df['Release_year'] = self.anime_df['Aired'].str.extract(r'(\d{4})').astype(float)

        self.anime_df['Genres'] = self.anime_df['Genres'].apply(lambda x: x.split(', ') if x != 'UNKNOWN' else [])
        self.anime_df['Studios'] = self.anime_df['Studios'].apply(lambda x: x.split(', ') if x != 'UNKNOWN' else [])

        # Weighted rating
        C = self.anime_df['Score'].mean()
        m = self.anime_df['Scored By'].quantile(0.65)
        self.anime_df['weighted_rating'] = (
            (self.anime_df['Scored By'] / (self.anime_df['Scored By'] + m)) * self.anime_df['Score'] +
            (m / (self.anime_df['Scored By'] + m)) * C
        )

    def _create_feature_matrices(self):
        """Create sparse feature matrices for fast similarity calculations."""
        # Multi-label genres and studios
        self.mlb_genres = MultiLabelBinarizer(sparse_output=True)
        self.genres_encoded = self.mlb_genres.fit_transform(self.anime_df['Genres'])

        self.mlb_studios = MultiLabelBinarizer(sparse_output=True)
        self.studios_encoded = self.mlb_studios.fit_transform(self.anime_df['Studios'])

        self.ohe_type = OneHotEncoder(sparse_output=True)
        self.type_encoded = self.ohe_type.fit_transform(self.anime_df[['Type']])

        self.ohe_source = OneHotEncoder(sparse_output=True)
        self.source_encoded = self.ohe_source.fit_transform(self.anime_df[['Source']])

        self.anime_df['Episodes'] = pd.to_numeric(self.anime_df['Episodes'], errors='coerce')
        self.median_episodes = self.anime_df['Episodes'].median()
        self.anime_df['Episodes'].fillna(self.median_episodes, inplace=True)

        self.bins = [0, 1, 12, 24, 50, np.inf]
        self.labels = ['1', '2-12', '13-24', '25-50', '51+']
        self.anime_df['Episodes_Binned'] = pd.cut(self.anime_df['Episodes'], bins=self.bins, labels=self.labels)
        self.ohe_episodes = OneHotEncoder(sparse_output=True)
        self.episodes_encoded = self.ohe_episodes.fit_transform(self.anime_df[['Episodes_Binned']])

        # TF-IDF for synopsis with enhanced cleaning
        self.anime_df['Synopsis'] = self._clean_text(self.anime_df['Synopsis'].fillna(''))
        self.tfidf = TfidfVectorizer(stop_words='english')
        self.synopsis_encoded = self.tfidf.fit_transform(self.anime_df['Synopsis'])

    @staticmethod
    def get_wordnet_pos(tag):
        """Map NLTK POS tag to WordNet POS tag for lemmatization."""
        if tag.startswith('J'):
            return 'a'  # adjective
        elif tag.startswith('V'):
            return 'v'  # verb
        elif tag.startswith('N'):
            return 'n'  # noun
        elif tag.startswith('R'):
            return 'r'  # adverb
        else:
            return 'n'  # default to noun

    def _lemmatize_text(self, text: str) -> str:
        """Lemmatize and clean a single text string."""
        text = text.lower()
        tokens = word_tokenize(text)
        tagged_tokens = nltk.pos_tag(tokens, tagset='universal')
        cleaned_tokens = []
        for token, tag in tagged_tokens:
            if token not in string.punctuation and token not in self.stop_words:
                wordnet_pos = self.get_wordnet_pos(tag)
                lemma = self.lemmatizer.lemmatize(token, pos=wordnet_pos)
                cleaned_tokens.append(lemma)
        return ' '.join(cleaned_tokens)

    def _clean_text(self, text_series: pd.Series) -> pd.Series:
        """Clean text data by lowercasing, tokenizing, removing punctuation and stopwords, and lemmatizing."""
        return text_series.apply(self._lemmatize_text)

    def _calculate_anime_similarity(self, idx: int) -> tuple[np.ndarray, np.ndarray]:
        """Calculate weighted similarity for a single anime using sparse operations."""
        genres_sim = cosine_similarity(self.genres_encoded[idx:idx+1], self.genres_encoded)[0]
        studios_sim = cosine_similarity(self.studios_encoded[idx:idx+1], self.studios_encoded)[0]
        synopsis_sim = cosine_similarity(self.synopsis_encoded[idx:idx+1], self.synopsis_encoded)[0]
        type_sim = (self.anime_df['Type'] == self.anime_df.iloc[idx]['Type']).astype(float).values
        source_sim = (self.anime_df['Source'] == self.anime_df.iloc[idx]['Source']).astype(float).values
        episodes_sim = (self.anime_df['Episodes_Binned'] == self.anime_df.iloc[idx]['Episodes_Binned']).astype(float).values

        combined_sim = (
            self.weights['genres'] * genres_sim +
            self.weights['synopsis'] * synopsis_sim +
            self.weights['type'] * type_sim +
            self.weights['studios'] * studios_sim +
            self.weights['episodes'] * episodes_sim +
            self.weights['source'] * source_sim
        )

        sim_scores = np.array(list(enumerate(combined_sim)))
        # Ensure that the number of recommendations requested doesn't exceed the number of available animes minus 1 (to exclude self)
        num_recs_to_get = min(52, len(self.anime_df) - 1)
        # Sort by similarity score in descending order and get top N+1 (including self)
        sorted_sim_scores = sim_scores[sim_scores[:, 1].argsort()[::-1]]
        # Exclude the first element (self) and take the next num_recs_to_get
        top_sim = sorted_sim_scores[1:num_recs_to_get + 1]

        top_indices = top_sim[:, 0].astype(int)
        sim_scores_top = top_sim[:, 1]
        return sim_scores_top, top_indices


    def _calculate_recency_boost(self, release_year):
        """Calculate a simple recency boost score based on the release year."""
        # Assuming a linear boost, you can adjust this formula
        current_year = 2025  # Adjust if needed
        # Handle potential NaN or non-numeric release_year
        year = release_year if pd.notna(release_year) else self.anime_df['Release_year'].min()
        min_year = self.anime_df['Release_year'].min()
        max_year = self.anime_df['Release_year'].max()
        year_range = max_year - min_year if max_year != min_year else 1

        # Scale the year to a 0-1 range
        scaled_year = (year - min_year) / year_range

        # You can adjust the recency boost formula based on scaled_year
        # Example: a simple linear boost where newer anime get a higher score
        recency_boost = scaled_year # A value between 0 and 1

        return recency_boost


    def get_anime_recommendations(self, title, n=10, similarity_weight=0.85, recency_weight=0.2):
        """Generate anime recommendations based on a given title."""
        matching_animes = self.anime_df[self.anime_df['Name'] == title]
        if matching_animes.empty:
            raise ValueError(f"Anime '{title}' not found in the database.")
        idx = matching_animes.index[0]

        sim_scores_top, top_indices = self._calculate_anime_similarity(idx)

        recommended_animes = self.anime_df.iloc[top_indices][
            ['Image URL', 'Name', 'anime_id', 'Type', 'Genres', 'Score', 'weighted_rating', 'Release_year']
        ].copy()

        # Apply the recency boost directly to the recommended animes
        recommended_animes['recency_score'] = recommended_animes['Release_year'].apply(self._calculate_recency_boost)
        recommended_animes['similarity_score'] = sim_scores_top


        rating_weight = 1 - similarity_weight

        # Ensure all weight components are non-negative
        rating_weight = max(0, rating_weight)
        similarity_weight = max(0, similarity_weight)
        recency_weight = max(0, recency_weight)

        qualified_animes = recommended_animes.copy() # Use a consistent variable name

        # Compute final score
        qualified_animes['final_score'] = (
            (1-similarity_weight) * qualified_animes['weighted_rating'] +
            similarity_weight * qualified_animes['similarity_score'])* (1-recency_weight) + (recency_weight * qualified_animes['recency_score'])



        return qualified_animes.sort_values('final_score', ascending=False).head(n)


    def get_recommendations_by_genres(self, genres, n=10):
        """Generate anime recommendations based on specified genres with IMDb-like popularity.

        Args:
            genres (str or List[str]): A single genre or list of genres to base recommendations on.
            n (int, optional): Number of recommendations to return. Defaults to 10.

        Returns:
            DataFrame: Top n anime recommendations with title, genres, final score, and popularity score.
        """
        # Ensure genres is a list
        if isinstance(genres, str):
            genres = [genres]

        # Validate genres
        valid_genres = set(self.mlb_genres.classes_)
        genres = [g for g in genres if g in valid_genres]
        if not genres:
            raise ValueError("No valid genres provided.")

        # Create a genre vector for input genres
        genre_vector = self.mlb_genres.transform([genres]).toarray()[0]

        # Calculate similarity score based on genre overlap
        similarity_scores = (self.genres_encoded.toarray() @ genre_vector).ravel()

        # Create a copy of the anime DataFrame for processing
        recommendations = self.anime_df[['Name', 'Genres', 'Release_year', 'Episodes', 'Status', 'weighted_rating','Image URL']].copy()
        recommendations['similarity_score'] = similarity_scores

        # Filter out anime with no genre overlap
        recommendations = recommendations[recommendations['similarity_score'] > 0]

        # Calculate age penalty
        current_year = 2025  # Current year as of May 21, 2025
        recommendations['end_year'] = recommendations['Release_year'].fillna(current_year)
        recommendations['episodes'] = pd.to_numeric(recommendations['Episodes'], errors='coerce').fillna(self.median_episodes)

        # Apply age penalty: 0 for still airing, reduced penalty for large anime
        recommendations['age_penalty'] = recommendations.apply(
            lambda row: 0 if row['Status'] == 'Currently Airing' else
            (current_year - row['end_year']) * (1 - 0.5 * min(row['episodes'] / 120, 1)),
            axis=1
        )

        # Sort by final score and select top n
        recommendations = recommendations.sort_values(by=['weighted_rating', 'age_penalty'],
        ascending=[ False, True]).head(n)

        # Return relevant columns
        return recommendations[['Image URL','Name', 'Genres', 'age_penalty', 'weighted_rating']]

    def get_anime_recommendations1(self, title, n=10, similarity_weight=0.85, recency_weight=0.2):
        """Generate anime recommendations based on a given title with age penalty."""
        matching_animes = self.anime_df[self.anime_df['Name'] == title]
        if matching_animes.empty:
            raise ValueError(f"Anime '{title}' not found in the database.")
        idx = matching_animes.index[0]

        sim_scores_top, top_indices = self._calculate_anime_similarity(idx)

        recommended_animes = self.anime_df.iloc[top_indices][
            ['Image URL', 'Name', 'anime_id', 'Type', 'Genres', 'Score', 'weighted_rating', 'Release_year', 'Episodes', 'Status']
        ].copy()

        # Calculate similarity and recency scores
        recommended_animes['similarity_score'] = sim_scores_top
        recommended_animes['recency_score'] = recommended_animes['Release_year'].apply(self._calculate_recency_boost)

        # Calculate age penalty
        current_year = 2025  # Current year as of May 25, 2025
        recommended_animes['end_year'] = recommended_animes['Release_year'].fillna(current_year)
        recommended_animes['episodes'] = pd.to_numeric(recommended_animes['Episodes'], errors='coerce').fillna(self.median_episodes)

        recommended_animes['age_penalty'] = recommended_animes.apply(
            lambda row: 0 if row['Status'] == 'Currently Airing' else
            (current_year - row['end_year']) * (1 - 0.5 * min(row['episodes'] / 120, 1)),
            axis=1
        )

        # Ensure weights are non-negative
        rating_weight = max(0, 1 - similarity_weight)
        similarity_weight = max(0, similarity_weight)
        recency_weight = max(0, recency_weight)

        # Compute final score incorporating age penalty
        recommended_animes['final_score'] = (
            (rating_weight * recommended_animes['weighted_rating'] +
            similarity_weight * recommended_animes['similarity_score']) * (1 - recency_weight) +
            recency_weight * recommended_animes['recency_score']
        ) / (1 + recommended_animes['age_penalty'] / 10)  # Scale down age penalty impact

        # Sort by final score and select top n
        return recommended_animes.sort_values('final_score', ascending=False).head(n)[
            ['Image URL', 'Name', 'anime_id', 'Type', 'Genres', 'Score', 'weighted_rating', 'final_score', 'age_penalty']
        ]

    def get_anime_recommendations2(self, title, n=10, similarity_weight=0.85, recency_weight=0.2):
        """Generate anime recommendations based on a given title with age penalty."""
        matching_animes = self.anime_df[self.anime_df['Name'] == title]
        if matching_animes.empty:
            raise ValueError(f"Anime '{title}' not found in the database.")
        idx = matching_animes.index[0]

        sim_scores_top, top_indices = self._calculate_anime_similarity(idx)

        recommended_animes = self.anime_df.iloc[top_indices][
                ['Image URL', 'Name', 'anime_id', 'Type', 'Genres', 'Score', 'weighted_rating', 'Release_year', 'Episodes', 'Status']
            ].copy()

            # Calculate similarity and recency scores
        recommended_animes['similarity_score'] = sim_scores_top
        recommended_animes['recency_score'] = recommended_animes['Release_year'].apply(self._calculate_recency_boost)

            # Calculate age penalty
        current_year = 2025  # Current year as of May 25, 2025
        recommended_animes['end_year'] = recommended_animes['Release_year'].fillna(current_year)
        recommended_animes['episodes'] = pd.to_numeric(recommended_animes['Episodes'], errors='coerce').fillna(self.median_episodes)

        recommended_animes['age_penalty'] = recommended_animes.apply(
                lambda row: 0 if row['Status'] == 'Currently Airing' else
                (current_year - row['end_year']) * (1 - 0.5 * min(row['episodes'] / 120, 1)),
                axis=1
            )

            # Ensure weights are non-negative
        rating_weight = max(0, 1 - similarity_weight)
        similarity_weight = max(0, similarity_weight)
        recency_weight = max(0, recency_weight)

            # Compute final score incorporating age penalty
        recommended_animes['final_score'] = (
                (rating_weight * recommended_animes['weighted_rating'] +
                similarity_weight * recommended_animes['similarity_score']) * (1 - recency_weight) )+(
                recency_weight * recommended_animes['age_penalty']
            )

            # Sort by final score and select top n
        return recommended_animes.sort_values('final_score', ascending=False).head(n)[
                ['Image URL', 'Name', 'anime_id', 'Type', 'Genres', 'Score', 'weighted_rating', 'final_score', 'age_penalty']
            ]
[nltk_data] Downloading package punkt to /root/nltk_data...
[nltk_data]   Package punkt is already up-to-date!
[nltk_data] Downloading package stopwords to /root/nltk_data...
[nltk_data]   Package stopwords is already up-to-date!
[nltk_data] Downloading package wordnet to /root/nltk_data...
[nltk_data]   Package wordnet is already up-to-date!
[nltk_data] Downloading package averaged_perceptron_tagger_eng to
[nltk_data]     /root/nltk_data...
[nltk_data]   Package averaged_perceptron_tagger_eng is already up-to-
[nltk_data]       date!
[nltk_data] Downloading package universal_tagset to /root/nltk_data...
[nltk_data]   Package universal_tagset is already up-to-date!
[nltk_data] Downloading package punkt_tab to /root/nltk_data...
[nltk_data]   Package punkt_tab is already up-to-date!
  • Lets make an instance and show some test...
In [ ]:
AnimeRecommender = AnimeRecommender(anime_df, ratings_df)
df = AnimeRecommender.get_anime_recommendations1('Darling in the FranXX', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating final_score age_penalty
21948 No description has been provided for this image Lycoris Recoil 50709 TV [Action] 8.20 8.183950 1.166947 2.837500
20964 No description has been provided for this image 86 Part 2 48569 TV [Action, Drama, Sci-Fi] 8.71 8.692836 1.130083 3.800000
16608 No description has been provided for this image 86 41457 TV [Action, Drama, Sci-Fi] 8.28 8.270491 1.092670 3.816667
22263 No description has been provided for this image Engage Kiss 51417 TV [Action, Comedy, Romance] 6.84 6.829794 1.048531 2.837500
16309 No description has been provided for this image SSSS.Dynazenon 40870 TV [Action, Sci-Fi] 7.42 7.375668 1.017247 3.800000
21073 No description has been provided for this image Cardfight!! Vanguard: overDress Season 2 48862 TV [Action, Drama] 6.67 6.538178 0.946119 3.783333
16266 No description has been provided for this image Hypnosis Mic: Division Rap Battle - Rhyme Anima 40803 TV [Action, Sci-Fi] 6.80 6.764323 0.902663 4.729167
12271 No description has been provided for this image Grancrest Senki 34279 TV [Action, Drama, Fantasy, Romance] 7.22 7.208601 0.849723 6.300000
11508 No description has been provided for this image Senki Zesshou Symphogear AXZ 32836 TV [Action, Sci-Fi] 7.60 7.472081 0.798264 7.566667
13591 No description has been provided for this image Beatless 36516 TV [Action, Drama, Romance, Sci-Fi] 6.21 6.215648 0.776584 6.416667
8855 No description has been provided for this image Shigatsu wa Kimi no Uso 23273 TV [Drama, Romance] 8.65 8.646914 0.772093 9.991667
11072 No description has been provided for this image Kiznaiver 31798 TV [Drama, Romance, Sci-Fi] 7.38 7.374965 0.767345 8.550000
9655 No description has been provided for this image Macross Δ 28013 TV [Action, Romance, Sci-Fi] 7.27 7.213781 0.763750 8.025000
9604 No description has been provided for this image Plastic Memories 27775 TV [Drama, Romance, Sci-Fi] 7.91 7.904120 0.761493 9.458333
10540 No description has been provided for this image Soukyuu no Fafner: Dead Aggressor - Exodus Part 2 30549 TV [Action, Drama, Sci-Fi] 7.61 7.309665 0.724244 9.458333
7558 No description has been provided for this image Soukyuu no Fafner: Dead Aggressor - Exodus 17080 TV [Action, Drama, Sci-Fi] 7.37 7.177703 0.717476 9.458333
10460 No description has been provided for this image Classroom☆Crisis 30383 TV [Drama, Romance, Sci-Fi] 6.97 6.949188 0.702818 9.458333
8424 No description has been provided for this image Buddy Complex 21437 TV [Action, Sci-Fi] 7.12 7.088736 0.665246 10.404167
8823 No description has been provided for this image M3: Sono Kuroki Hagane 23133 TV [Action, Drama, Mystery, Sci-Fi] 6.57 6.553907 0.654233 9.900000
7299 No description has been provided for this image Senki Zesshou Symphogear G 15793 TV [Action, Sci-Fi] 7.46 7.396078 0.651114 11.350000
6358 No description has been provided for this image Guilty Crown 10793 TV [Action, Drama, Sci-Fi] 7.42 7.417078 0.623462 12.716667
6594 No description has been provided for this image Senki Zesshou Symphogear 11751 TV [Action, Sci-Fi] 7.03 7.004872 0.602644 12.295833
5559 No description has been provided for this image Star Driver: Kagayaki no Takuto 8934 TV [Action, Romance, Sci-Fi] 7.19 7.159537 0.580523 13.437500
3375 No description has been provided for this image Kidou Senshi Gundam 00 Second Season 3927 TV [Action, Drama, Sci-Fi] 8.08 8.048096 0.579084 15.229167
In [ ]:
df = AnimeRecommender.get_anime_recommendations2('Darling in the FranXX', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating final_score age_penalty
2013 No description has been provided for this image Muteki Choujin Zanbot 3 2200 TV [Action, Drama, Sci-Fi] 7.16 6.752812 9.855553 43.400000
4292 No description has been provided for this image Uchuu Kuubo Blue Noah 5763 TV [Action, Drama, Sci-Fi] 6.53 6.417003 9.404405 41.400000
59 No description has been provided for this image Kidou Senshi Gundam 80 TV [Action, Drama, Sci-Fi] 7.76 7.718750 8.803062 37.758333
988 No description has been provided for this image Macross 1088 TV [Action, Romance, Sci-Fi] 7.90 7.828247 8.575618 36.550000
3675 No description has been provided for this image Choujikuu Kidan Southern Cross 4503 TV [Action, Drama, Sci-Fi] 6.56 6.497439 8.550448 37.070833
4663 No description has been provided for this image Chou Kousoku Galvion 6636 TV [Action, Sci-Fi] 6.04 6.330598 8.534154 37.241667
2369 No description has been provided for this image Soukou Kihei Votoms 2582 TV [Action, Drama, Sci-Fi] 7.70 7.395743 7.793458 32.900000
64 No description has been provided for this image Kidou Senshi Zeta Gundam 85 TV [Drama, Romance, Sci-Fi] 7.90 7.828992 7.596149 31.666667
1325 No description has been provided for this image Uchuu no Kishi Tekkaman Blade 1459 TV [Action, Adventure, Drama, Romance, Sci-Fi] 7.45 7.190315 6.436900 26.262500
195 No description has been provided for this image Kidou Senkan Nadesico 218 TV [Action, Romance, Sci-Fi] 7.49 7.397964 6.396828 25.858333
69 No description has been provided for this image Shin Kidou Senki Gundam Wing 90 TV [Action, Drama, Sci-Fi] 7.69 7.664281 6.018393 23.875000
1789 No description has been provided for this image Chikyuu Bouei Kazoku 1962 TV [Action, Comedy, Drama, Sci-Fi] 6.85 6.518807 5.647813 22.700000
113 No description has been provided for this image Gunslinger Girl 134 TV [Action, Drama, Sci-Fi] 7.39 7.367269 5.372226 20.808333
16 No description has been provided for this image Texhnolyze 26 TV [Action, Drama, Sci-Fi] 7.76 7.717234 5.274484 19.983333
92 No description has been provided for this image Uchuu no Stellvia 113 TV [Action, Romance, Sci-Fi] 7.37 7.215704 5.122776 19.616667
453 No description has been provided for this image Kurau Phantom Memory 483 TV [Action, Drama, Sci-Fi] 7.29 7.126334 4.982339 18.900000
2911 No description has been provided for this image IGPX: Immortal Grand Prix (2005) 3270 TV [Action, Drama, Sci-Fi] 7.07 6.950303 4.976938 18.916667
55 No description has been provided for this image Soukyuu no Fafner: Dead Aggressor 75 TV [Action, Drama, Sci-Fi] 7.26 7.166644 4.945383 18.812500
72 No description has been provided for this image Kidou Senshi Gundam SEED 93 TV [Action, Award Winning, Drama, Romance, Sci-Fi] 7.75 7.724560 4.892516 18.208333
130 No description has been provided for this image Solty Rei 152 TV [Action, Sci-Fi] 7.27 7.159682 4.782494 18.000000
1279 No description has been provided for this image IGPX: Immortal Grand Prix (2005) 2nd Season 1410 TV [Action, Sci-Fi] 7.25 7.033195 4.758792 17.970833
775 No description has been provided for this image Gunparade Orchestra 858 TV [Drama, Romance, Sci-Fi] 5.84 6.161658 4.665074 18.000000
793 No description has been provided for this image Zegapain 878 TV [Action, Romance, Sci-Fi] 7.29 7.163313 4.580063 16.941667
73 No description has been provided for this image Kidou Senshi Gundam SEED Destiny 94 TV [Action, Drama, Romance, Sci-Fi] 7.18 7.158412 4.530976 16.625000
In [ ]:
df = AnimeRecommender.get_anime_recommendations('Naruto: Shippuuden', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating Release_year recency_score similarity_score final_score
16617 No description has been provided for this image Bleach: Sennen Kessen-hen 41467 TV [Action, Adventure, Fantasy] 9.07 9.048079 2022.0 0.972222 0.611729 1.696190
10 No description has been provided for this image Naruto 20 TV [Action, Adventure, Fantasy] 7.99 7.988501 2002.0 0.787037 0.783057 1.648506
6456 No description has been provided for this image Hunter x Hunter (2011) 11061 TV [Action, Adventure, Fantasy] 9.04 9.037173 2011.0 0.870370 0.555852 1.636514
3961 No description has been provided for this image Fullmetal Alchemist: Brotherhood 5114 TV [Action, Adventure, Drama, Fantasy] 9.10 9.097636 2009.0 0.851852 0.523833 1.618293
368 No description has been provided for this image Yuu☆Yuu☆Hakusho 392 TV [Action, Fantasy] 8.46 8.448490 1992.0 0.694444 0.601456 1.561698
245 No description has been provided for this image Bleach 269 TV [Action, Adventure, Fantasy] 7.92 7.917476 2004.0 0.805556 0.654016 1.555939
11 No description has been provided for this image One Piece 21 TV [Action, Adventure, Fantasy] 8.69 8.686696 1999.0 0.759259 0.519085 1.547233
12428 No description has been provided for this image Black Clover 34572 TV [Action, Comedy, Fantasy] 8.14 8.136070 2017.0 0.925926 0.560497 1.542652
115 No description has been provided for this image Hunter x Hunter 136 TV [Action, Adventure, Fantasy] 8.41 8.397139 1999.0 0.759259 0.554684 1.536694
9225 No description has been provided for this image Akatsuki no Yona 25013 TV [Action, Adventure, Fantasy, Romance] 8.03 8.022766 2014.0 0.898148 0.567099 1.527989
7799 No description has been provided for this image Magi: The Kingdom of Magic 18115 TV [Action, Adventure, Fantasy] 8.22 8.212752 2013.0 0.888889 0.531031 1.524409
1344 No description has been provided for this image D.Gray-man 1482 TV [Action, Adventure, Fantasy] 8.02 8.009810 2006.0 0.824074 0.557886 1.505355
131 No description has been provided for this image Juuni Kokuki 153 TV [Action, Adventure, Fantasy] 8.02 7.957254 2002.0 0.787037 0.554957 1.489649
16329 No description has been provided for this image Dragon Quest: Dai no Daibouken (2020) 40906 TV [Action, Adventure, Fantasy] 7.74 7.643075 2020.0 0.953704 0.557394 1.486937
8558 No description has been provided for this image Fairy Tail (2014) 22043 TV [Action, Adventure, Fantasy] 7.65 7.645865 2014.0 0.898148 0.571065 1.485457
7001 No description has been provided for this image Naruto: Shippuuden Movie 6 - Road to Ninja 13667 Movie [Action, Adventure, Fantasy] 7.68 7.668692 2012.0 0.879630 0.569754 1.483602
11043 No description has been provided for this image Magi: Sinbad no Bouken (TV) 31741 TV [Action, Adventure, Fantasy] 7.85 7.839802 2016.0 0.916667 0.515753 1.474822
13260 No description has been provided for this image Fairy Tail: Final Series 35972 TV [Action, Adventure, Fantasy] 7.57 7.561180 2018.0 0.935185 0.557004 1.473141
734 No description has been provided for this image Dragon Ball Z 813 TV [Action, Adventure, Comedy, Fantasy] 8.16 8.156166 1989.0 0.666667 0.523575 1.468104
8619 No description has been provided for this image Tokyo Ghoul 22319 TV [Action, Fantasy, Horror] 7.79 7.788620 2014.0 0.898148 0.515360 1.464708
11291 No description has been provided for this image D.Gray-man Hallow 32370 TV [Action, Adventure, Fantasy] 7.70 7.671143 2016.0 0.916667 0.520391 1.457736
4694 No description has been provided for this image Fairy Tail 6702 TV [Action, Adventure, Fantasy] 7.57 7.567877 2009.0 0.851852 0.556568 1.456982
8747 No description has been provided for this image Dragon Ball Kai (2014) 22777 TV [Action, Adventure, Comedy, Fantasy] 7.68 7.658538 2014.0 0.898148 0.526743 1.456840
4416 No description has been provided for this image Dragon Ball Kai 6033 TV [Action, Adventure, Comedy, Fantasy] 7.73 7.719814 2009.0 0.851852 0.528874 1.456383
In [ ]:
df = AnimeRecommender.get_anime_recommendations1('High School DxD', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating final_score age_penalty
15566 No description has been provided for this image Yahari Ore no Seishun Love Comedy wa Machigatteiru. Kan 39547 TV [Comedy, Romance] 8.36 8.350713 1.047413 4.750000
14836 No description has been provided for this image Ore wo Suki nano wa Omae dake ka yo 38483 TV [Comedy, Romance] 7.32 7.312971 0.903399 5.700000
16209 No description has been provided for this image Monster Musume no Oishasan 40708 TV [Comedy, Fantasy, Romance, Ecchi] 6.53 6.527310 0.897358 4.750000
12273 No description has been provided for this image High School DxD Hero 34281 TV [Action, Comedy, Romance, Ecchi] 7.25 7.244283 0.896247 6.650000
15419 No description has been provided for this image Kawaikereba Hentai demo Suki ni Natte Kuremasu ka? 39326 TV [Comedy, Romance, Ecchi] 6.50 6.498662 0.858891 5.700000
10586 No description has been provided for this image Saenai Heroine no Sodatekata ♭ 30727 TV [Comedy, Romance, Ecchi] 7.76 7.746675 0.846892 7.633333
9152 No description has been provided for this image High School DxD BorN 24703 TV [Action, Comedy, Romance, Ecchi] 7.42 7.416314 0.816511 9.500000
12969 No description has been provided for this image Imouto sae Ireba Ii. 35413 TV [Comedy, Romance, Ecchi] 7.28 7.269535 0.816102 7.600000
12272 No description has been provided for this image Gamers! 34280 TV [Comedy, Romance] 6.76 6.758171 0.769588 7.600000
8856 No description has been provided for this image Saenai Heroine no Sodatekata 23277 TV [Comedy, Romance, Ecchi] 7.48 7.473676 0.750873 9.500000
10393 No description has been provided for this image Prison School 30240 TV [Comedy, Romance, Ecchi] 7.61 7.606261 0.748234 9.500000
7245 No description has been provided for this image High School DxD New 15451 TV [Action, Comedy, Romance, Ecchi] 7.48 7.476668 0.743072 11.400000
11554 No description has been provided for this image Eromanga-sensei 32901 TV [Comedy, Drama, Romance, Ecchi] 6.36 6.360103 0.740590 7.600000
10886 No description has been provided for this image Netoge no Yome wa Onnanoko ja Nai to Omotta? 31404 TV [Comedy, Romance, Ecchi] 6.71 6.707898 0.736670 8.550000
12335 No description has been provided for this image Hajimete no Gal 34403 TV [Comedy, Romance, Ecchi] 6.29 6.290573 0.730968 7.666667
11376 No description has been provided for this image Okusama ga Seitokaichou!+! 32603 TV [Comedy, Romance, Ecchi] 6.59 6.585942 0.713720 8.550000
9255 No description has been provided for this image Ore ga Ojousama Gakkou ni "Shomin Sample" Toshite Gets♥Sareta Ken 25099 TV [Comedy, Romance, Ecchi] 6.69 6.685905 0.702583 9.500000
13675 No description has been provided for this image Ore ga Suki nano wa Imouto dakedo Imouto ja Nai 36632 TV [Comedy, Romance, Ecchi] 4.87 4.918538 0.692166 6.708333
7178 No description has been provided for this image Boku wa Tomodachi ga Sukunai Next 14967 TV [Comedy, Romance, Ecchi] 7.29 7.284973 0.680695 11.400000
9845 No description has been provided for this image Okusama ga Seitokaichou! 28819 TV [Comedy, Romance, Ecchi] 6.58 6.577678 0.678750 9.500000
8766 No description has been provided for this image Seireitsukai no Blade Dance 22877 TV [Action, Comedy, Fantasy, Romance, Ecchi] 6.69 6.687074 0.677346 10.450000
7795 No description has been provided for this image Nourin 18095 TV [Comedy, Romance, Ecchi] 6.75 6.741877 0.669791 10.450000
7149 No description has been provided for this image Chuunibyou demo Koi ga Shitai! 14741 TV [Comedy, Romance] 7.71 7.706904 0.655911 12.350000
7281 No description has been provided for this image Nekomonogatari: Kuro 15689 TV [Comedy, Romance, Supernatural, Ecchi] 7.93 7.921766 0.648867 12.783333
In [ ]:
df = AnimeRecommender.get_recommendations_by_genres(['Action', 'Fantasy']	, n=50)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name Genres age_penalty weighted_rating
3961 No description has been provided for this image Fullmetal Alchemist: Brotherhood [Action, Adventure, Drama, Fantasy] 11.733333 9.097636
16617 No description has been provided for this image Bleach: Sennen Kessen-hen [Action, Adventure, Fantasy] 2.837500 9.048079
14865 No description has been provided for this image Shingeki no Kyojin Season 3 Part 2 [Action, Drama] 5.750000 9.046816
9880 No description has been provided for this image Gintama° [Action, Comedy, Sci-Fi] 7.875000 9.040355
6456 No description has been provided for this image Hunter x Hunter (2011) [Action, Adventure, Fantasy] 7.000000 9.037173
22348 No description has been provided for this image Shingeki no Kyojin: The Final Season - Kanketsu-hen [Action, Drama, Suspense] 0.000000 9.020218
5989 No description has been provided for this image Gintama' [Action, Comedy, Sci-Fi] 11.025000 9.019494
7240 No description has been provided for this image Gintama': Enchousen [Action, Comedy, Sci-Fi] 12.295833 9.000788
15525 No description has been provided for this image Gintama: The Final [Action, Comedy, Drama, Sci-Fi] 3.983333 8.968517
12179 No description has been provided for this image Gintama. [Action, Comedy, Sci-Fi] 7.600000 8.947376
833 No description has been provided for this image Gintama [Action, Comedy, Sci-Fi] 9.500000 8.928261
2647 No description has been provided for this image Code Geass: Hangyaku no Lelouch R2 [Action, Award Winning, Drama, Sci-Fi] 15.229167 8.906124
14527 No description has been provided for this image Violet Evergarden Movie [Award Winning, Drama, Fantasy] 4.979167 8.881617
7228 No description has been provided for this image Gintama Movie 2: Kanketsu-hen - Yorozuya yo Eien Nare [Action, Comedy, Sci-Fi] 11.950000 8.876192
14206 No description has been provided for this image Gintama.: Shirogane no Tamashii-hen - Kouhan-sen [Action, Comedy, Sci-Fi] 6.591667 8.831842
15822 No description has been provided for this image Shingeki no Kyojin: The Final Season [Action, Drama] 4.666667 8.796520
14219 No description has been provided for this image Mob Psycho 100 II [Action, Comedy, Supernatural] 5.675000 8.795299
20430 No description has been provided for this image Kimetsu no Yaiba: Yuukaku-hen [Action, Fantasy] 3.816667 8.794506
11052 No description has been provided for this image Kizumonogatari III: Reiketsu-hen [Action, Mystery, Supernatural] 7.966667 8.773543
21303 No description has been provided for this image Vinland Saga Season 2 [Action, Adventure, Drama] 1.800000 8.771356
13818 No description has been provided for this image Gintama.: Shirogane no Tamashii-hen [Action, Comedy, Sci-Fi] 6.650000 8.767080
20972 No description has been provided for this image Shingeki no Kyojin: The Final Season Part 2 [Action, Drama] 2.850000 8.763341
0 No description has been provided for this image Cowboy Bebop [Action, Award Winning, Sci-Fi] 24.075000 8.745454
14226 No description has been provided for this image Vinland Saga [Action, Adventure, Drama] 5.400000 8.734590
21680 No description has been provided for this image Mob Psycho 100 III [Action, Comedy, Supernatural] 2.850000 8.703707
1431 No description has been provided for this image Code Geass: Hangyaku no Lelouch [Action, Award Winning, Drama, Sci-Fi] 17.020833 8.696970
20964 No description has been provided for this image 86 Part 2 [Action, Drama, Sci-Fi] 3.800000 8.692836
18920 No description has been provided for this image Mushoku Tensei: Isekai Ittara Honki Dasu Part 2 [Drama, Fantasy, Ecchi] 3.800000 8.691501
16191 No description has been provided for this image Kingdom 3rd Season [Action] 4.458333 8.691051
11 No description has been provided for this image One Piece [Action, Adventure, Fantasy] 0.000000 8.686696
25 No description has been provided for this image Rurouni Kenshin: Meiji Kenkaku Romantan - Tsuioku-hen [Action, Drama, Romance] 25.566667 8.679878
11800 No description has been provided for this image Violet Evergarden [Drama, Fantasy] 6.620833 8.665611
142 No description has been provided for this image Mononoke Hime [Action, Adventure, Award Winning, Fantasy] 27.883333 8.664782
11630 No description has been provided for this image Fate/stay night Movie: Heaven's Feel - III. Spring Song [Action, Fantasy, Supernatural] 4.979167 8.656426
404 No description has been provided for this image Howl no Ugoku Shiro [Adventure, Award Winning, Drama, Fantasy, Romance] 20.912500 8.655388
12435 No description has been provided for this image Made in Abyss [Adventure, Drama, Fantasy, Mystery, Sci-Fi] 7.566667 8.654291
16236 No description has been provided for this image Jujutsu Kaisen [Action, Award Winning, Fantasy] 4.500000 8.637287
16412 No description has been provided for this image Made in Abyss: Retsujitsu no Ougonkyou [Adventure, Drama, Fantasy, Mystery, Sci-Fi] 2.850000 8.635083
1822 No description has been provided for this image Tengen Toppa Gurren Lagann [Action, Adventure, Award Winning, Sci-Fi] 15.975000 8.625455
13176 No description has been provided for this image Shingeki no Kyojin Season 3 [Action, Drama] 6.650000 8.617390
16060 No description has been provided for this image Kimetsu no Yaiba Movie: Mugen Ressha-hen [Action, Fantasy] 4.979167 8.615747
21734 No description has been provided for this image Spy x Family [Action, Award Winning, Comedy] 2.850000 8.615184
13832 No description has been provided for this image Made in Abyss Movie 3: Fukaki Tamashii no Reimei [Adventure, Drama, Fantasy, Mystery, Sci-Fi] 4.979167 8.612744
16931 No description has been provided for this image Cyberpunk: Edgerunners [Action, Sci-Fi] 2.875000 8.600006
23341 No description has been provided for this image JoJo no Kimyou na Bouken Part 6: Stone Ocean Part 3 [Action, Adventure, Supernatural] 2.825000 8.590229
18172 No description has been provided for this image Chainsaw Man [Action, Fantasy] 2.850000 8.584003
3271 No description has been provided for this image Evangelion: 3.0+1.0 Thrice Upon a Time [Action, Award Winning, Drama, Sci-Fi, Suspense] 3.983333 8.582592
14531 No description has been provided for this image JoJo no Kimyou na Bouken Part 5: Ougon no Kaze [Action, Adventure, Supernatural] 5.862500 8.573965
6714 No description has been provided for this image Ookami Kodomo no Ame to Yuki [Award Winning, Fantasy, Slice of Life] 12.945833 8.571330
21676 No description has been provided for this image Kingdom 4th Season [Action] 2.675000 8.566972
  • Install spaCy

This downloads the small English language model (en_core_web_sm) which includes:

  • Vocabulary
  • Syntax
  • Named entities
In [ ]:
!pip install spacy
!python -m spacy download en_core_web_sm
Requirement already satisfied: spacy in /usr/local/lib/python3.11/dist-packages (3.8.7)
Requirement already satisfied: spacy-legacy<3.1.0,>=3.0.11 in /usr/local/lib/python3.11/dist-packages (from spacy) (3.0.12)
Requirement already satisfied: spacy-loggers<2.0.0,>=1.0.0 in /usr/local/lib/python3.11/dist-packages (from spacy) (1.0.5)
Requirement already satisfied: murmurhash<1.1.0,>=0.28.0 in /usr/local/lib/python3.11/dist-packages (from spacy) (1.0.13)
Requirement already satisfied: cymem<2.1.0,>=2.0.2 in /usr/local/lib/python3.11/dist-packages (from spacy) (2.0.11)
Requirement already satisfied: preshed<3.1.0,>=3.0.2 in /usr/local/lib/python3.11/dist-packages (from spacy) (3.0.10)
Requirement already satisfied: thinc<8.4.0,>=8.3.4 in /usr/local/lib/python3.11/dist-packages (from spacy) (8.3.6)
Requirement already satisfied: wasabi<1.2.0,>=0.9.1 in /usr/local/lib/python3.11/dist-packages (from spacy) (1.1.3)
Requirement already satisfied: srsly<3.0.0,>=2.4.3 in /usr/local/lib/python3.11/dist-packages (from spacy) (2.5.1)
Requirement already satisfied: catalogue<2.1.0,>=2.0.6 in /usr/local/lib/python3.11/dist-packages (from spacy) (2.0.10)
Requirement already satisfied: weasel<0.5.0,>=0.1.0 in /usr/local/lib/python3.11/dist-packages (from spacy) (0.4.1)
Requirement already satisfied: typer<1.0.0,>=0.3.0 in /usr/local/lib/python3.11/dist-packages (from spacy) (0.16.0)
Requirement already satisfied: tqdm<5.0.0,>=4.38.0 in /usr/local/lib/python3.11/dist-packages (from spacy) (4.67.1)
Requirement already satisfied: numpy>=1.19.0 in /usr/local/lib/python3.11/dist-packages (from spacy) (2.0.2)
Requirement already satisfied: requests<3.0.0,>=2.13.0 in /usr/local/lib/python3.11/dist-packages (from spacy) (2.32.3)
Requirement already satisfied: pydantic!=1.8,!=1.8.1,<3.0.0,>=1.7.4 in /usr/local/lib/python3.11/dist-packages (from spacy) (2.11.7)
Requirement already satisfied: jinja2 in /usr/local/lib/python3.11/dist-packages (from spacy) (3.1.6)
Requirement already satisfied: setuptools in /usr/local/lib/python3.11/dist-packages (from spacy) (75.2.0)
Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.11/dist-packages (from spacy) (25.0)
Requirement already satisfied: langcodes<4.0.0,>=3.2.0 in /usr/local/lib/python3.11/dist-packages (from spacy) (3.5.0)
Requirement already satisfied: language-data>=1.2 in /usr/local/lib/python3.11/dist-packages (from langcodes<4.0.0,>=3.2.0->spacy) (1.3.0)
Requirement already satisfied: annotated-types>=0.6.0 in /usr/local/lib/python3.11/dist-packages (from pydantic!=1.8,!=1.8.1,<3.0.0,>=1.7.4->spacy) (0.7.0)
Requirement already satisfied: pydantic-core==2.33.2 in /usr/local/lib/python3.11/dist-packages (from pydantic!=1.8,!=1.8.1,<3.0.0,>=1.7.4->spacy) (2.33.2)
Requirement already satisfied: typing-extensions>=4.12.2 in /usr/local/lib/python3.11/dist-packages (from pydantic!=1.8,!=1.8.1,<3.0.0,>=1.7.4->spacy) (4.14.1)
Requirement already satisfied: typing-inspection>=0.4.0 in /usr/local/lib/python3.11/dist-packages (from pydantic!=1.8,!=1.8.1,<3.0.0,>=1.7.4->spacy) (0.4.1)
Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/dist-packages (from requests<3.0.0,>=2.13.0->spacy) (3.4.2)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/dist-packages (from requests<3.0.0,>=2.13.0->spacy) (3.10)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/dist-packages (from requests<3.0.0,>=2.13.0->spacy) (2.4.0)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.11/dist-packages (from requests<3.0.0,>=2.13.0->spacy) (2025.7.9)
Requirement already satisfied: blis<1.4.0,>=1.3.0 in /usr/local/lib/python3.11/dist-packages (from thinc<8.4.0,>=8.3.4->spacy) (1.3.0)
Requirement already satisfied: confection<1.0.0,>=0.0.1 in /usr/local/lib/python3.11/dist-packages (from thinc<8.4.0,>=8.3.4->spacy) (0.1.5)
Requirement already satisfied: click>=8.0.0 in /usr/local/lib/python3.11/dist-packages (from typer<1.0.0,>=0.3.0->spacy) (8.2.1)
Requirement already satisfied: shellingham>=1.3.0 in /usr/local/lib/python3.11/dist-packages (from typer<1.0.0,>=0.3.0->spacy) (1.5.4)
Requirement already satisfied: rich>=10.11.0 in /usr/local/lib/python3.11/dist-packages (from typer<1.0.0,>=0.3.0->spacy) (14.0.0)
Requirement already satisfied: cloudpathlib<1.0.0,>=0.7.0 in /usr/local/lib/python3.11/dist-packages (from weasel<0.5.0,>=0.1.0->spacy) (0.21.1)
Requirement already satisfied: smart-open<8.0.0,>=5.2.1 in /usr/local/lib/python3.11/dist-packages (from weasel<0.5.0,>=0.1.0->spacy) (7.3.0.post1)
Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.11/dist-packages (from jinja2->spacy) (3.0.2)
Requirement already satisfied: marisa-trie>=1.1.0 in /usr/local/lib/python3.11/dist-packages (from language-data>=1.2->langcodes<4.0.0,>=3.2.0->spacy) (1.2.1)
Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.11/dist-packages (from rich>=10.11.0->typer<1.0.0,>=0.3.0->spacy) (3.0.0)
Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.11/dist-packages (from rich>=10.11.0->typer<1.0.0,>=0.3.0->spacy) (2.19.2)
Requirement already satisfied: wrapt in /usr/local/lib/python3.11/dist-packages (from smart-open<8.0.0,>=5.2.1->weasel<0.5.0,>=0.1.0->spacy) (1.17.2)
Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.11/dist-packages (from markdown-it-py>=2.2.0->rich>=10.11.0->typer<1.0.0,>=0.3.0->spacy) (0.1.2)
Collecting en-core-web-sm==3.8.0
  Downloading https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl (12.8 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 12.8/12.8 MB 48.4 MB/s eta 0:00:00
✔ Download and installation successful
You can now load the package via spacy.load('en_core_web_sm')
⚠ Restart to reload dependencies
If you are in a Jupyter or Colab notebook, you may need to restart Python in
order to load all the package's dependencies. You can do this by selecting the
'Restart kernel' or 'Restart runtime' option.

The following AnimeRecommender class solves key limitations in the previous version by replacing the outdated NLTK pipeline with a cleaner and more efficient spaCy NLP model, improving genre and studio normalization, and introducing consistent recency scoring and age penalty handling. It also adds personalized user-based recommendations and a simpler genre-based filtering method. These changes lead to smarter, fresher, and more relevant recommendations that better reflect user preferences and anime trends.


AnimeRecommender Class — Hybrid NLP & Metadata-Based Anime Recommendation Engine¶

Overview:¶

The AnimeRecommender class implements a hybrid recommendation engine that blends NLP-enhanced content filtering, metadata-driven similarity, and user-based collaborative signals. It dynamically adjusts recommendation priorities using recency scoring and age-based penalties, ensuring results are relevant, personalized, and trend-aware.

Class Methodology & Core Components:¶

__init__()¶

  • Loads anime_df and ratings_df datasets.
  • Initializes spaCy NLP pipeline and vector encoders.
  • Applies preprocessing and feature engineering.
  • Sets default feature weights:
weights = {
    'genres': 0.30,
    'synopsis': 0.35,
    'type': 0.15,
    'studios': 0.10,
    'episodes': 0.05,
    'source': 0.05
}

_preprocess_data()¶

  • Cleans numerical and string fields.
  • Extracts Release_year from Aired.
  • Converts genres and studios to normalized lists.
  • Calculates IMDb-style weighted rating:

$$ \text{weighted\_rating} = \left( \frac{v}{v + m} \right) R + \left( \frac{m}{v + m} \right) C $$

Where:

  • $R$: anime's mean score
  • $v$: number of votes (Scored By)
  • $m$: 65th percentile of all vote counts
  • $C$: global mean score

_create_feature_matrices()¶

Creates efficient encodings for similarity computation:

Feature Encoding Method
Genres MultiLabelBinarizer (sparse)
Studios MultiLabelBinarizer
Type OneHotEncoder
Source OneHotEncoder
Episodes Binned + OneHotEncoder
Synopsis spaCy → Lemmatized → TF-IDF

📊 Similarity Calculation¶

_calculate_anime_similarity(idx)¶

Generates weighted similarity score:

$$ \text{similarity} = \sum w_i \cdot \text{sim}_i $$

Where $w_i$ are feature weights and $\text{sim}_i$ is cosine or binary match similarity for:

  • Genres
  • Synopsis
  • Type
  • Studios
  • Episodes
  • Source

Recency Scoring¶

_calculate_recency_boost(release_year)¶

Applies min-max normalization on release year:

$$ \text{recency_score} = \frac{\text{year} - \text{min\_year}}{\text{max_year} - \text{min_year}} $$


Final Scoring Formulas¶

1. Without Age Penalty (in get_anime_recommendations()):¶

$$\text{final_score} = \left[ (1 - w_s) \cdot \text{weighted_rating} + w_s \cdot \text{similarity} \right] \cdot (1 - w_r) + w_r \cdot \text{recency_score} $$

2. With Age Penalty (in get_anime_recommendations1() and 2()):¶

$$ \text{final_score} = \frac{ \left[ (1 - w_s) \cdot \text{weighted_rating} + w_s \cdot \text{similarity} \right] \cdot (1 - w_r) + w_r \cdot \text{recency_score} }{1 + \frac{\text{age_penalty}}{10}} $$


Recommendation Strategies¶

Method Description
get_anime_recommendations Based on title; includes similarity, rating, and recency boost.
get_anime_recommendations1/2 Adds age_penalty to suppress outdated content unless still airing.
get_user_recommendations Based on user’s top-rated anime; scores by similarity × rating × recency.
get_recommendations_by_genres Genre-based matching using binary or semantic overlap.
simple() Lightweight genre intersection without encoders.

Design Highlights¶

Feature Included
Weighted metadata-based similarity (multi-feature) ✅
NLP-powered synopsis matching via spaCy + TF-IDF ✅
Recency boosting to promote newer anime ✅
Age penalty to deprioritize outdated shows ✅
IMDb-like popularity-adjusted scoring ✅
Modular functions for extensibility ✅
In [ ]:
class AnimeRecommender:
    def __init__(self, anime_df, ratings_df):
        self.nlp = spacy.load("en_core_web_sm")
        self.anime_df = anime_df.copy()
        self.ratings_df = ratings_df.copy()
        self.nlp = spacy.load("en_core_web_sm")
        self.current_year = datetime.now().year

        self._preprocess_data()
        self._create_feature_matrices()

        self.weights = {
            'genres': 0.30,
            'synopsis': 0.35,
            'type': 0.15,
            'studios': 0.10,
            'episodes': 0.05,
            'source': 0.05
        }

    def _preprocess_data(self):
        self.anime_df['Score'] = self.anime_df['Score'].replace('[^0-9.]', '', regex=True)
        self.anime_df['Scored By'] = self.anime_df['Scored By'].replace('[^0-9]', '', regex=True)
        self.anime_df['Score'] = pd.to_numeric(self.anime_df['Score'], errors='coerce')
        self.anime_df['Scored By'] = pd.to_numeric(self.anime_df['Scored By'], errors='coerce')
        self.anime_df['Score'].fillna(self.anime_df['Score'].median(), inplace=True)
        self.anime_df['Scored By'].fillna(self.anime_df['Scored By'].median(), inplace=True)
        self.anime_df['Release_year'] = self.anime_df['Aired'].str.extract(r'(\d{4})').astype(float)

        def normalize_genre_list(genre_string):
            if genre_string == 'UNKNOWN' or pd.isna(genre_string):
                return []
            genres = re.split(r',\s*', genre_string)
            cleaned = [re.sub(r'[^\w\s]', '', g).strip().lower() for g in genres]
            return list(set(cleaned))

        self.anime_df['Genres'] = self.anime_df['Genres'].apply(normalize_genre_list)
        self.anime_df['Studios'] = self.anime_df['Studios'].apply(normalize_genre_list)

        C = self.anime_df['Score'].mean()
        m = self.anime_df['Scored By'].quantile(0.65)
        self.anime_df['weighted_rating'] = (
            (self.anime_df['Scored By'] / (self.anime_df['Scored By'] + m)) * self.anime_df['Score'] +
            (m / (self.anime_df['Scored By'] + m)) * C
        )

    def _create_feature_matrices(self):
        self.mlb_genres = MultiLabelBinarizer(sparse_output=True)
        self.genres_encoded = self.mlb_genres.fit_transform(self.anime_df['Genres'])

        self.mlb_studios = MultiLabelBinarizer(sparse_output=True)
        self.studios_encoded = self.mlb_studios.fit_transform(self.anime_df['Studios'])

        self.ohe_type = OneHotEncoder(sparse_output=True)
        self.type_encoded = self.ohe_type.fit_transform(self.anime_df[['Type']])

        self.ohe_source = OneHotEncoder(sparse_output=True)
        self.source_encoded = self.ohe_source.fit_transform(self.anime_df[['Source']])

        self.anime_df['Episodes'] = pd.to_numeric(self.anime_df['Episodes'], errors='coerce')
        self.median_episodes = self.anime_df['Episodes'].median()
        self.anime_df['Episodes'].fillna(self.median_episodes, inplace=True)

        self.bins = [0, 1, 12, 24, 50, np.inf]
        self.labels = ['1', '2-12', '13-24', '25-50', '51+']
        self.anime_df['Episodes_Binned'] = pd.cut(self.anime_df['Episodes'], bins=self.bins, labels=self.labels)
        self.ohe_episodes = OneHotEncoder(sparse_output=True)
        self.episodes_encoded = self.ohe_episodes.fit_transform(self.anime_df[['Episodes_Binned']])

        self.anime_df['Synopsis'] = self._clean_text(self.anime_df['Synopsis'].fillna(''))
        self.tfidf = TfidfVectorizer(stop_words='english')
        self.synopsis_encoded = self.tfidf.fit_transform(self.anime_df['Synopsis'])

    def _clean_text(self, text_series: pd.Series) -> pd.Series:
        return text_series.apply(self._spacy_clean)

    def _spacy_clean(self, text: str) -> str:
        doc = self.nlp(text.lower())
        return ' '.join(
            token.lemma_ for token in doc
            if not token.is_stop and not token.is_punct and token.is_alpha
        )

    def _calculate_recency_boost(self, release_year):
        year = release_year if pd.notna(release_year) else self.anime_df['Release_year'].min()
        min_year = self.anime_df['Release_year'].min()
        max_year = self.anime_df['Release_year'].max()
        year_range = max_year - min_year if max_year != min_year else 1
        scaled_year = (year - min_year) / year_range
        return scaled_year

    def _calculate_anime_similarity(self, idx: int):
        genres_sim = cosine_similarity(self.genres_encoded[idx:idx+1], self.genres_encoded)[0]
        studios_sim = cosine_similarity(self.studios_encoded[idx:idx+1], self.studios_encoded)[0]
        synopsis_sim = cosine_similarity(self.synopsis_encoded[idx:idx+1], self.synopsis_encoded)[0]
        type_sim = (self.anime_df['Type'] == self.anime_df.iloc[idx]['Type']).astype(float).values
        source_sim = (self.anime_df['Source'] == self.anime_df.iloc[idx]['Source']).astype(float).values
        episodes_sim = (self.anime_df['Episodes_Binned'] == self.anime_df.iloc[idx]['Episodes_Binned']).astype(float).values

        combined_sim = (
            self.weights['genres'] * genres_sim +
            self.weights['synopsis'] * synopsis_sim +
            self.weights['type'] * type_sim +
            self.weights['studios'] * studios_sim +
            self.weights['episodes'] * episodes_sim +
            self.weights['source'] * source_sim
        )

        sim_scores = np.array(list(enumerate(combined_sim)))
        num_recs_to_get = min(52, len(self.anime_df) - 1)
        sorted_sim_scores = sim_scores[sim_scores[:, 1].argsort()[::-1]]
        top_sim = sorted_sim_scores[1:num_recs_to_get + 1]

        top_indices = top_sim[:, 0].astype(int)
        sim_scores_top = top_sim[:, 1]
        return sim_scores_top, top_indices

    def get_user_recommendations(self, user_id, n=10, top_k=20):
        user_ratings = self.ratings_df[self.ratings_df['user_id'] == user_id]
        if user_ratings.empty:
            return pd.DataFrame()

        top_rated = (
            user_ratings
            .merge(self.anime_df, on='anime_id')
            .nlargest(top_k, 'rating')
            [['anime_id', 'rating', 'Release_year']]
        )

        candidate_scores = defaultdict(float)
        anime_id_to_index = pd.Series(self.anime_df.index, index=self.anime_df['anime_id']).to_dict()

        for _, row in top_rated.iterrows():
            anime_id = row['anime_id']
            if anime_id in anime_id_to_index:
                anime_idx = anime_id_to_index[anime_id]
                sim_scores_top, top_indices = self._calculate_anime_similarity(anime_idx)
                recency = self._calculate_recency_boost(row['Release_year'])
                weighted_scores = sim_scores_top * row['rating'] * recency

                for i, rec_idx in enumerate(top_indices):
                    if rec_idx < len(self.anime_df):
                        candidate_scores[rec_idx] += weighted_scores[i]

        watched_ids = set(user_ratings['anime_id'])
        recommended_anime_indices = sorted(candidate_scores.keys(), key=lambda k: candidate_scores[k], reverse=True)
        recommended_anime_indices = [idx for idx in recommended_anime_indices if self.anime_df.iloc[idx]['anime_id'] not in watched_ids]
        top_n_indices = recommended_anime_indices[:n]

        recommendations = (
            self.anime_df
            .iloc[top_n_indices]
            .assign(predicted_score=lambda x: x.index.map(candidate_scores))
            [['Name', 'Image URL', 'anime_id', 'Type', 'Genres', 'Score', 'predicted_score']]
        )

        return recommendations

    def get_anime_recommendations(self, title, n=10, similarity_weight=0.85, recency_weight=0.2):
        matching_animes = self.anime_df[self.anime_df['Name'] == title]
        if matching_animes.empty:
            raise ValueError(f"Anime '{title}' not found in the database.")
        idx = matching_animes.index[0]

        sim_scores_top, top_indices = self._calculate_anime_similarity(idx)

        recommended_animes = self.anime_df.iloc[top_indices][
            ['Image URL', 'Name', 'anime_id', 'Type', 'Genres', 'Score', 'weighted_rating', 'Release_year']
        ].copy()

        recommended_animes['recency_score'] = recommended_animes['Release_year'].apply(self._calculate_recency_boost)
        recommended_animes['similarity_score'] = sim_scores_top

        rating_weight = max(0, 1 - similarity_weight)
        similarity_weight = max(0, similarity_weight)
        recency_weight = max(0, recency_weight)

        recommended_animes['final_score'] = (
            (rating_weight * recommended_animes['weighted_rating'] +
             similarity_weight * recommended_animes['similarity_score']) * (1 - recency_weight) +
            recency_weight * recommended_animes['recency_score']
        )

        return recommended_animes.sort_values('final_score', ascending=False).head(n)

    def get_anime_recommendations1(self, title, n=10, similarity_weight=0.85, recency_weight=0.2):
        matching_animes = self.anime_df[self.anime_df['Name'] == title]
        if matching_animes.empty:
            raise ValueError(f"Anime '{title}' not found in the database.")
        idx = matching_animes.index[0]

        sim_scores_top, top_indices = self._calculate_anime_similarity(idx)

        recommended_animes = self.anime_df.iloc[top_indices][
            ['Image URL', 'Name', 'anime_id', 'Type', 'Genres', 'Score', 'weighted_rating', 'Release_year', 'Episodes', 'Status']
        ].copy()

        recommended_animes['similarity_score'] = sim_scores_top
        recommended_animes['recency_score'] = recommended_animes['Release_year'].apply(self._calculate_recency_boost)
        recommended_animes['end_year'] = recommended_animes['Release_year'].fillna(self.current_year)
        recommended_animes['episodes'] = pd.to_numeric(recommended_animes['Episodes'], errors='coerce').fillna(self.median_episodes)

        recommended_animes['age_penalty'] = recommended_animes.apply(
            lambda row: 0 if row['Status'] == 'Currently Airing' else
            (self.current_year - row['end_year']) * (1 - 0.5 * min(row['episodes'] / 120, 1)),
            axis=1
        )

        rating_weight = max(0, 1 - similarity_weight)
        similarity_weight = max(0, similarity_weight)
        recency_weight = max(0, recency_weight)

        recommended_animes['final_score'] = (
            (rating_weight * recommended_animes['weighted_rating'] +
             similarity_weight * recommended_animes['similarity_score']) * (1 - recency_weight) +
            recency_weight * recommended_animes['recency_score']
        ) / (1 + recommended_animes['age_penalty'] / 10)

        return recommended_animes.sort_values('final_score', ascending=False).head(n)[
            ['Image URL', 'Name', 'anime_id', 'Type', 'Genres', 'Score', 'weighted_rating', 'final_score', 'age_penalty']
        ]

    def get_anime_recommendations2(self, title, n=10, similarity_weight=0.85, recency_weight=0.2):
        matching_animes = self.anime_df[self.anime_df['Name'] == title]
        if matching_animes.empty:
            raise ValueError(f"Anime '{title}' not found in the database.")
        idx = matching_animes.index[0]

        sim_scores_top, top_indices = self._calculate_anime_similarity(idx)

        recommended_animes = self.anime_df.iloc[top_indices][
            ['Image URL', 'Name', 'anime_id', 'Type', 'Genres', 'Score', 'weighted_rating', 'Release_year', 'Episodes', 'Status']
        ].copy()

        recommended_animes['similarity_score'] = sim_scores_top
        recommended_animes['recency_score'] = recommended_animes['Release_year'].apply(self._calculate_recency_boost)
        recommended_animes['end_year'] = recommended_animes['Release_year'].fillna(self.current_year)
        recommended_animes['episodes'] = pd.to_numeric(recommended_animes['Episodes'], errors='coerce').fillna(self.median_episodes)

        recommended_animes['age_penalty'] = recommended_animes.apply(
            lambda row: 0 if row['Status'] == 'Currently Airing' else
            (self.current_year - row['end_year']) * (1 - 0.5 * min(row['episodes'] / 120, 1)),
            axis=1
        )

        rating_weight = max(0, 1 - similarity_weight)
        similarity_weight = max(0, similarity_weight)
        recency_weight = max(0, recency_weight)

        recommended_animes['final_score'] = (
            (rating_weight * recommended_animes['weighted_rating'] +
             similarity_weight * recommended_animes['similarity_score']) * (1 - recency_weight) +
            recency_weight * recommended_animes['recency_score']
        ) / (1 + recommended_animes['age_penalty'] / 10)

        return recommended_animes.sort_values('final_score', ascending=False).head(n)[
            ['Image URL', 'Name', 'anime_id', 'Type', 'Genres', 'Score', 'weighted_rating', 'final_score', 'age_penalty']
        ]

    def get_recommendations_by_genres(self, genres, n=10):
        if isinstance(genres, str):
            genres = [genres]

        valid_genres = set(self.mlb_genres.classes_)
        genres = [g.strip().lower() for g in genres if g.strip().lower() in valid_genres]
        if not genres:
            raise ValueError("No valid genres provided.")

        genre_vector = self.mlb_genres.transform([genres]).toarray()[0]
        similarity_scores = (self.genres_encoded.toarray() @ genre_vector).ravel()

        recommendations = self.anime_df.copy()
        recommendations['similarity_score'] = similarity_scores
        recommendations = recommendations[recommendations['similarity_score'] > 0]
        current_year = self.current_year

        recommendations['end_year'] = recommendations['Release_year'].fillna(current_year)
        recommendations['episodes'] = pd.to_numeric(recommendations['Episodes'], errors='coerce').fillna(self.median_episodes)
        recommendations['age_penalty'] = recommendations.apply(
            lambda row: 0 if row['Status'] == 'Currently Airing' else
            (current_year - row['end_year']) * (1 - 0.5 * min(row['episodes'] / 120, 1)),
            axis=1
        )

        recommendations = recommendations.sort_values(
            by=['weighted_rating', 'age_penalty'], ascending=[False, True]
        ).head(n)

        return recommendations[['Image URL', 'Name', 'Genres', 'age_penalty', 'weighted_rating']]

    def get_recommendations_by_genres_simple(self, genres, n=10):
        if isinstance(genres, str):
            genres = [genres]
        input_genres = {g.strip().lower() for g in genres}
        if not input_genres:
            raise ValueError("No valid genres provided.")

        if not isinstance(self.anime_df['Genres'].iloc[0], set):
            self.anime_df['Genres'] = self.anime_df['Genres'].apply(
                lambda g_list: {g.strip().lower() for g in g_list}
            )

        self.anime_df['genre_similarity'] = self.anime_df['Genres'].apply(
            lambda anime_genres: len(input_genres & anime_genres)
        )

        recommendations = self.anime_df[self.anime_df['genre_similarity'] > 0].copy()
        current_year = self.current_year
        recommendations['end_year'] = recommendations['Release_year'].fillna(current_year)
        recommendations['episodes'] = pd.to_numeric(recommendations['Episodes'], errors='coerce').fillna(self.median_episodes)

        recommendations['age_penalty'] = recommendations.apply(
            lambda row: 0 if row['Status'] == 'Currently Airing' else
            (current_year - row['end_year']) * (1 - 0.5 * min(row['episodes'] / 120, 1)),
            axis=1
        )

        recommendations = recommendations.sort_values(
            by=['genre_similarity', 'weighted_rating', 'age_penalty'], ascending=[False, False, True]
        ).head(n)

        return recommendations[['Image URL', 'Name', 'Genres', 'genre_similarity', 'weighted_rating', 'age_penalty']]
In [ ]:
AnimeRecommender = AnimeRecommender(anime_df, ratings_df)
In [ ]:
df = AnimeRecommender.get_anime_recommendations1('Darling in the FranXX', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating final_score age_penalty
21948 No description has been provided for this image Lycoris Recoil 50709 TV [action] 8.20 8.183950 1.166601 2.837500
20964 No description has been provided for this image 86 Part 2 48569 TV [scifi, drama, action] 8.71 8.692836 1.129940 3.800000
16608 No description has been provided for this image 86 41457 TV [scifi, drama, action] 8.28 8.270491 1.092477 3.816667
22263 No description has been provided for this image Engage Kiss 51417 TV [action, comedy, romance] 6.84 6.829794 1.048399 2.837500
16309 No description has been provided for this image SSSS.Dynazenon 40870 TV [scifi, action] 7.42 7.375668 1.017294 3.800000
21073 No description has been provided for this image Cardfight!! Vanguard: overDress Season 2 48862 TV [drama, action] 6.67 6.538178 0.945743 3.783333
16266 No description has been provided for this image Hypnosis Mic: Division Rap Battle - Rhyme Anima 40803 TV [scifi, action] 6.80 6.764323 0.902413 4.729167
12271 No description has been provided for this image Grancrest Senki 34279 TV [drama, action, romance, fantasy] 7.22 7.208601 0.849582 6.300000
13591 No description has been provided for this image Beatless 36516 TV [scifi, drama, action, romance] 6.21 6.215648 0.776463 6.416667
8855 No description has been provided for this image Shigatsu wa Kimi no Uso 23273 TV [drama, romance] 8.65 8.646914 0.771948 9.991667
11072 No description has been provided for this image Kiznaiver 31798 TV [scifi, drama, romance] 7.38 7.374965 0.767270 8.550000
9655 No description has been provided for this image Macross Δ 28013 TV [scifi, action, romance] 7.27 7.213781 0.763383 8.025000
9604 No description has been provided for this image Plastic Memories 27775 TV [scifi, drama, romance] 7.91 7.904120 0.761342 9.458333
10540 No description has been provided for this image Soukyuu no Fafner: Dead Aggressor - Exodus Part 2 30549 TV [scifi, drama, action] 7.61 7.309665 0.724167 9.458333
7558 No description has been provided for this image Soukyuu no Fafner: Dead Aggressor - Exodus 17080 TV [scifi, drama, action] 7.37 7.177703 0.717187 9.458333
10460 No description has been provided for this image Classroom☆Crisis 30383 TV [scifi, drama, romance] 6.97 6.949188 0.702850 9.458333
11157 No description has been provided for this image Bubuki Buranki 32023 TV [scifi, drama, action] 6.25 6.257899 0.677197 8.550000
8424 No description has been provided for this image Buddy Complex 21437 TV [scifi, action] 7.12 7.088736 0.665043 10.404167
8823 No description has been provided for this image M3: Sono Kuroki Hagane 23133 TV [scifi, drama, action, mystery] 6.57 6.553907 0.654097 9.900000
7299 No description has been provided for this image Senki Zesshou Symphogear G 15793 TV [scifi, action] 7.46 7.396078 0.650975 11.350000
6358 No description has been provided for this image Guilty Crown 10793 TV [scifi, drama, action] 7.42 7.417078 0.623158 12.716667
6594 No description has been provided for this image Senki Zesshou Symphogear 11751 TV [scifi, action] 7.03 7.004872 0.602205 12.295833
5559 No description has been provided for this image Star Driver: Kagayaki no Takuto 8934 TV [scifi, action, romance] 7.19 7.159537 0.580298 13.437500
3375 No description has been provided for this image Kidou Senshi Gundam 00 Second Season 3927 TV [scifi, drama, action] 8.08 8.048096 0.579181 15.229167
In [ ]:
df = AnimeRecommender.get_anime_recommendations1('Darling in the FranXX', n=10)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/tmp/ipython-input-39-418889061.py in <cell line: 0>()
----> 1 df = AnimeRecommender.get_anime_recommendations1('Guilty Crown', n=10)
      2 df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')
      3 
      4 display(HTML(df.to_html(escape=False)))

TypeError: AnimeRecommender.get_anime_recommendations1() missing 1 required positional argument: 'title'
In [ ]:
df = AnimeRecommender.get_anime_recommendations1('Fate/stay night: Unlimited Blade Works', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating final_score age_penalty
23475 No description has been provided for this image Dead Mount Death Play 53613 TV [action, fantasy, supernatural] 7.31 7.240476 1.407744 0.000000
20893 No description has been provided for this image Maou Gakuin no Futekigousha: Shijou Saikyou no Maou no Shiso, Tensei shite Shison-tachi no Gakkou e Kayou II 48417 TV [action, fantasy] 6.91 6.884430 1.332888 0.000000
22048 No description has been provided for this image Kimetsu no Yaiba: Katanakaji no Sato-hen 51019 TV [action, fantasy] 8.49 8.467293 1.329885 1.908333
21139 No description has been provided for this image Mahou Shoujo Magical Destroyers 48981 TV [action, fantasy] 6.49 6.470741 1.285783 0.000000
24370 No description has been provided for this image Sinbi Apateu: Zero 55047 TV [fantasy, supernatural] 6.39 6.387130 1.272720 0.000000
21905 No description has been provided for this image Yu☆Gi☆Oh! Go Rush!! 50607 TV [action, fantasy] 5.70 6.168963 1.244499 0.000000
18172 No description has been provided for this image Chainsaw Man 44511 TV [action, fantasy] 8.59 8.584003 1.193523 2.850000
20430 No description has been provided for this image Kimetsu no Yaiba: Yuukaku-hen 47778 TV [action, fantasy] 8.80 8.794506 1.171410 3.816667
21790 No description has been provided for this image Mononogatari 50384 TV [action, supernatural] 7.20 7.113428 1.144930 1.900000
24875 No description has been provided for this image Kimetsu no Yaiba: Hashira Geiko-hen 55701 TV [action, fantasy] 6.39 6.387130 1.137021 0.000000
21533 No description has been provided for this image Kimetsu no Yaiba: Mugen Ressha-hen 49926 TV [action, fantasy] 8.39 8.380549 1.133320 3.883333
24201 No description has been provided for this image Dead Mount Death Play Part 2 54743 TV [action, fantasy, supernatural] 6.39 6.387130 1.087136 1.983333
23250 No description has been provided for this image Fate/strange Fake: Whispers of Dawn 53127 Special [action, fantasy, supernatural] 6.39 6.387130 1.083347 1.991667
21685 No description has been provided for this image Seiken Gakuin no Makentsukai 50184 TV [action, fantasy] 6.39 6.387130 1.076166 0.000000
11630 No description has been provided for this image Fate/stay night Movie: Heaven's Feel - III. Spring Song 33050 Movie [action, fantasy, supernatural] 8.68 8.656426 1.073761 4.979167
22436 No description has been provided for this image Hyouken no Majutsushi ga Sekai wo Suberu 51711 TV [action, fantasy] 6.36 6.360717 1.066844 1.900000
23417 No description has been provided for this image Boushoku no Berserk 53439 TV [action, fantasy] 6.39 6.387130 1.061446 1.983333
11629 No description has been provided for this image Fate/stay night Movie: Heaven's Feel - II. Lost Butterfly 33049 Movie [action, fantasy, supernatural] 8.50 8.482620 1.004332 5.975000
14613 No description has been provided for this image Fate/Grand Order: Zettai Majuu Sensen Babylonia 38084 TV [action, fantasy, supernatural] 7.94 7.918371 0.956556 5.475000
15844 No description has been provided for this image BNA 40060 TV [action, fantasy] 7.35 7.341161 0.937340 4.750000
14163 No description has been provided for this image Sarazanmai 37426 TV [action, fantasy, supernatural] 7.49 7.449953 0.905291 5.725000
9312 No description has been provided for this image Fate/stay night Movie: Heaven's Feel - I. Presage Flower 25537 Movie [action, fantasy, supernatural] 8.17 8.156913 0.900007 7.966667
9821 No description has been provided for this image Fate/stay night: Unlimited Blade Works 2nd Season 28701 TV [action, fantasy, supernatural] 8.32 8.313739 0.878341 9.458333
12475 No description has been provided for this image Fate/Apocrypha 34662 TV [action, fantasy, supernatural] 7.19 7.184197 0.869493 7.166667
In [ ]:
df = AnimeRecommender.get_anime_recommendations1('Kimetsu no Yaiba', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating final_score age_penalty
22048 No description has been provided for this image Kimetsu no Yaiba: Katanakaji no Sato-hen 51019 TV [action, fantasy] 8.49 8.467293 1.405850 1.908333
20430 No description has been provided for this image Kimetsu no Yaiba: Yuukaku-hen 47778 TV [action, fantasy] 8.80 8.794506 1.213726 3.816667
18172 No description has been provided for this image Chainsaw Man 44511 TV [action, fantasy] 8.59 8.584003 1.194630 2.850000
21533 No description has been provided for this image Kimetsu no Yaiba: Mugen Ressha-hen 49926 TV [action, fantasy] 8.39 8.380549 1.171226 3.883333
24875 No description has been provided for this image Kimetsu no Yaiba: Hashira Geiko-hen 55701 TV [action, fantasy] 6.39 6.387130 1.137021 0.000000
16236 No description has been provided for this image Jujutsu Kaisen 40748 TV [action, award winning, fantasy] 8.64 8.637287 1.085981 4.500000
22190 No description has been provided for this image Ragna Crimson 51297 TV [action, fantasy] 6.39 6.387130 1.058089 1.983333
21741 No description has been provided for this image Delicious Party♡Precure 50281 TV [action, fantasy] 6.96 6.708747 1.049547 2.437500
16060 No description has been provided for this image Kimetsu no Yaiba Movie: Mugen Ressha-hen 40456 Movie [action, fantasy] 8.62 8.615747 1.042566 4.979167
17997 No description has been provided for this image Tropical-Rouge! Precure 44191 TV [action, fantasy] 7.41 7.052018 1.021119 3.233333
14835 No description has been provided for this image Toaru Kagaku no Railgun T 38481 TV [scifi, action, fantasy] 8.17 8.134640 1.019212 4.479167
16152 No description has been provided for this image Healin' Good♡Precure 40610 TV [action, fantasy] 6.92 6.729515 0.927384 4.062500
14899 No description has been provided for this image Star☆Twinkle Precure 38578 TV [action, fantasy] 7.53 7.150101 0.915191 4.775000
13644 No description has been provided for this image Hug tto! Precure 36593 TV [action, fantasy] 7.85 7.459017 0.892823 5.570833
8472 No description has been provided for this image Yu☆Gi☆Oh! Arc-V 21639 TV [action, fantasy] 6.70 6.683704 0.830336 5.500000
11182 No description has been provided for this image Sousei no Onmyouji 32105 TV [action, romance, fantasy] 7.30 7.292304 0.797023 7.125000
11869 No description has been provided for this image Ao no Exorcist: Kyoto Fujouou-hen 33506 TV [action, fantasy] 7.35 7.345707 0.780590 7.600000
11105 No description has been provided for this image Mahoutsukai Precure! 31884 TV [action, fantasy] 7.26 6.999381 0.778346 7.125000
12175 No description has been provided for this image Tales of Zestiria the Cross 2nd Season 34086 TV [action, adventure, fantasy] 7.31 7.288806 0.777519 7.566667
9821 No description has been provided for this image Fate/stay night: Unlimited Blade Works 2nd Season 28701 TV [action, fantasy, supernatural] 8.32 8.313739 0.764396 9.458333
11605 No description has been provided for this image Katsugeki/Touken Ranbu 33018 TV [action, fantasy] 6.73 6.711748 0.758336 7.566667
10527 No description has been provided for this image Noragami Aragoto 30503 TV [action, fantasy] 8.16 8.156397 0.753569 9.458333
10662 No description has been provided for this image Tales of Zestiria the Cross 30911 TV [action, adventure, fantasy] 7.24 7.229445 0.736357 8.550000
8617 No description has been provided for this image Fate/stay night: Unlimited Blade Works 22297 TV [action, fantasy, supernatural] 8.19 8.185116 0.718117 10.450000
In [ ]:
df = AnimeRecommender.get_anime_recommendations1('One Piece', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating final_score age_penalty
23543 No description has been provided for this image Hirogaru Sky! Precure 53716 TV [action, fantasy] 7.69 6.923455 1.408175 0.000000
21578 No description has been provided for this image Edens Zero 2nd Season 50002 TV [scifi, action, adventure, fantasy] 7.43 7.164798 1.407991 0.000000
24186 No description has been provided for this image Mahoutsukai Precure! 2 54717 TV [action, fantasy] 6.39 6.387130 1.214710 0.991667
16329 No description has been provided for this image Dragon Quest: Dai no Daibouken (2020) 40906 TV [action, adventure, fantasy] 7.74 7.643075 1.182576 2.916667
21472 No description has been provided for this image Fairy Tail: 100 Years Quest 49785 TV [action, adventure, fantasy] 6.39 6.387130 1.143662 0.000000
24174 No description has been provided for this image Boruto: Naruto Next Generations Part 2 54687 TV [action, adventure, fantasy] 6.39 6.387130 1.140456 0.000000
22481 No description has been provided for this image Nanatsu no Taizai: Mokushiroku no Yonkishi 51794 TV [action, adventure, fantasy] 6.39 6.387130 1.121166 1.983333
24042 No description has been provided for this image Ishura 54449 TV [action, adventure, fantasy] 6.39 6.387130 1.121126 0.000000
24175 No description has been provided for this image Naruto (Shinsaku Anime) 54688 TV [action, adventure, fantasy] 6.39 6.387130 1.117063 1.966667
22788 No description has been provided for this image Shangri-La Frontier: Kusoge Hunter, Kamige ni Idoman to su 52347 TV [action, adventure, fantasy] 6.39 6.387130 1.116004 1.983333
23754 No description has been provided for this image Bleach: Sennen Kessen-hen - Ketsubetsu-tan 53998 TV [action, adventure, fantasy] 6.39 6.387130 1.115509 1.983333
24185 No description has been provided for this image Kibou no Chikara: Otona Precure '23 54716 TV [action, fantasy] 6.39 6.387130 1.098529 1.983333
24677 No description has been provided for this image Naruto (2023) 55453 TV [action, comedy, adventure, fantasy] 6.39 6.387130 1.098318 1.983333
22235 No description has been provided for this image Orient: Awajishima Gekitou-hen 51368 TV [action, adventure, fantasy] 7.04 6.978657 1.094073 2.850000
17060 No description has been provided for this image Heion Sedai no Idaten-tachi 42625 TV [action, adventure, fantasy] 7.64 7.609725 1.075481 3.816667
18914 No description has been provided for this image Orient 45560 TV [action, adventure, fantasy] 6.60 6.590130 1.061672 2.850000
14699 No description has been provided for this image One Piece Movie 14: Stampede 38234 Movie [action, adventure, fantasy] 8.22 8.190025 0.980617 5.975000
10577 No description has been provided for this image Dragon Ball Super 30694 TV [action, comedy, adventure, fantasy] 7.43 7.426386 0.973232 5.000000
16405 No description has been provided for this image Digimon Adventure: 41074 TV [action, comedy, adventure, fantasy] 6.42 6.416737 0.966149 3.604167
13291 No description has been provided for this image Golden Kamuy 36028 TV [action, adventure] 7.87 7.852865 0.890325 6.650000
8558 No description has been provided for this image Fairy Tail (2014) 22043 TV [action, adventure, fantasy] 7.65 7.645865 0.888932 6.325000
13409 No description has been provided for this image One Piece: Episode of East Blue - Luffy to 4-nin no Nakama no Daibouken 36215 Special [action, adventure, fantasy] 7.88 7.758384 0.850474 7.966667
6018 No description has been provided for this image Toriko 10033 TV [comedy, gourmet, action, adventure, fantasy] 7.52 7.481460 0.849102 7.000000
8747 No description has been provided for this image Dragon Ball Kai (2014) 22777 TV [action, comedy, adventure, fantasy] 7.68 7.658538 0.812629 8.204167
In [ ]:
df = AnimeRecommender.get_anime_recommendations1('Bleach: Sennen Kessen-hen', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating final_score age_penalty
19600 No description has been provided for this image Jigokuraku 46569 TV [action, adventure, fantasy] 8.26 8.224549 1.563704 0.000000
11 No description has been provided for this image One Piece 21 TV [action, adventure, fantasy] 8.69 8.686696 1.539619 0.000000
22017 No description has been provided for this image Saikyou Onmyouji no Isekai Tenseiki 50932 TV [action, adventure, fantasy] 7.20 7.181995 1.179488 1.891667
23754 No description has been provided for this image Bleach: Sennen Kessen-hen - Ketsubetsu-tan 53998 TV [action, adventure, fantasy] 6.39 6.387130 1.143882 1.983333
21472 No description has been provided for this image Fairy Tail: 100 Years Quest 49785 TV [action, adventure, fantasy] 6.39 6.387130 1.112952 0.000000
22481 No description has been provided for this image Nanatsu no Taizai: Mokushiroku no Yonkishi 51794 TV [action, adventure, fantasy] 6.39 6.387130 1.090871 1.983333
12428 No description has been provided for this image Black Clover 34572 TV [action, comedy, fantasy] 8.14 8.136070 1.076231 4.000000
22235 No description has been provided for this image Orient: Awajishima Gekitou-hen 51368 TV [action, adventure, fantasy] 7.04 6.978657 1.072318 2.850000
16630 No description has been provided for this image Nanatsu no Taizai: Funnu no Shinpan 41491 TV [action, adventure, fantasy] 6.58 6.578161 1.002656 3.600000
12427 No description has been provided for this image Boruto: Naruto Next Generations 34566 TV [action, adventure, fantasy] 6.06 6.061365 0.947646 4.000000
6456 No description has been provided for this image Hunter x Hunter (2011) 11061 TV [action, adventure, fantasy] 9.04 9.037173 0.943020 7.000000
15440 No description has been provided for this image Radiant 2nd Season 39355 TV [action, adventure, fantasy] 7.58 7.532102 0.929037 5.475000
14165 No description has been provided for this image Tensei shitara Slime Datta Ken 37430 TV [action, comedy, adventure, fantasy] 8.14 8.136214 0.928519 6.300000
13260 No description has been provided for this image Fairy Tail: Final Series 35972 TV [action, adventure, fantasy] 7.57 7.561180 0.927846 5.512500
16774 No description has been provided for this image Hanyou no Yashahime: Sengoku Otogizoushi 41911 TV [action, adventure, fantasy] 6.70 6.684564 0.922382 4.500000
12429 No description has been provided for this image Nanatsu no Taizai: Imashime no Fukkatsu 34577 TV [action, adventure, fantasy] 7.59 7.586863 0.904220 6.300000
14331 No description has been provided for this image Overlord III 37675 TV [action, adventure, fantasy] 7.92 7.914924 0.893133 6.620833
13570 No description has been provided for this image Sword Art Online: Alicization 36474 TV [action, adventure, fantasy] 7.56 7.556488 0.892171 6.300000
15653 No description has been provided for this image Nanatsu no Taizai: Kamigami no Gekirin 39701 TV [action, adventure, fantasy] 6.46 6.459664 0.870117 5.400000
13843 No description has been provided for this image Arifureta Shokugyou de Sekai Saikyou 36882 TV [action, adventure, fantasy] 6.70 6.698515 0.857293 5.675000
14409 No description has been provided for this image Gunjou no Magmell 37806 TV [action, adventure, fantasy] 6.10 6.106922 0.830180 5.675000
1574 No description has been provided for this image Naruto: Shippuuden 1735 TV [action, adventure, fantasy] 8.26 8.257899 0.829226 9.000000
10588 No description has been provided for this image Shingeki no Bahamut: Virgin Soul 30736 TV [action, adventure, fantasy] 7.43 7.409368 0.827490 7.200000
11043 No description has been provided for this image Magi: Sinbad no Bouken (TV) 31741 TV [action, adventure, fantasy] 7.85 7.839802 0.813310 8.512500
In [ ]:
df = AnimeRecommender.get_anime_recommendations1('Hunter x Hunter (2011)', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating final_score age_penalty
11 No description has been provided for this image One Piece 21 TV [action, adventure, fantasy] 8.69 8.686696 1.539138 0.000000
21093 No description has been provided for this image Overlord IV 48895 TV [action, adventure, fantasy] 8.09 8.076119 1.198494 2.837500
22758 No description has been provided for this image Ore dake Level Up na Ken 52299 TV [action, adventure, fantasy] 6.39 6.387130 1.191686 0.991667
16329 No description has been provided for this image Dragon Quest: Dai no Daibouken (2020) 40906 TV [action, adventure, fantasy] 7.74 7.643075 1.148750 2.916667
21472 No description has been provided for this image Fairy Tail: 100 Years Quest 49785 TV [action, adventure, fantasy] 6.39 6.387130 1.116855 0.000000
10577 No description has been provided for this image Dragon Ball Super 30694 TV [action, comedy, adventure, fantasy] 7.43 7.426386 0.946701 5.000000
13260 No description has been provided for this image Fairy Tail: Final Series 35972 TV [action, adventure, fantasy] 7.57 7.561180 0.946578 5.512500
12427 No description has been provided for this image Boruto: Naruto Next Generations 34566 TV [action, adventure, fantasy] 6.06 6.061365 0.922746 4.000000
14331 No description has been provided for this image Overlord III 37675 TV [action, adventure, fantasy] 7.92 7.914924 0.910894 6.620833
8558 No description has been provided for this image Fairy Tail (2014) 22043 TV [action, adventure, fantasy] 7.65 7.645865 0.902034 6.325000
12736 No description has been provided for this image Overlord II 35073 TV [action, adventure, fantasy] 7.76 7.755981 0.898896 6.620833
15653 No description has been provided for this image Nanatsu no Taizai: Kamigami no Gekirin 39701 TV [action, adventure, fantasy] 6.46 6.459664 0.850289 5.400000
6018 No description has been provided for this image Toriko 10033 TV [comedy, gourmet, action, adventure, fantasy] 7.52 7.481460 0.837125 7.000000
1574 No description has been provided for this image Naruto: Shippuuden 1735 TV [action, adventure, fantasy] 8.26 8.257899 0.808763 9.000000
4694 No description has been provided for this image Fairy Tail 6702 TV [action, adventure, fantasy] 7.57 7.567877 0.807406 8.000000
11058 No description has been provided for this image Nejimaki Seirei Senki: Tenkyou no Alderamin 31764 TV [action, adventure, fantasy] 7.65 7.635808 0.799579 8.512500
16703 No description has been provided for this image Monkateu 41667 TV [action, adventure, fantasy] 6.39 6.387130 0.798462 6.266667
11043 No description has been provided for this image Magi: Sinbad no Bouken (TV) 31741 TV [action, adventure, fantasy] 7.85 7.839802 0.795099 8.512500
8747 No description has been provided for this image Dragon Ball Kai (2014) 22777 TV [action, comedy, adventure, fantasy] 7.68 7.658538 0.793952 8.204167
10134 No description has been provided for this image Overlord 29803 TV [action, adventure, fantasy] 7.91 7.907027 0.774153 9.458333
3961 No description has been provided for this image Fullmetal Alchemist: Brotherhood 5114 TV [drama, action, adventure, fantasy] 9.10 9.097636 0.742336 11.733333
4416 No description has been provided for this image Dragon Ball Kai 6033 TV [action, comedy, adventure, fantasy] 7.73 7.719814 0.740963 9.533333
7799 No description has been provided for this image Magi: The Kingdom of Magic 18115 TV [action, adventure, fantasy] 8.22 8.212752 0.726797 10.750000
245 No description has been provided for this image Bleach 269 TV [action, adventure, fantasy] 7.92 7.917476 0.726078 10.500000
In [ ]:
df = AnimeRecommender.get_anime_recommendations1('Bleach', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating final_score age_penalty
19600 No description has been provided for this image Jigokuraku 46569 TV [action, adventure, fantasy] 8.26 8.224549 1.533767 0.000000
16617 No description has been provided for this image Bleach: Sennen Kessen-hen 41467 TV [action, adventure, fantasy] 9.07 9.048079 1.403018 2.837500
16329 No description has been provided for this image Dragon Quest: Dai no Daibouken (2020) 40906 TV [action, adventure, fantasy] 7.74 7.643075 1.150671 2.916667
23754 No description has been provided for this image Bleach: Sennen Kessen-hen - Ketsubetsu-tan 53998 TV [action, adventure, fantasy] 6.39 6.387130 1.143882 1.983333
12428 No description has been provided for this image Black Clover 34572 TV [action, comedy, fantasy] 8.14 8.136070 1.101288 4.000000
22235 No description has been provided for this image Orient: Awajishima Gekitou-hen 51368 TV [action, adventure, fantasy] 7.04 6.978657 1.071986 2.850000
16630 No description has been provided for this image Nanatsu no Taizai: Funnu no Shinpan 41491 TV [action, adventure, fantasy] 6.58 6.578161 0.976640 3.600000
12427 No description has been provided for this image Boruto: Naruto Next Generations 34566 TV [action, adventure, fantasy] 6.06 6.061365 0.972418 4.000000
6456 No description has been provided for this image Hunter x Hunter (2011) 11061 TV [action, adventure, fantasy] 9.04 9.037173 0.962227 7.000000
13260 No description has been provided for this image Fairy Tail: Final Series 35972 TV [action, adventure, fantasy] 7.57 7.561180 0.947759 5.512500
10577 No description has been provided for this image Dragon Ball Super 30694 TV [action, comedy, adventure, fantasy] 7.43 7.426386 0.946675 5.000000
8558 No description has been provided for this image Fairy Tail (2014) 22043 TV [action, adventure, fantasy] 7.65 7.645865 0.903553 6.325000
1574 No description has been provided for this image Naruto: Shippuuden 1735 TV [action, adventure, fantasy] 8.26 8.257899 0.843707 9.000000
4694 No description has been provided for this image Fairy Tail 6702 TV [action, adventure, fantasy] 7.57 7.567877 0.809000 8.000000
11043 No description has been provided for this image Magi: Sinbad no Bouken (TV) 31741 TV [action, adventure, fantasy] 7.85 7.839802 0.795354 8.512500
8747 No description has been provided for this image Dragon Ball Kai (2014) 22777 TV [action, comedy, adventure, fantasy] 7.68 7.658538 0.793952 8.204167
11291 No description has been provided for this image D.Gray-man Hallow 32370 TV [action, adventure, fantasy] 7.70 7.671143 0.784868 8.512500
14405 No description has been provided for this image Tokyo Ghoul:re 2nd Season 37799 TV [horror, action, fantasy] 6.43 6.429838 0.783645 6.650000
13588 No description has been provided for this image Tokyo Ghoul:re 36511 TV [horror, action, fantasy] 6.37 6.370037 0.779183 6.650000
9225 No description has been provided for this image Akatsuki no Yona 25013 TV [action, romance, adventure, fantasy] 8.03 8.022766 0.766408 9.900000
3961 No description has been provided for this image Fullmetal Alchemist: Brotherhood 5114 TV [drama, action, adventure, fantasy] 9.10 9.097636 0.743270 11.733333
4416 No description has been provided for this image Dragon Ball Kai 6033 TV [action, comedy, adventure, fantasy] 7.73 7.719814 0.742782 9.533333
1344 No description has been provided for this image D.Gray-man 1482 TV [action, adventure, fantasy] 8.02 8.009810 0.728096 10.845833
10 No description has been provided for this image Naruto 20 TV [action, adventure, fantasy] 7.99 7.988501 0.725557 11.500000
In [ ]:
df = AnimeRecommender.get_anime_recommendations1('Kimetsu no Yaiba: Yuukaku-hen', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating final_score age_penalty
22048 No description has been provided for this image Kimetsu no Yaiba: Katanakaji no Sato-hen 51019 TV [action, fantasy] 8.49 8.467293 1.437633 1.908333
20893 No description has been provided for this image Maou Gakuin no Futekigousha: Shijou Saikyou no Maou no Shiso, Tensei shite Shison-tachi no Gakkou e Kayou II 48417 TV [action, fantasy] 6.91 6.884430 1.383529 0.000000
23543 No description has been provided for this image Hirogaru Sky! Precure 53716 TV [action, fantasy] 7.69 6.923455 1.374168 0.000000
21905 No description has been provided for this image Yu☆Gi☆Oh! Go Rush!! 50607 TV [action, fantasy] 5.70 6.168963 1.277073 0.000000
21533 No description has been provided for this image Kimetsu no Yaiba: Mugen Ressha-hen 49926 TV [action, fantasy] 8.39 8.380549 1.245945 3.883333
18172 No description has been provided for this image Chainsaw Man 44511 TV [action, fantasy] 8.59 8.584003 1.245837 2.850000
21793 No description has been provided for this image Mato Seihei no Slave 50392 TV [action, ecchi, fantasy] 6.39 6.387130 1.208660 0.991667
24875 No description has been provided for this image Kimetsu no Yaiba: Hashira Geiko-hen 55701 TV [action, fantasy] 6.39 6.387130 1.208456 0.000000
21207 No description has been provided for this image High Card 49154 TV [action, fantasy] 7.14 7.089661 1.169196 1.900000
23669 No description has been provided for this image Ao no Exorcist (Shin Series) 53889 TV [action, fantasy] 6.39 6.387130 1.140456 0.000000
21515 No description has been provided for this image Tensei shitara Ken deshita 49891 TV [action, fantasy] 7.55 7.531441 1.122883 2.850000
22748 No description has been provided for this image Nokemono-tachi no Yoru 52274 TV [action, fantasy] 6.58 6.550538 1.115787 1.891667
22190 No description has been provided for this image Ragna Crimson 51297 TV [action, fantasy] 6.39 6.387130 1.115509 1.983333
22042 No description has been provided for this image Jujutsu Kaisen 2nd Season 51009 TV [action, fantasy] 6.39 6.387130 1.115509 1.983333
22049 No description has been provided for this image Helck 51020 TV [action, fantasy] 6.39 6.387130 1.108854 1.983333
21685 No description has been provided for this image Seiken Gakuin no Makentsukai 50184 TV [action, fantasy] 6.39 6.387130 1.108668 0.000000
22436 No description has been provided for this image Hyouken no Majutsushi ga Sekai wo Suberu 51711 TV [action, fantasy] 6.36 6.360717 1.095980 1.900000
23417 No description has been provided for this image Boushoku no Berserk 53439 TV [action, fantasy] 6.39 6.387130 1.090731 1.983333
24265 No description has been provided for this image Kikansha no Mahou wa Tokubetsu desu 54852 TV [action, fantasy] 6.39 6.387130 1.089456 1.983333
21031 No description has been provided for this image Gaikotsu Kishi-sama, Tadaima Isekai e Odekakechuu 48760 TV [action, fantasy] 7.17 7.159906 1.088318 2.850000
22235 No description has been provided for this image Orient: Awajishima Gekitou-hen 51368 TV [action, adventure, fantasy] 7.04 6.978657 1.074215 2.850000
16060 No description has been provided for this image Kimetsu no Yaiba Movie: Mugen Ressha-hen 40456 Movie [action, fantasy] 8.62 8.615747 1.070059 4.979167
14539 No description has been provided for this image Kimetsu no Yaiba 38000 TV [action, award winning, fantasy] 8.50 8.498085 1.066900 5.350000
17060 No description has been provided for this image Heion Sedai no Idaten-tachi 42625 TV [action, adventure, fantasy] 7.64 7.609725 1.059244 3.816667
In [ ]:
df = AnimeRecommender.get_recommendations_by_genres_simple(['horror', 'action']	, n=50)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name Genres genre_similarity weighted_rating age_penalty
23 No description has been provided for this image Kenpuu Denki Berserk {horror, drama, action, adventure, fantasy} 2 8.548288 25.083333
708 No description has been provided for this image Hellsing Ultimate {horror, action, supernatural} 2 8.342544 18.208333
8677 No description has been provided for this image Kiseijuu: Sei no Kakuritsu {scifi, horror, action} 2 8.336886 9.900000
6671 No description has been provided for this image Berserk: Ougon Jidai-hen III - Kourin {horror, drama, action, adventure, fantasy} 2 8.176690 11.950000
28 No description has been provided for this image Akira {horror, supernatural, action, scifi, adventure} 2 8.153587 36.845833
14942 No description has been provided for this image Dorohedoro {horror, action, comedy, fantasy} 2 8.048611 4.750000
509 No description has been provided for this image Vampire Hunter D (2000) {horror, romance, drama, action, scifi, fantasy} 2 7.880489 24.895833
6670 No description has been provided for this image Berserk: Ougon Jidai-hen II - Doldrey Kouryaku {horror, drama, action, adventure, fantasy} 2 7.850457 12.945833
8619 No description has been provided for this image Tokyo Ghoul {horror, action, fantasy} 2 7.788620 10.450000
12774 No description has been provided for this image Devilman: Crybaby {horror, action, supernatural, avant garde} 2 7.756334 6.708333
6099 No description has been provided for this image Berserk: Ougon Jidai-hen I - Haou no Tamago {horror, drama, action, adventure, fantasy} 2 7.683875 12.945833
23140 No description has been provided for this image Berserk: Ougon Jidai-hen - Memorial Edition {horror, drama, action, adventure, fantasy} 2 7.673791 2.837500
12419 No description has been provided for this image Koutetsujou no Kabaneri Movie 3: Unato Kessen {drama, action, horror, fantasy} 2 7.653065 5.975000
3155 No description has been provided for this image JoJo no Kimyou na Bouken: Phantom Blood {horror, action, adventure} 2 7.630798 17.925000
128 No description has been provided for this image Blood+ {horror, mystery, supernatural, drama, action} 2 7.606274 15.833333
11751 No description has been provided for this image Ajin Part 2 {horror, action, mystery, supernatural} 2 7.567470 8.512500
246 No description has been provided for this image Hellsing {horror, action, supernatural} 2 7.484577 22.700000
4801 No description has been provided for this image Hellsing: Digest for Freaks {horror, action, supernatural} 2 7.479373 18.920833
202 No description has been provided for this image Elfen Lied {horror, supernatural, drama, action, romance} 2 7.477739 19.862500
11876 No description has been provided for this image Koutetsujou no Kabaneri Movie 2: Moeru Inochi {drama, action, horror, fantasy} 2 7.439158 7.966667
11875 No description has been provided for this image Koutetsujou no Kabaneri Movie 1: Tsudou Hikari {drama, action, horror, fantasy} 2 7.434561 8.962500
883 No description has been provided for this image Change!! Getter Robo: Sekai Saigo no Hi {scifi, horror, action, adventure} 2 7.428132 25.537500
12182 No description has been provided for this image Danganronpa 3: The End of Kibougamine Gakuen - Kibou-hen {horror, action, mystery} 2 7.402755 8.962500
10960 No description has been provided for this image Ajin {horror, action, mystery, supernatural} 2 7.393813 8.512500
11171 No description has been provided for this image Gantz:O {scifi, drama, action, horror} 2 7.379877 8.962500
11613 No description has been provided for this image Danganronpa 3: The End of Kibougamine Gakuen - Zetsubou-hen {horror, action, mystery} 2 7.369897 8.587500
10642 No description has been provided for this image Ajin Part 1: Shoudou {horror, action, mystery, supernatural} 2 7.338186 9.958333
10513 No description has been provided for this image Tokyo Ghoul: "Jack" {horror, action, fantasy} 2 7.288512 9.958333
1320 No description has been provided for this image Kemonozume {horror, action, romance, supernatural} 2 7.268849 17.970833
9798 No description has been provided for this image Koutetsujou no Kabaneri {drama, action, horror, fantasy} 2 7.266267 8.550000
2961 No description has been provided for this image Mnemosyne: Mnemosyne no Musume-tachi {horror, supernatural, girls love, action, scifi} 2 7.238974 16.575000
3920 No description has been provided for this image Shikabane Hime: Kuro {horror, action, supernatural} 2 7.223877 15.200000
11210 No description has been provided for this image Danganronpa 3: The End of Kibougamine Gakuen - Mirai-hen {horror, action, mystery} 2 7.221937 8.550000
10849 No description has been provided for this image Tokyo Ghoul: "Pinto" {horror, action, fantasy} 2 7.187825 9.958333
3717 No description has been provided for this image Shikabane Hime: Aka {horror, action, supernatural} 2 7.159253 16.079167
4784 No description has been provided for this image Deadman Wonderland {scifi, horror, action, supernatural} 2 7.147983 13.300000
6297 No description has been provided for this image Blood-C: The Last Dark {horror, action, supernatural} 2 7.132560 12.945833
12206 No description has been provided for this image Super Danganronpa 2.5: Komaeda Nagito to Sekai no Hakaimono {horror, action, suspense, mystery} 2 7.115634 7.966667
2459 No description has been provided for this image Tokyo Majin Gakuen Kenpucho: Tou Dai Ni Maku {horror, mystery, drama, action, fantasy} 2 7.109664 17.100000
11155 No description has been provided for this image Ajin OVA {horror, action, mystery, supernatural} 2 7.108905 8.925000
6461 No description has been provided for this image Hellsing: The Dawn {horror, action, supernatural} 2 7.098920 13.825000
8733 No description has been provided for this image Terra Formars: Bugs 2-hen {scifi, horror, action} 2 7.086941 10.908333
5207 No description has been provided for this image Highschool of the Dead {horror, action, ecchi, supernatural} 2 7.068681 14.250000
2708 No description has been provided for this image Shin Getter Robo {scifi, horror, action, adventure} 2 7.067195 19.862500
642 No description has been provided for this image Kyuuketsuhime Miyu (TV) {drama, action, horror} 2 7.061079 24.966667
16394 No description has been provided for this image Dorohedoro: Ma no Omake {horror, action, comedy, fantasy} 2 7.055402 4.875000
5804 No description has been provided for this image Biohazard: Damnation {scifi, horror, action} 2 7.047338 12.945833
10643 No description has been provided for this image Ajin Part 2: Shoutotsu {horror, action, mystery, supernatural} 2 7.029073 8.962500
1696 No description has been provided for this image Tokyo Majin Gakuen Kenpucho: Tou {horror, supernatural, drama, action, fantasy} 2 7.028130 16.950000
10644 No description has been provided for this image Ajin Part 3: Shougeki {horror, action, mystery, supernatural} 2 7.026792 8.962500
In [ ]:
df = AnimeRecommender.get_anime_recommendations1('Chainsaw Man', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating final_score age_penalty
19600 No description has been provided for this image Jigokuraku 46569 TV {action, adventure, fantasy} 8.26 8.224549 1.560568 0.000000
22709 No description has been provided for this image Mashle 52211 TV {action, comedy, fantasy} 7.59 7.553219 1.449163 0.000000
22048 No description has been provided for this image Kimetsu no Yaiba: Katanakaji no Sato-hen 51019 TV {action, fantasy} 8.49 8.467293 1.336205 1.908333
21139 No description has been provided for this image Mahou Shoujo Magical Destroyers 48981 TV {action, fantasy} 6.49 6.470741 1.317749 0.000000
20972 No description has been provided for this image Shingeki no Kyojin: The Final Season Part 2 48583 TV {drama, action} 8.77 8.763341 1.238309 2.850000
21403 No description has been provided for this image Chiyu Mahou no Machigatta Tsukaikata: Senjou wo Kakeru Kaifuku Youin 49613 TV {action, fantasy} 6.39 6.387130 1.191462 0.991667
20430 No description has been provided for this image Kimetsu no Yaiba: Yuukaku-hen 47778 TV {action, fantasy} 8.80 8.794506 1.175615 3.816667
22042 No description has been provided for this image Jujutsu Kaisen 2nd Season 51009 TV {action, fantasy} 6.39 6.387130 1.172255 1.983333
21207 No description has been provided for this image High Card 49154 TV {action, fantasy} 7.14 7.089661 1.170209 1.900000
24875 No description has been provided for this image Kimetsu no Yaiba: Hashira Geiko-hen 55701 TV {action, fantasy} 6.39 6.387130 1.140456 0.000000
23669 No description has been provided for this image Ao no Exorcist (Shin Series) 53889 TV {action, fantasy} 6.39 6.387130 1.140456 0.000000
21533 No description has been provided for this image Kimetsu no Yaiba: Mugen Ressha-hen 49926 TV {action, fantasy} 8.39 8.380549 1.134483 3.883333
21515 No description has been provided for this image Tensei shitara Ken deshita 49891 TV {action, fantasy} 7.55 7.531441 1.125021 2.850000
22190 No description has been provided for this image Ragna Crimson 51297 TV {action, fantasy} 6.39 6.387130 1.120044 1.983333
22748 No description has been provided for this image Nokemono-tachi no Yoru 52274 TV {action, fantasy} 6.58 6.550538 1.117246 1.891667
23663 No description has been provided for this image Arknights: Fuyukomori Kaerimichi 53881 TV {action, fantasy} 6.39 6.387130 1.110861 0.000000
16236 No description has been provided for this image Jujutsu Kaisen 40748 TV {action, award winning, fantasy} 8.64 8.637287 1.104581 4.500000
22436 No description has been provided for this image Hyouken no Majutsushi ga Sekai wo Suberu 51711 TV {action, fantasy} 6.36 6.360717 1.096955 1.900000
17060 No description has been provided for this image Heion Sedai no Idaten-tachi 42625 TV {action, adventure, fantasy} 7.64 7.609725 1.093722 3.816667
22481 No description has been provided for this image Nanatsu no Taizai: Mokushiroku no Yonkishi 51794 TV {action, adventure, fantasy} 6.39 6.387130 1.093422 1.983333
21031 No description has been provided for this image Gaikotsu Kishi-sama, Tadaima Isekai e Odekakechuu 48760 TV {action, fantasy} 7.17 7.159906 1.087822 2.850000
22069 No description has been provided for this image Kuro no Shoukanshi 51064 TV {action, fantasy} 7.10 7.087070 1.086927 2.850000
21696 No description has been provided for this image Arknights: Reimei Zensou 50205 TV {action, fantasy} 7.13 7.087613 1.076639 2.900000
14942 No description has been provided for this image Dorohedoro 38668 TV {horror, action, comedy, fantasy} 8.06 8.048611 1.047240 4.750000
In [ ]:
df = AnimeRecommender.get_anime_recommendations2('Tensei shitara Slime Datta Ken', n=24)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating final_score age_penalty
19600 No description has been provided for this image Jigokuraku 46569 TV [fantasy, action, adventure] 8.26 8.224549 1.538809 0.000000
16617 No description has been provided for this image Bleach: Sennen Kessen-hen 41467 TV [fantasy, action, adventure] 9.07 9.048079 1.269965 2.837500
15568 No description has been provided for this image Tensei shitara Slime Datta Ken 2nd Season 39551 TV [fantasy, action, adventure, comedy] 8.39 8.382957 1.197764 3.800000
23458 No description has been provided for this image Tensei shitara Slime Datta Ken 3rd Season 53580 TV [fantasy, action, adventure, comedy] 6.39 6.387130 1.196618 0.991667
16626 No description has been provided for this image Tensei shitara Slime Datta Ken 2nd Season Part 2 41487 TV [fantasy, action, adventure, comedy] 8.33 8.321181 1.184758 3.800000
21510 No description has been provided for this image Tensei shitara Slime Datta Ken Movie: Guren no Kizuna-hen 49877 Movie [fantasy, action, adventure, comedy] 7.63 7.587295 1.107159 2.987500
24677 No description has been provided for this image Naruto (2023) 55453 TV [fantasy, action, adventure, comedy] 6.39 6.387130 1.092246 1.983333
21472 No description has been provided for this image Fairy Tail: 100 Years Quest 49785 TV [fantasy, action, adventure] 6.39 6.387130 1.092210 0.000000
24116 No description has been provided for this image Tensei shitara Slime Datta Ken: Coleus no Yume 54565 OVA [fantasy, action, adventure, comedy] 6.39 6.387130 1.077132 1.975000
16627 No description has been provided for this image Tensura Nikki: Tensei shitara Slime Datta Ken 41488 TV [fantasy, comedy] 7.59 7.574482 1.075618 3.800000
14524 No description has been provided for this image Kumo desu ga, Nani ka? 37984 TV [fantasy, comedy, action, adventure, mystery] 7.45 7.441162 1.047976 3.600000
22052 No description has been provided for this image Duel Masters King Max 51037 TV [fantasy, action, adventure, comedy] 6.39 6.387130 1.019977 2.787500
16630 No description has been provided for this image Nanatsu no Taizai: Funnu no Shinpan 41491 TV [fantasy, action, adventure] 6.58 6.578161 0.982486 3.600000
22003 No description has been provided for this image Hoshi no Samidare 50891 TV [action, adventure, comedy, drama] 5.64 5.721517 0.955434 2.700000
10577 No description has been provided for this image Dragon Ball Super 30694 TV [fantasy, action, adventure, comedy] 7.43 7.426386 0.946056 5.000000
13221 No description has been provided for this image Lupin III: Part 5 35857 TV [action, adventure, mystery, comedy] 8.13 7.955901 0.902684 6.300000
15029 No description has been provided for this image Tensei shitara Slime Datta Ken OVA 38793 OVA [fantasy, action, adventure, comedy] 7.49 7.472148 0.895563 5.875000
12429 No description has been provided for this image Nanatsu no Taizai: Imashime no Fukkatsu 34577 TV [fantasy, action, adventure] 7.59 7.586863 0.892227 6.300000
14800 No description has been provided for this image Arad: Gyakuten no Wa 38416 TV [fantasy, action, adventure, comedy] 5.82 6.337777 0.878517 4.729167
11801 No description has been provided for this image Cardcaptor Sakura: Clear Card-hen 33354 TV [romance, adventure, fantasy, comedy] 7.65 7.600925 0.871620 6.358333
13124 No description has been provided for this image Yama no Susume Third Season 35672 TV [adventure, slice of life, comedy] 7.59 7.401887 0.863175 6.620833
15653 No description has been provided for this image Nanatsu no Taizai: Kamigami no Gekirin 39701 TV [fantasy, action, adventure] 6.46 6.459664 0.856502 5.400000
12531 No description has been provided for this image Mahoujin Guruguru (2017) 34745 TV [adventure, fantasy, comedy] 7.81 7.597635 0.845437 7.200000
14409 No description has been provided for this image Gunjou no Magmell 37806 TV [fantasy, action, adventure] 6.10 6.106922 0.810942 5.675000
In [ ]:
df['Name']
Out[ ]:
Name
19600 Jigokuraku
16617 Bleach: Sennen Kessen-hen
15568 Tensei shitara Slime Datta Ken 2nd Season
23458 Tensei shitara Slime Datta Ken 3rd Season
16626 Tensei shitara Slime Datta Ken 2nd Season Part 2
21510 Tensei shitara Slime Datta Ken Movie: Guren no...
24677 Naruto (2023)
21472 Fairy Tail: 100 Years Quest
24116 Tensei shitara Slime Datta Ken: Coleus no Yume
16627 Tensura Nikki: Tensei shitara Slime Datta Ken
14524 Kumo desu ga, Nani ka?
22052 Duel Masters King Max
16630 Nanatsu no Taizai: Funnu no Shinpan
22003 Hoshi no Samidare
10577 Dragon Ball Super
13221 Lupin III: Part 5
15029 Tensei shitara Slime Datta Ken OVA
12429 Nanatsu no Taizai: Imashime no Fukkatsu
14800 Arad: Gyakuten no Wa
11801 Cardcaptor Sakura: Clear Card-hen
13124 Yama no Susume Third Season
15653 Nanatsu no Taizai: Kamigami no Gekirin
12531 Mahoujin Guruguru (2017)
14409 Gunjou no Magmell

The AnimeRecommender1 class builds upon the earlier AnimeRecommender implementation by refining the genre-based recommendation logic and improving the robustness of set operations. Previously, genre filtering was prone to inconsistencies due to format mismatches or missing preprocessing. This updated version resolves that by dynamically converting genre lists into standardized sets, ensuring accurate genre matching regardless of input format. Additionally, the revised logic supports full subset matching using issubset() to only recommend anime that include all user-specified genres. This enhancement makes genre filtering more precise and eliminates false matches—effectively solving a subtle reliability issue in the earlier system.

Genre-Based Recommendation Methodology (Improved Genre Subset Matching)¶

The enhanced genre-based recommendation method implemented in the AnimeRecommender1 class adopts a rigorous set-theoretic approach to ensure precise alignment between user-specified genre preferences and the genre composition of candidate anime titles. Unlike prior implementations that relied on partial overlaps or genre count similarity, the improved method enforces a subset constraint, thereby ensuring that only anime whose genre sets fully contain all requested genres are considered for recommendation.

1. Genre Input Normalization¶

User-provided genre queries are first preprocessed into standardized, lowercase string sets:

input_genres = {g.strip().lower() for g in genres}

This step mitigates inconsistencies arising from formatting variations and capitalization in the genre metadata.

2. Genre Representation Alignment¶

Each anime's Genres list is dynamically converted into a Python set to enable direct subset comparisons:

genre_sets = self.anime_df['Genres'].apply(lambda g_list: {g.strip().lower() for g in g_list})

This ensures that genre comparisons are type-consistent, precise, and scalable across large datasets.

3. Subset Filtering¶

A boolean mask is computed for each anime entry, evaluating whether the user-specified genres are a subset of the anime's genres:

self.anime_df['has_all_genres'] = genre_sets.apply(lambda anime_genres: input_genres.issubset(anime_genres))

Only anime entries where this condition holds true are retained for further ranking.

4. Temporal Adjustment via Age Penalty¶

To discourage overly outdated or long-running anime, an age penalty function is applied:

$$ \text{age_penalty} = \begin{cases} 0 & \text{if status is 'Currently Airing'} \\ (\text{current_year} - \text{end_year}) \cdot \left(1 - 0.5 \cdot \min\left(\frac{\text{episodes}}{120}, 1\right)\right) & \text{otherwise} \end{cases} $$

This formula penalizes older anime while accounting for their length, with shorter series receiving reduced penalties.

5. Ranking and Recommendation Output¶

The final list is sorted based on:

  1. Weighted rating (IMDb-style formula integrating rating value and popularity).
  2. Age penalty, in ascending order.

Only the top-N anime entries that meet the genre subset condition and rank highest after age adjustment are returned as recommendations.


Comparative Advantage¶

This revised methodology improves upon earlier implementations by enforcing stricter semantic coherence between user intent and system output. It avoids the inclusion of marginally related anime and provides a more targeted and trustworthy recommendation experience, particularly for users with specific genre preferences.

In [ ]:
class AnimeRecommender1:
    def __init__(self, anime_df, ratings_df):
        self.nlp = spacy.load("en_core_web_sm")
        self.anime_df = anime_df.copy()
        self.ratings_df = ratings_df.copy()
        self.nlp = spacy.load("en_core_web_sm")
        self.current_year = datetime.now().year

        self._preprocess_data()
        self._create_feature_matrices()

        self.weights = {
            'genres': 0.30,
            'synopsis': 0.35,
            'type': 0.15,
            'studios': 0.10,
            'episodes': 0.05,
            'source': 0.05
        }

    def _preprocess_data(self):
        self.anime_df['Score'] = self.anime_df['Score'].replace('[^0-9.]', '', regex=True)
        self.anime_df['Scored By'] = self.anime_df['Scored By'].replace('[^0-9]', '', regex=True)
        self.anime_df['Score'] = pd.to_numeric(self.anime_df['Score'], errors='coerce')
        self.anime_df['Scored By'] = pd.to_numeric(self.anime_df['Scored By'], errors='coerce')
        self.anime_df['Score'].fillna(self.anime_df['Score'].median(), inplace=True)
        self.anime_df['Scored By'].fillna(self.anime_df['Scored By'].median(), inplace=True)
        self.anime_df['Release_year'] = self.anime_df['Aired'].str.extract(r'(\d{4})').astype(float)

        def normalize_genre_list(genre_string):
            if genre_string == 'UNKNOWN' or pd.isna(genre_string):
                return []
            genres = re.split(r',\s*', genre_string)
            cleaned = [re.sub(r'[^\w\s]', '', g).strip().lower() for g in genres]
            return list(set(cleaned))

        self.anime_df['Genres'] = self.anime_df['Genres'].apply(normalize_genre_list)
        self.anime_df['Studios'] = self.anime_df['Studios'].apply(normalize_genre_list)

        C = self.anime_df['Score'].mean()
        m = self.anime_df['Scored By'].quantile(0.65)
        self.anime_df['weighted_rating'] = (
            (self.anime_df['Scored By'] / (self.anime_df['Scored By'] + m)) * self.anime_df['Score'] +
            (m / (self.anime_df['Scored By'] + m)) * C
        )

    def _create_feature_matrices(self):
        self.mlb_genres = MultiLabelBinarizer(sparse_output=True)
        self.genres_encoded = self.mlb_genres.fit_transform(self.anime_df['Genres'])

        self.mlb_studios = MultiLabelBinarizer(sparse_output=True)
        self.studios_encoded = self.mlb_studios.fit_transform(self.anime_df['Studios'])

        self.ohe_type = OneHotEncoder(sparse_output=True)
        self.type_encoded = self.ohe_type.fit_transform(self.anime_df[['Type']])

        self.ohe_source = OneHotEncoder(sparse_output=True)
        self.source_encoded = self.ohe_source.fit_transform(self.anime_df[['Source']])

        self.anime_df['Episodes'] = pd.to_numeric(self.anime_df['Episodes'], errors='coerce')
        self.median_episodes = self.anime_df['Episodes'].median()
        self.anime_df['Episodes'].fillna(self.median_episodes, inplace=True)

        self.bins = [0, 1, 12, 24, 50, np.inf]
        self.labels = ['1', '2-12', '13-24', '25-50', '51+']
        self.anime_df['Episodes_Binned'] = pd.cut(self.anime_df['Episodes'], bins=self.bins, labels=self.labels)
        self.ohe_episodes = OneHotEncoder(sparse_output=True)
        self.episodes_encoded = self.ohe_episodes.fit_transform(self.anime_df[['Episodes_Binned']])

        self.anime_df['Synopsis'] = self._clean_text(self.anime_df['Synopsis'].fillna(''))
        self.tfidf = TfidfVectorizer(stop_words='english')
        self.synopsis_encoded = self.tfidf.fit_transform(self.anime_df['Synopsis'])

    def _clean_text(self, text_series: pd.Series) -> pd.Series:
        return text_series.apply(self._spacy_clean)

    def _spacy_clean(self, text: str) -> str:
        doc = self.nlp(text.lower())
        return ' '.join(
            token.lemma_ for token in doc
            if not token.is_stop and not token.is_punct and token.is_alpha
        )

    def _calculate_recency_boost(self, release_year):
        year = release_year if pd.notna(release_year) else self.anime_df['Release_year'].min()
        min_year = self.anime_df['Release_year'].min()
        max_year = self.anime_df['Release_year'].max()
        year_range = max_year - min_year if max_year != min_year else 1
        scaled_year = (year - min_year) / year_range
        return scaled_year

    def _calculate_anime_similarity(self, idx: int):
        genres_sim = cosine_similarity(self.genres_encoded[idx:idx+1], self.genres_encoded)[0]
        studios_sim = cosine_similarity(self.studios_encoded[idx:idx+1], self.studios_encoded)[0]
        synopsis_sim = cosine_similarity(self.synopsis_encoded[idx:idx+1], self.synopsis_encoded)[0]
        type_sim = (self.anime_df['Type'] == self.anime_df.iloc[idx]['Type']).astype(float).values
        source_sim = (self.anime_df['Source'] == self.anime_df.iloc[idx]['Source']).astype(float).values
        episodes_sim = (self.anime_df['Episodes_Binned'] == self.anime_df.iloc[idx]['Episodes_Binned']).astype(float).values

        combined_sim = (
            self.weights['genres'] * genres_sim +
            self.weights['synopsis'] * synopsis_sim +
            self.weights['type'] * type_sim +
            self.weights['studios'] * studios_sim +
            self.weights['episodes'] * episodes_sim +
            self.weights['source'] * source_sim
        )

        sim_scores = np.array(list(enumerate(combined_sim)))
        num_recs_to_get = min(52, len(self.anime_df) - 1)
        sorted_sim_scores = sim_scores[sim_scores[:, 1].argsort()[::-1]]
        top_sim = sorted_sim_scores[1:num_recs_to_get + 1]

        top_indices = top_sim[:, 0].astype(int)
        sim_scores_top = top_sim[:, 1]
        return sim_scores_top, top_indices

    def get_user_recommendations(self, user_id, n=10, top_k=20):
        user_ratings = self.ratings_df[self.ratings_df['user_id'] == user_id]
        if user_ratings.empty:
            return pd.DataFrame()

        top_rated = (
            user_ratings
            .merge(self.anime_df, on='anime_id')
            .nlargest(top_k, 'rating')
            [['anime_id', 'rating', 'Release_year']]
        )

        candidate_scores = defaultdict(float)
        anime_id_to_index = pd.Series(self.anime_df.index, index=self.anime_df['anime_id']).to_dict()

        for _, row in top_rated.iterrows():
            anime_id = row['anime_id']
            if anime_id in anime_id_to_index:
                anime_idx = anime_id_to_index[anime_id]
                sim_scores_top, top_indices = self._calculate_anime_similarity(anime_idx)
                recency = self._calculate_recency_boost(row['Release_year'])
                weighted_scores = sim_scores_top * row['rating'] * recency

                for i, rec_idx in enumerate(top_indices):
                    if rec_idx < len(self.anime_df):
                        candidate_scores[rec_idx] += weighted_scores[i]

        watched_ids = set(user_ratings['anime_id'])
        recommended_anime_indices = sorted(candidate_scores.keys(), key=lambda k: candidate_scores[k], reverse=True)
        recommended_anime_indices = [idx for idx in recommended_anime_indices if self.anime_df.iloc[idx]['anime_id'] not in watched_ids]
        top_n_indices = recommended_anime_indices[:n]

        recommendations = (
            self.anime_df
            .iloc[top_n_indices]
            .assign(predicted_score=lambda x: x.index.map(candidate_scores))
            [['Name', 'Image URL', 'anime_id', 'Type', 'Genres', 'Score', 'predicted_score']]
        )

        return recommendations

    def get_anime_recommendations(self, title, n=10, similarity_weight=0.85, recency_weight=0.2):
        matching_animes = self.anime_df[self.anime_df['Name'] == title]
        if matching_animes.empty:
            raise ValueError(f"Anime '{title}' not found in the database.")
        idx = matching_animes.index[0]

        sim_scores_top, top_indices = self._calculate_anime_similarity(idx)

        recommended_animes = self.anime_df.iloc[top_indices][
            ['Image URL', 'Name', 'anime_id', 'Type', 'Genres', 'Score', 'weighted_rating', 'Release_year']
        ].copy()

        recommended_animes['recency_score'] = recommended_animes['Release_year'].apply(self._calculate_recency_boost)
        recommended_animes['similarity_score'] = sim_scores_top

        rating_weight = max(0, 1 - similarity_weight)
        similarity_weight = max(0, similarity_weight)
        recency_weight = max(0, recency_weight)

        recommended_animes['final_score'] = (
            (rating_weight * recommended_animes['weighted_rating'] +
             similarity_weight * recommended_animes['similarity_score']) * (1 - recency_weight) +
            recency_weight * recommended_animes['recency_score']
        )

        return recommended_animes.sort_values('final_score', ascending=False).head(n)

    def get_anime_recommendations1(self, title, n=10, similarity_weight=0.85, recency_weight=0.2):
        matching_animes = self.anime_df[self.anime_df['Name'] == title]
        if matching_animes.empty:
            raise ValueError(f"Anime '{title}' not found in the database.")
        idx = matching_animes.index[0]

        sim_scores_top, top_indices = self._calculate_anime_similarity(idx)

        recommended_animes = self.anime_df.iloc[top_indices][
            ['Image URL', 'Name', 'anime_id', 'Type', 'Genres', 'Score', 'weighted_rating', 'Release_year', 'Episodes', 'Status']
        ].copy()

        recommended_animes['similarity_score'] = sim_scores_top
        recommended_animes['recency_score'] = recommended_animes['Release_year'].apply(self._calculate_recency_boost)
        recommended_animes['end_year'] = recommended_animes['Release_year'].fillna(self.current_year)
        recommended_animes['episodes'] = pd.to_numeric(recommended_animes['Episodes'], errors='coerce').fillna(self.median_episodes)

        recommended_animes['age_penalty'] = recommended_animes.apply(
            lambda row: 0 if row['Status'] == 'Currently Airing' else
            (self.current_year - row['end_year']) * (1 - 0.5 * min(row['episodes'] / 120, 1)),
            axis=1
        )

        rating_weight = max(0, 1 - similarity_weight)
        similarity_weight = max(0, similarity_weight)
        recency_weight = max(0, recency_weight)

        recommended_animes['final_score'] = (
            (rating_weight * recommended_animes['weighted_rating'] +
             similarity_weight * recommended_animes['similarity_score']) * (1 - recency_weight) +
            recency_weight * recommended_animes['recency_score']
        ) / (1 + recommended_animes['age_penalty'] / 10)

        return recommended_animes.sort_values('final_score', ascending=False).head(n)[
            ['Image URL', 'Name', 'anime_id', 'Type', 'Genres', 'Score', 'weighted_rating', 'final_score', 'age_penalty']
        ]

    def get_recommendations_by_genres_simple(self, genres, n=10):
        if isinstance(genres, str):
            genres = [genres]
        input_genres = {g.strip().lower() for g in genres}
        if not input_genres:
            raise ValueError("No valid genres provided.")

        # Always safely convert genre lists to sets on-the-fly
        genre_sets = self.anime_df['Genres'].apply(lambda g_list: {g.strip().lower() for g in g_list})
        self.anime_df['has_all_genres'] = genre_sets.apply(
            lambda anime_genres: input_genres.issubset(anime_genres)
        )

        recommendations = self.anime_df[self.anime_df['has_all_genres']].copy()
        current_year = self.current_year
        recommendations['end_year'] = recommendations['Release_year'].fillna(current_year)
        recommendations['episodes'] = pd.to_numeric(recommendations['Episodes'], errors='coerce').fillna(self.median_episodes)

        recommendations['age_penalty'] = recommendations.apply(
            lambda row: 0 if row['Status'] == 'Currently Airing' else
            (current_year - row['end_year']) * (1 - 0.5 * min(row['episodes'] / 120, 1)),
            axis=1
        )

        recommendations = recommendations.sort_values(
            by=['weighted_rating', 'age_penalty'], ascending=[False, True]
        ).head(n)

        return recommendations[['Image URL', 'Name', 'Genres', 'weighted_rating', 'age_penalty']]
Lets make an instance and do some tests...¶
In [ ]:
AnimeRecommender1 = AnimeRecommender1(anime_df, ratings_df)
In [ ]:
df = AnimeRecommender1.get_recommendations_by_genres_simple(['horror', 'action']	, n=50)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name Genres weighted_rating age_penalty
23 No description has been provided for this image Kenpuu Denki Berserk [horror, drama, action, adventure, fantasy] 8.548288 25.083333
708 No description has been provided for this image Hellsing Ultimate [horror, action, supernatural] 8.342544 18.208333
8677 No description has been provided for this image Kiseijuu: Sei no Kakuritsu [scifi, horror, action] 8.336886 9.900000
6671 No description has been provided for this image Berserk: Ougon Jidai-hen III - Kourin [horror, drama, action, adventure, fantasy] 8.176690 11.950000
28 No description has been provided for this image Akira [horror, supernatural, action, scifi, adventure] 8.153587 36.845833
14942 No description has been provided for this image Dorohedoro [horror, action, comedy, fantasy] 8.048611 4.750000
509 No description has been provided for this image Vampire Hunter D (2000) [horror, drama, action, scifi, fantasy, romance] 7.880489 24.895833
6670 No description has been provided for this image Berserk: Ougon Jidai-hen II - Doldrey Kouryaku [horror, drama, action, adventure, fantasy] 7.850457 12.945833
8619 No description has been provided for this image Tokyo Ghoul [horror, action, fantasy] 7.788620 10.450000
12774 No description has been provided for this image Devilman: Crybaby [horror, action, supernatural, avant garde] 7.756334 6.708333
6099 No description has been provided for this image Berserk: Ougon Jidai-hen I - Haou no Tamago [horror, drama, action, adventure, fantasy] 7.683875 12.945833
23140 No description has been provided for this image Berserk: Ougon Jidai-hen - Memorial Edition [horror, drama, action, adventure, fantasy] 7.673791 2.837500
12419 No description has been provided for this image Koutetsujou no Kabaneri Movie 3: Unato Kessen [drama, action, horror, fantasy] 7.653065 5.975000
3155 No description has been provided for this image JoJo no Kimyou na Bouken: Phantom Blood [horror, action, adventure] 7.630798 17.925000
128 No description has been provided for this image Blood+ [horror, mystery, supernatural, drama, action] 7.606274 15.833333
11751 No description has been provided for this image Ajin Part 2 [horror, action, mystery, supernatural] 7.567470 8.512500
246 No description has been provided for this image Hellsing [horror, action, supernatural] 7.484577 22.700000
4801 No description has been provided for this image Hellsing: Digest for Freaks [horror, action, supernatural] 7.479373 18.920833
202 No description has been provided for this image Elfen Lied [horror, supernatural, drama, action, romance] 7.477739 19.862500
11876 No description has been provided for this image Koutetsujou no Kabaneri Movie 2: Moeru Inochi [drama, action, horror, fantasy] 7.439158 7.966667
11875 No description has been provided for this image Koutetsujou no Kabaneri Movie 1: Tsudou Hikari [drama, action, horror, fantasy] 7.434561 8.962500
883 No description has been provided for this image Change!! Getter Robo: Sekai Saigo no Hi [scifi, horror, action, adventure] 7.428132 25.537500
12182 No description has been provided for this image Danganronpa 3: The End of Kibougamine Gakuen - Kibou-hen [horror, action, mystery] 7.402755 8.962500
10960 No description has been provided for this image Ajin [horror, action, mystery, supernatural] 7.393813 8.512500
11171 No description has been provided for this image Gantz:O [scifi, drama, action, horror] 7.379877 8.962500
11613 No description has been provided for this image Danganronpa 3: The End of Kibougamine Gakuen - Zetsubou-hen [horror, action, mystery] 7.369897 8.587500
10642 No description has been provided for this image Ajin Part 1: Shoudou [horror, action, mystery, supernatural] 7.338186 9.958333
10513 No description has been provided for this image Tokyo Ghoul: "Jack" [horror, action, fantasy] 7.288512 9.958333
1320 No description has been provided for this image Kemonozume [horror, action, romance, supernatural] 7.268849 17.970833
9798 No description has been provided for this image Koutetsujou no Kabaneri [drama, action, horror, fantasy] 7.266267 8.550000
2961 No description has been provided for this image Mnemosyne: Mnemosyne no Musume-tachi [horror, supernatural, girls love, action, scifi] 7.238974 16.575000
3920 No description has been provided for this image Shikabane Hime: Kuro [horror, action, supernatural] 7.223877 15.200000
11210 No description has been provided for this image Danganronpa 3: The End of Kibougamine Gakuen - Mirai-hen [horror, action, mystery] 7.221937 8.550000
10849 No description has been provided for this image Tokyo Ghoul: "Pinto" [horror, action, fantasy] 7.187825 9.958333
3717 No description has been provided for this image Shikabane Hime: Aka [horror, action, supernatural] 7.159253 16.079167
4784 No description has been provided for this image Deadman Wonderland [scifi, horror, action, supernatural] 7.147983 13.300000
6297 No description has been provided for this image Blood-C: The Last Dark [horror, action, supernatural] 7.132560 12.945833
12206 No description has been provided for this image Super Danganronpa 2.5: Komaeda Nagito to Sekai no Hakaimono [horror, action, suspense, mystery] 7.115634 7.966667
2459 No description has been provided for this image Tokyo Majin Gakuen Kenpucho: Tou Dai Ni Maku [horror, mystery, drama, action, fantasy] 7.109664 17.100000
11155 No description has been provided for this image Ajin OVA [horror, action, mystery, supernatural] 7.108905 8.925000
6461 No description has been provided for this image Hellsing: The Dawn [horror, action, supernatural] 7.098920 13.825000
8733 No description has been provided for this image Terra Formars: Bugs 2-hen [scifi, horror, action] 7.086941 10.908333
5207 No description has been provided for this image Highschool of the Dead [horror, action, ecchi, supernatural] 7.068681 14.250000
2708 No description has been provided for this image Shin Getter Robo [scifi, horror, action, adventure] 7.067195 19.862500
642 No description has been provided for this image Kyuuketsuhime Miyu (TV) [drama, action, horror] 7.061079 24.966667
16394 No description has been provided for this image Dorohedoro: Ma no Omake [horror, action, comedy, fantasy] 7.055402 4.875000
5804 No description has been provided for this image Biohazard: Damnation [scifi, horror, action] 7.047338 12.945833
10643 No description has been provided for this image Ajin Part 2: Shoutotsu [horror, action, mystery, supernatural] 7.029073 8.962500
1696 No description has been provided for this image Tokyo Majin Gakuen Kenpucho: Tou [horror, supernatural, drama, action, fantasy] 7.028130 16.950000
10644 No description has been provided for this image Ajin Part 3: Shougeki [horror, action, mystery, supernatural] 7.026792 8.962500
In [ ]:
df = AnimeRecommender1.get_recommendations_by_genres_simple([ 'scifi','action','romance',]	, n=50)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name Genres weighted_rating age_penalty
509 No description has been provided for this image Vampire Hunter D (2000) [horror, drama, action, scifi, fantasy, romance] 7.880489 24.895833
3131 No description has been provided for this image Macross F [scifi, action, award winning, romance] 7.850851 15.229167
988 No description has been provided for this image Macross [scifi, action, romance] 7.828247 36.550000
989 No description has been provided for this image Macross: Do You Remember Love? [scifi, action, romance] 7.823890 40.829167
4922 No description has been provided for this image Macross F Movie 2: Sayonara no Tsubasa [scifi, action, award winning, romance] 7.758669 13.941667
16612 No description has been provided for this image Date A Live IV [scifi, action, romance] 7.746146 2.850000
72 No description has been provided for this image Kidou Senshi Gundam SEED [award winning, drama, action, scifi, romance] 7.724560 18.208333
4074 No description has been provided for this image Macross F Movie 1: Itsuwari no Utahime [scifi, action, romance] 7.646773 15.933333
373 No description has been provided for this image Seikai no Senki II [scifi, action, romance] 7.612668 23.000000
1181 No description has been provided for this image Urusei Yatsura [comedy, drama, action, scifi, adventure, romance] 7.608737 22.000000
74 No description has been provided for this image Turn A Gundam [award winning, drama, action, scifi, adventure, romance] 7.606676 20.583333
1752 No description has been provided for this image Urusei Yatsura 2: Beautiful Dreamer [comedy, drama, action, scifi, adventure, romance] 7.585621 40.829167
372 No description has been provided for this image Seikai no Senki [scifi, action, romance] 7.528374 23.645833
266 No description has been provided for this image Seikai no Monshou [scifi, action, romance] 7.528017 24.591667
1104 No description has been provided for this image Macross Plus Movie Edition [scifi, action, adventure, romance] 7.462419 29.875000
374 No description has been provided for this image Seikai no Senki III [scifi, action, romance] 7.440590 19.833333
8305 No description has been provided for this image Mahouka Koukou no Rettousei [scifi, action, romance, fantasy] 7.406821 9.808333
195 No description has been provided for this image Kidou Senkan Nadesico [scifi, action, romance] 7.397964 25.858333
143 No description has been provided for this image RahXephon [award winning, mystery, drama, action, scifi, romance] 7.349977 20.508333
9140 No description has been provided for this image Date A Live Movie: Mayuri Judgment [scifi, action, romance] 7.315063 9.958333
911 No description has been provided for this image Tenchi Muyou! in Love [scifi, action, comedy, romance] 7.278265 28.879167
16090 No description has been provided for this image Mahouka Koukou no Rettousei: Raihousha-hen [scifi, action, romance, fantasy] 7.269632 4.729167
538 No description has been provided for this image Saber Marionette J [comedy, drama, action, scifi, adventure, romance] 7.260175 25.979167
6597 No description has been provided for this image Accel World [scifi, action, romance] 7.226102 11.700000
92 No description has been provided for this image Uchuu no Stellvia [scifi, action, romance] 7.215704 19.616667
9655 No description has been provided for this image Macross Δ [scifi, action, romance] 7.213781 8.025000
13216 No description has been provided for this image Darling in the FranXX [scifi, drama, action, romance] 7.208504 6.300000
1325 No description has been provided for this image Uchuu no Kishi Tekkaman Blade [drama, action, scifi, adventure, romance] 7.190315 26.262500
8000 No description has been provided for this image Date A Live II [scifi, action, romance] 7.186278 10.541667
13676 No description has been provided for this image Date A Live III [scifi, action, romance] 7.182833 5.700000
793 No description has been provided for this image Zegapain [scifi, action, romance] 7.163313 16.941667
5559 No description has been provided for this image Star Driver: Kagayaki no Takuto [scifi, action, romance] 7.159537 13.437500
73 No description has been provided for this image Kidou Senshi Gundam SEED Destiny [scifi, drama, action, romance] 7.158412 16.625000
7047 No description has been provided for this image Accel World EX [scifi, action, romance] 7.079104 12.891667
1266 No description has been provided for this image Macross 7 [comedy, drama, action, scifi, adventure, romance] 7.076136 24.670833
6198 No description has been provided for this image Aquarion Evol [scifi, action, romance, fantasy] 7.053481 11.591667
449 No description has been provided for this image Sousei no Aquarion [scifi, action, romance, fantasy] 7.052144 17.833333
3078 No description has been provided for this image Genius Party [action, avant garde, scifi, fantasy, romance] 7.047031 17.475000
1755 No description has been provided for this image Urusei Yatsura Movie 5: Kanketsu-hen [comedy, drama, action, scifi, adventure, romance] 7.042509 36.845833
1086 No description has been provided for this image Saber Marionette J Again [scifi, action, comedy, romance] 7.031205 27.300000
2100 No description has been provided for this image Kidou Senshi Gundam SEED Destiny Special Edition [scifi, drama, action, romance] 7.001912 18.683333
986 No description has been provided for this image Kenran Butou Sai: The Mars Daybreak [comedy, action, scifi, adventure, romance] 6.999471 18.725000
11040 No description has been provided for this image Gakusen Toshi Asterisk 2nd Season [comedy, action, ecchi, scifi, fantasy, romance] 6.995652 8.550000
462 No description has been provided for this image Armitage III: Poly-Matrix [scifi, action, adventure, romance] 6.922447 28.879167
979 No description has been provided for this image Armitage III [scifi, action, adventure, romance] 6.919472 29.500000
514 No description has been provided for this image Wonderful Days [scifi, drama, action, romance] 6.918831 21.908333
2181 No description has been provided for this image Cybersix [scifi, action, adventure, romance] 6.917548 24.591667
903 No description has been provided for this image Blue Seed [horror, comedy, mystery, drama, action, ecchi, scifi, adventure, romance] 6.910652 27.641667
1774 No description has been provided for this image Photon [comedy, drama, action, ecchi, scifi, adventure, romance] 6.889656 27.300000
693 No description has been provided for this image RahXephon: Tagen Hensoukyoku [scifi, drama, action, romance] 6.876021 21.908333
In [ ]:
df = AnimeRecommender1.get_anime_recommendations1('Kizumonogatari III: Reiketsu-hen'	, n=50)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating final_score age_penalty
21051 No description has been provided for this image Mahou Shoujo Madoka★Magica Movie 4: Walpurgis no Kaiten 48820 Movie [drama, suspense, mystery, supernatural] 6.39 6.387130 1.088235 0.000000
16445 No description has been provided for this image Princess Principal: Crown Handler Movie 3 41141 Movie [action, mystery] 6.39 6.387130 1.055164 1.991667
21930 No description has been provided for this image Mahoutsukai no Yoru 50668 Movie [mystery, supernatural] 6.39 6.387130 1.055164 1.991667
22375 No description has been provided for this image City Hunter Movie: Tenshi no Namida 51585 Movie [action, mystery] 6.39 6.387130 1.055164 1.991667
14410 No description has been provided for this image Princess Principal: Crown Handler Movie 1 37807 Movie [action, mystery] 7.52 7.311564 0.982313 3.983333
16444 No description has been provided for this image Princess Principal: Crown Handler Movie 2 41140 Movie [action, mystery] 7.71 7.316857 0.982012 3.983333
13907 No description has been provided for this image Zoku Owarimonogatari 36999 Movie [comedy, mystery, supernatural] 8.45 8.414520 0.958951 6.825000
11051 No description has been provided for this image Kizumonogatari II: Nekketsu-hen 31757 Movie [action, mystery, supernatural] 8.58 8.565061 0.956823 8.962500
5670 No description has been provided for this image Kizumonogatari I: Tekketsu-hen 9260 Movie [action, mystery, supernatural] 8.37 8.357224 0.897322 8.962500
12647 No description has been provided for this image Bungou Stray Dogs: Dead Apple 34944 Movie [action, mystery, supernatural] 7.92 7.901468 0.870743 6.970833
11076 No description has been provided for this image Kuroshitsuji Movie: Book of the Atlantic 31812 Movie [action, comedy, mystery, supernatural] 8.25 8.211884 0.826493 7.966667
14089 No description has been provided for this image K: Seven Stories Movie 4 - Lost Small World - Ori no Mukou ni 37305 Movie [action, supernatural] 7.44 7.189447 0.817666 6.970833
14090 No description has been provided for this image K: Seven Stories Movie 5 - Memory of Red - Burn 37306 Movie [action, supernatural] 7.62 7.329238 0.807656 6.970833
14087 No description has been provided for this image K: Seven Stories Movie 2 - Side:Blue - Tenrou no Gotoku 37303 Movie [action, supernatural] 7.30 7.102172 0.791741 6.970833
13791 No description has been provided for this image Servamp Movie: Alice in the Garden 36803 Movie [action, supernatural] 7.24 7.063517 0.787954 6.970833
20810 No description has been provided for this image Sinbi Apateu Movie: Haneuldokkaebi Dae Yoleumungandeu 48271 Movie [mystery, supernatural] 6.39 6.387130 0.787424 5.975000
12975 No description has been provided for this image Donten ni Warau Gaiden: Shukumei, Soutou no Fuuma 35424 Movie [action, supernatural] 7.51 7.001060 0.784547 6.970833
14091 No description has been provided for this image K: Seven Stories Movie 6 - Circle Vision - Nameless Song 37307 Movie [action, supernatural] 7.19 6.978058 0.781912 6.970833
14088 No description has been provided for this image K: Seven Stories Movie 3 - Side:Green - Uwagaki Sekai 37304 Movie [action, supernatural] 7.14 6.960402 0.781520 6.970833
13786 No description has been provided for this image Owarimonogatari 2nd Season Recaps 36796 Special [comedy, mystery, supernatural] 7.80 7.565795 0.780914 7.933333
12352 No description has been provided for this image Overlord Movie 2: Shikkoku no Eiyuu 34428 Movie [action, fantasy, supernatural] 7.66 7.577513 0.779492 7.966667
12209 No description has been provided for this image Overlord Movie 1: Fushisha no Ou 34161 Movie [action, fantasy, supernatural] 7.61 7.535257 0.776669 7.966667
12976 No description has been provided for this image Donten ni Warau Gaiden: Ouka, Tenbou no Kakehashi 35425 Movie [action, supernatural] 7.16 6.780010 0.774289 6.970833
11150 No description has been provided for this image Detective Conan Movie 20: The Darkest Nightmare 32005 Movie [action, mystery] 8.17 8.037584 0.766312 8.962500
20809 No description has been provided for this image Sinbi Apateu: Geumbich Dokkaebiwa Bimil-ui Dong-gul 48270 Movie [mystery, supernatural] 6.39 6.387130 0.740127 6.970833
11838 No description has been provided for this image Walking Meat 33438 Movie [action, supernatural] 6.39 6.387130 0.740127 6.970833
12747 No description has been provided for this image Donten ni Warau Gaiden: Ketsubetsu, Yamainu no Chikai 35086 Movie [action, supernatural] 7.40 6.987897 0.739563 7.966667
10643 No description has been provided for this image Ajin Part 2: Shoutotsu 30869 Movie [horror, action, mystery, supernatural] 7.22 7.029073 0.709749 8.962500
10644 No description has been provided for this image Ajin Part 3: Shougeki 30870 Movie [horror, action, mystery, supernatural] 7.24 7.026792 0.709605 8.962500
9753 No description has been provided for this image Detective Conan Movie 19: The Hellfire Sunflowers 28479 Movie [action, mystery] 7.72 7.618908 0.700617 9.958333
10642 No description has been provided for this image Ajin Part 1: Shoudou 30868 Movie [horror, action, mystery, supernatural] 7.44 7.338186 0.691993 9.958333
8418 No description has been provided for this image Detective Conan Movie 18: The Sniper from Another Dimension 21419 Movie [action, mystery] 8.07 7.951886 0.687619 10.954167
7156 No description has been provided for this image Kara no Kyoukai Movie: Mirai Fukuin 14807 Movie [drama, mystery, supernatural] 8.00 7.946199 0.656134 11.950000
3944 No description has been provided for this image Bakemonogatari 5081 TV [romance, mystery, supernatural] 8.33 8.325189 0.597078 15.000000
10409 No description has been provided for this image Ghost Messenger Movie 30278 Movie [action, supernatural] 5.68 6.305062 0.591791 10.954167
7096 No description has been provided for this image Persona 4 the Animation: The Factor of Hope 14267 Movie [action, adventure, mystery, supernatural] 7.27 7.027294 0.580441 12.945833
4008 No description has been provided for this image Kara no Kyoukai Movie 7: Satsujin Kousatsu (Go) 5205 Movie [suspense, mystery, supernatural, action, romance] 8.39 8.358043 0.578928 15.933333
4594 No description has been provided for this image Detective Conan Movie 14: The Lost Ship in the Sky 6467 Movie [action, mystery] 8.11 8.018776 0.577354 14.937500
6537 No description has been provided for this image Un-Go: Inga-ron 11531 Movie [mystery, supernatural] 7.54 7.441425 0.573560 13.941667
6319 No description has been provided for this image Towa no Quon 2: Konton no Ranbu 10713 Movie [scifi, action, mystery, supernatural] 7.32 7.245869 0.566480 13.941667
4130 No description has been provided for this image Detective Conan Movie 13: The Raven Chaser 5460 Movie [action, mystery] 8.21 8.115840 0.558738 15.933333
3568 No description has been provided for this image Kara no Kyoukai Movie 5: Mujun Rasen 4282 Movie [suspense, mystery, supernatural, drama, action, romance] 8.53 8.500891 0.558579 16.929167
3268 No description has been provided for this image Kara no Kyoukai Movie 3: Tsuukaku Zanryuu 3783 Movie [suspense, mystery, supernatural, drama, action] 8.02 7.998942 0.542886 16.929167
3567 No description has been provided for this image Kara no Kyoukai Movie 4: Garan no Dou 4280 Movie [action, suspense, mystery, supernatural] 7.83 7.810155 0.540824 16.929167
4007 No description has been provided for this image Kara no Kyoukai Movie 6: Boukyaku Rokuon 5204 Movie [suspense, mystery, supernatural, action, romance] 7.46 7.442779 0.517242 16.929167
3267 No description has been provided for this image Kara no Kyoukai Movie 2: Satsujin Kousatsu (Zen) 3782 Movie [suspense, mystery, supernatural, action, romance] 7.78 7.763108 0.510976 17.925000
2379 No description has been provided for this image Kara no Kyoukai Movie 1: Fukan Fuukei 2593 Movie [action, suspense, mystery, supernatural] 7.57 7.558499 0.508916 17.925000
3993 No description has been provided for this image First Squad: The Moment of Truth 5178 Movie [action, supernatural] 5.95 5.984949 0.459673 15.933333
672 No description has been provided for this image Vampire Hunter D 732 Movie [scifi, horror, action, supernatural] 7.01 6.986076 0.256773 39.833333
7841 No description has been provided for this image Dokkaebi Bangmang-I 18325 Movie [action, supernatural] 6.39 6.387130 0.245057 38.837500

Now lets add the Collaborative filtering:¶

In [ ]:
class AnimeRecommender1:
    def __init__(self, anime_df, ratings_df):
        self.nlp = spacy.load("en_core_web_sm")
        self.anime_df = anime_df.copy()
        self.ratings_df = ratings_df.copy()
        self.nlp = spacy.load("en_core_web_sm")
        self.current_year = datetime.now().year

        self._preprocess_data()
        self._create_feature_matrices()

        self.weights = {
            'genres': 0.30,
            'synopsis': 0.35,
            'type': 0.15,
            'studios': 0.10,
            'episodes': 0.05,
            'source': 0.05
        }

    def _preprocess_data(self):
        self.anime_df['Score'] = self.anime_df['Score'].replace('[^0-9.]', '', regex=True)
        self.anime_df['Scored By'] = self.anime_df['Scored By'].replace('[^0-9]', '', regex=True)
        self.anime_df['Score'] = pd.to_numeric(self.anime_df['Score'], errors='coerce')
        self.anime_df['Scored By'] = pd.to_numeric(self.anime_df['Scored By'], errors='coerce')
        self.anime_df['Score'].fillna(self.anime_df['Score'].median(), inplace=True)
        self.anime_df['Scored By'].fillna(self.anime_df['Scored By'].median(), inplace=True)
        self.anime_df['Release_year'] = self.anime_df['Aired'].str.extract(r'(\d{4})').astype(float)

        def normalize_genre_list(genre_string):
            if genre_string == 'UNKNOWN' or pd.isna(genre_string):
                return []
            genres = re.split(r',\s*', genre_string)
            cleaned = [re.sub(r'[^\w\s]', '', g).strip().lower() for g in genres]
            return list(set(cleaned))

        self.anime_df['Genres'] = self.anime_df['Genres'].apply(normalize_genre_list)
        self.anime_df['Studios'] = self.anime_df['Studios'].apply(normalize_genre_list)

        C = self.anime_df['Score'].mean()
        m = self.anime_df['Scored By'].quantile(0.65)
        self.anime_df['weighted_rating'] = (
            (self.anime_df['Scored By'] / (self.anime_df['Scored By'] + m)) * self.anime_df['Score'] +
            (m / (self.anime_df['Scored By'] + m)) * C
        )

    def _create_feature_matrices(self):
        self.mlb_genres = MultiLabelBinarizer(sparse_output=True)
        self.genres_encoded = self.mlb_genres.fit_transform(self.anime_df['Genres'])

        self.mlb_studios = MultiLabelBinarizer(sparse_output=True)
        self.studios_encoded = self.mlb_studios.fit_transform(self.anime_df['Studios'])

        self.ohe_type = OneHotEncoder(sparse_output=True)
        self.type_encoded = self.ohe_type.fit_transform(self.anime_df[['Type']])

        self.ohe_source = OneHotEncoder(sparse_output=True)
        self.source_encoded = self.ohe_source.fit_transform(self.anime_df[['Source']])

        self.anime_df['Episodes'] = pd.to_numeric(self.anime_df['Episodes'], errors='coerce')
        self.median_episodes = self.anime_df['Episodes'].median()
        self.anime_df['Episodes'].fillna(self.median_episodes, inplace=True)

        self.bins = [0, 1, 12, 24, 50, np.inf]
        self.labels = ['1', '2-12', '13-24', '25-50', '51+']
        self.anime_df['Episodes_Binned'] = pd.cut(self.anime_df['Episodes'], bins=self.bins, labels=self.labels)
        self.ohe_episodes = OneHotEncoder(sparse_output=True)
        self.episodes_encoded = self.ohe_episodes.fit_transform(self.anime_df[['Episodes_Binned']])

        self.anime_df['Synopsis'] = self._clean_text(self.anime_df['Synopsis'].fillna(''))
        self.tfidf = TfidfVectorizer(stop_words='english')
        self.synopsis_encoded = self.tfidf.fit_transform(self.anime_df['Synopsis'])

    def _clean_text(self, text_series: pd.Series) -> pd.Series:
        return text_series.apply(self._spacy_clean)

    def _spacy_clean(self, text: str) -> str:
        doc = self.nlp(text.lower())
        return ' '.join(
            token.lemma_ for token in doc
            if not token.is_stop and not token.is_punct and token.is_alpha
        )

    def _calculate_recency_boost(self, release_year):
        year = release_year if pd.notna(release_year) else self.anime_df['Release_year'].min()
        min_year = self.anime_df['Release_year'].min()
        max_year = self.anime_df['Release_year'].max()
        year_range = max_year - min_year if max_year != min_year else 1
        scaled_year = (year - min_year) / year_range
        return scaled_year

    def _calculate_anime_similarity(self, idx: int):
        genres_sim = cosine_similarity(self.genres_encoded[idx:idx+1], self.genres_encoded)[0]
        studios_sim = cosine_similarity(self.studios_encoded[idx:idx+1], self.studios_encoded)[0]
        synopsis_sim = cosine_similarity(self.synopsis_encoded[idx:idx+1], self.synopsis_encoded)[0]
        type_sim = (self.anime_df['Type'] == self.anime_df.iloc[idx]['Type']).astype(float).values
        source_sim = (self.anime_df['Source'] == self.anime_df.iloc[idx]['Source']).astype(float).values
        episodes_sim = (self.anime_df['Episodes_Binned'] == self.anime_df.iloc[idx]['Episodes_Binned']).astype(float).values

        combined_sim = (
            self.weights['genres'] * genres_sim +
            self.weights['synopsis'] * synopsis_sim +
            self.weights['type'] * type_sim +
            self.weights['studios'] * studios_sim +
            self.weights['episodes'] * episodes_sim +
            self.weights['source'] * source_sim
        )

        sim_scores = np.array(list(enumerate(combined_sim)))
        num_recs_to_get = min(52, len(self.anime_df) - 1)
        sorted_sim_scores = sim_scores[sim_scores[:, 1].argsort()[::-1]]
        top_sim = sorted_sim_scores[1:num_recs_to_get + 1]

        top_indices = top_sim[:, 0].astype(int)
        sim_scores_top = top_sim[:, 1]
        return sim_scores_top, top_indices

    def get_anime_recommendations1(self, title, user_id, n=10,best_svd_model=SVD_model, similarity_weight=0.85, recency_weight=0.2, svd_weight=0.6):
      matching_animes = self.anime_df[self.anime_df['Name'] == title]
      if matching_animes.empty:
        raise ValueError(f"Anime '{title}' not found in the database.")
      idx = matching_animes.index[0]

      sim_scores_top, top_indices = self._calculate_anime_similarity(idx)

      recommended_animes = self.anime_df.iloc[top_indices][
        ['Image URL', 'Name', 'anime_id', 'Type', 'Genres', 'Score', 'weighted_rating', 'Release_year', 'Episodes', 'Status']
      ].copy()

      recommended_animes['similarity_score'] = sim_scores_top
      recommended_animes['recency_score'] = recommended_animes['Release_year'].apply(self._calculate_recency_boost)
      recommended_animes['end_year'] = recommended_animes['Release_year'].fillna(self.current_year)
      recommended_animes['episodes'] = pd.to_numeric(recommended_animes['Episodes'], errors='coerce').fillna(self.median_episodes)

      recommended_animes['age_penalty'] = recommended_animes.apply(
        lambda row: 0 if row['Status'] == 'Currently Airing' else
        (self.current_year - row['end_year']) * (1 - 0.5 * min(row['episodes'] / 120, 1)),
        axis=1
        )

    # 🔄 Predict SVD ratings for this user if model and anime_id mapping exists
      svd_preds = []
      for anime_id in recommended_animes['anime_id']:
        try:
          pred = best_svd_model.predict(user_id, anime_id).est
        except Exception:
          pred = best_svd_model.trainset.global_mean  # fallback
        svd_preds.append(pred)

      recommended_animes['svd_pred'] = svd_preds

    # 🔄 Normalize weights
      rating_weight = max(0, 1 - similarity_weight)
      similarity_weight = max(0, similarity_weight)
      recency_weight = max(0, recency_weight)
      svd_weight = max(0, min(svd_weight, 1))
    # 🔄 Blend collaborative + content score
      content_score = (
        rating_weight * recommended_animes['weighted_rating'] +
        similarity_weight * recommended_animes['similarity_score']
    )

      recommended_animes['final_score'] = (
        ((1 - svd_weight) * content_score + svd_weight * recommended_animes['svd_pred']) * (1 - recency_weight) +
        recency_weight * recommended_animes['recency_score']
    ) / (1 + recommended_animes['age_penalty'] / 10)

      return recommended_animes.sort_values('final_score', ascending=False).head(n)[
        ['Image URL', 'Name', 'anime_id', 'Type', 'Genres', 'Score', 'weighted_rating', 'svd_pred', 'final_score', 'age_penalty']
    ]

    def get_recommendations_by_genres_simple(self, genres, n=10):
        if isinstance(genres, str):
            genres = [genres]
        input_genres = {g.strip().lower() for g in genres}
        if not input_genres:
            raise ValueError("No valid genres provided.")

        # Always safely convert genre lists to sets on-the-fly
        genre_sets = self.anime_df['Genres'].apply(lambda g_list: {g.strip().lower() for g in g_list})
        self.anime_df['has_all_genres'] = genre_sets.apply(
            lambda anime_genres: input_genres.issubset(anime_genres)
        )

        recommendations = self.anime_df[self.anime_df['has_all_genres']].copy()
        current_year = self.current_year
        recommendations['end_year'] = recommendations['Release_year'].fillna(current_year)
        recommendations['episodes'] = pd.to_numeric(recommendations['Episodes'], errors='coerce').fillna(self.median_episodes)

        recommendations['age_penalty'] = recommendations.apply(
            lambda row: 0 if row['Status'] == 'Currently Airing' else
            (current_year - row['end_year']) * (1 - 0.5 * min(row['episodes'] / 120, 1)),
            axis=1
        )

        recommendations = recommendations.sort_values(
            by=['weighted_rating', 'age_penalty'], ascending=[False, True]
        ).head(n)

        return recommendations[['Image URL', 'Name', 'Genres', 'weighted_rating', 'age_penalty']]
  • lets load the SVD model
In [ ]:
import pickle
with open('/content/drive/MyDrive/Anime Recommender System/svd_best_model13.pkl', 'rb') as f:
    SVD_model = pickle.load(f)
In [ ]:
recommender = AnimeRecommender1(anime_df, ratings_df)
In [ ]:
df = recommender.get_anime_recommendations1(
    title='One Piece',
    user_id=1,
    best_svd_model=SVD_model,
    n=24,
    similarity_weight=0.60,
    recency_weight=0.2,
    svd_weight=0.9
)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating svd_pred final_score age_penalty
23543 No description has been provided for this image Hirogaru Sky! Precure 53716 TV [fantasy, action] 7.69 6.923455 7.775836 6.043347 0.000000
21578 No description has been provided for this image Edens Zero 2nd Season 50002 TV [fantasy, adventure, scifi, action] 7.43 7.164798 7.302414 5.708149 0.000000
21472 No description has been provided for this image Fairy Tail: 100 Years Quest 49785 TV [fantasy, adventure, action] 6.39 6.387130 7.519458 5.645024 0.000000
24174 No description has been provided for this image Boruto: Naruto Next Generations Part 2 54687 TV [fantasy, adventure, action] 6.39 6.387130 7.519458 5.644798 0.000000
24042 No description has been provided for this image Ishura 54449 TV [fantasy, adventure, action] 6.39 6.387130 7.519458 5.643434 0.000000
24186 No description has been provided for this image Mahoutsukai Precure! 2 54717 TV [fantasy, action] 6.39 6.387130 7.519458 5.315576 0.991667
23754 No description has been provided for this image Bleach: Sennen Kessen-hen - Ketsubetsu-tan 53998 TV [fantasy, adventure, action] 6.39 6.387130 8.180449 5.271495 1.983333
16329 No description has been provided for this image Dragon Quest: Dai no Daibouken (2020) 40906 TV [fantasy, adventure, action] 7.74 7.643075 8.136377 4.895325 2.916667
24175 No description has been provided for this image Naruto (Shinsaku Anime) 54688 TV [fantasy, adventure, action] 6.39 6.387130 7.519458 4.881137 1.966667
22481 No description has been provided for this image Nanatsu no Taizai: Mokushiroku no Yonkishi 51794 TV [fantasy, adventure, action] 6.39 6.387130 7.519458 4.874748 1.983333
22788 No description has been provided for this image Shangri-La Frontier: Kusoge Hunter, Kamige ni Idoman to su 52347 TV [fantasy, adventure, action] 6.39 6.387130 7.519458 4.874384 1.983333
24185 No description has been provided for this image Kibou no Chikara: Otona Precure '23 54716 TV [fantasy, action] 6.39 6.387130 7.519458 4.873150 1.983333
24677 No description has been provided for this image Naruto (2023) 55453 TV [fantasy, adventure, comedy, action] 6.39 6.387130 7.519458 4.873135 1.983333
22235 No description has been provided for this image Orient: Awajishima Gekitou-hen 51368 TV [fantasy, adventure, action] 7.04 6.978657 7.047267 4.294314 2.850000
17060 No description has been provided for this image Heion Sedai no Idaten-tachi 42625 TV [fantasy, adventure, action] 7.64 7.609725 7.489363 4.237840 3.816667
18914 No description has been provided for this image Orient 45560 TV [fantasy, adventure, action] 6.60 6.590130 6.404930 3.925004 2.850000
10577 No description has been provided for this image Dragon Ball Super 30694 TV [fantasy, adventure, comedy, action] 7.43 7.426386 7.376076 3.838155 5.000000
14699 No description has been provided for this image One Piece Movie 14: Stampede 38234 Movie [fantasy, adventure, action] 8.22 8.190025 7.467511 3.665383 5.975000
16405 No description has been provided for this image Digimon Adventure: 41074 TV [fantasy, adventure, comedy, action] 6.42 6.416737 6.315851 3.652153 3.604167
8558 No description has been provided for this image Fairy Tail (2014) 22043 TV [fantasy, adventure, action] 7.65 7.645865 7.630431 3.640551 6.325000
13291 No description has been provided for this image Golden Kamuy 36028 TV [adventure, action] 7.87 7.852865 7.637980 3.581137 6.650000
13409 No description has been provided for this image One Piece: Episode of East Blue - Luffy to 4-nin no Nakama no Daibouken 36215 Special [fantasy, adventure, action] 7.88 7.758384 7.977352 3.454295 7.966667
10865 No description has been provided for this image Drifters 31339 TV [fantasy, adventure, comedy, action] 7.90 7.889898 8.058146 3.376119 8.550000
6018 No description has been provided for this image Toriko 10033 TV [adventure, action, gourmet, fantasy, comedy] 7.52 7.481460 7.320828 3.359241 7.000000
In [ ]:
class AnimeRecommender1:
    def __init__(self, anime_df, ratings_df, svd_model):
        self.nlp = spacy.load("en_core_web_sm")
        self.anime_df = anime_df.copy()
        self.ratings_df = ratings_df.copy()
        self.svd_model = svd_model
        self.current_year = datetime.now().year

        self._preprocess_data()
        self._create_feature_matrices()

        self.weights = {
            'genres': 0.30,
            'synopsis': 0.35,
            'type': 0.15,
            'studios': 0.10,
            'episodes': 0.05,
            'source': 0.05
        }

    def _preprocess_data(self):
        self.anime_df['Score'] = self.anime_df['Score'].replace('[^0-9.]', '', regex=True)
        self.anime_df['Scored By'] = self.anime_df['Scored By'].replace('[^0-9]', '', regex=True)
        self.anime_df['Score'] = pd.to_numeric(self.anime_df['Score'], errors='coerce')
        self.anime_df['Scored By'] = pd.to_numeric(self.anime_df['Scored By'], errors='coerce')
        self.anime_df['Score'].fillna(self.anime_df['Score'].median(), inplace=True)
        self.anime_df['Scored By'].fillna(self.anime_df['Scored By'].median(), inplace=True)
        self.anime_df['Release_year'] = self.anime_df['Aired'].str.extract(r'(\d{4})').astype(float)

        def normalize_genre_list(genre_string):
            if genre_string == 'UNKNOWN' or pd.isna(genre_string):
                return []
            genres = re.split(r',\s*', genre_string)
            return list(set([re.sub(r'[^\w\s]', '', g).strip().lower() for g in genres]))

        self.anime_df['Genres'] = self.anime_df['Genres'].apply(normalize_genre_list)
        self.anime_df['Studios'] = self.anime_df['Studios'].apply(normalize_genre_list)

        C = self.anime_df['Score'].mean()
        m = self.anime_df['Scored By'].quantile(0.65)
        self.anime_df['weighted_rating'] = (
            (self.anime_df['Scored By'] / (self.anime_df['Scored By'] + m)) * self.anime_df['Score'] +
            (m / (self.anime_df['Scored By'] + m)) * C
        )

    def _create_feature_matrices(self):
        self.mlb_genres = MultiLabelBinarizer(sparse_output=True)
        self.genres_encoded = self.mlb_genres.fit_transform(self.anime_df['Genres'])

        self.mlb_studios = MultiLabelBinarizer(sparse_output=True)
        self.studios_encoded = self.mlb_studios.fit_transform(self.anime_df['Studios'])

        self.ohe_type = OneHotEncoder(sparse_output=True)
        self.type_encoded = self.ohe_type.fit_transform(self.anime_df[['Type']])

        self.ohe_source = OneHotEncoder(sparse_output=True)
        self.source_encoded = self.ohe_source.fit_transform(self.anime_df[['Source']])

        self.anime_df['Episodes'] = pd.to_numeric(self.anime_df['Episodes'], errors='coerce')
        self.median_episodes = self.anime_df['Episodes'].median()
        self.anime_df['Episodes'].fillna(self.median_episodes, inplace=True)

        self.bins = [0, 1, 12, 24, 50, np.inf]
        self.labels = ['1', '2-12', '13-24', '25-50', '51+']
        self.anime_df['Episodes_Binned'] = pd.cut(self.anime_df['Episodes'], bins=self.bins, labels=self.labels)
        self.ohe_episodes = OneHotEncoder(sparse_output=True)
        self.episodes_encoded = self.ohe_episodes.fit_transform(self.anime_df[['Episodes_Binned']])

        self.anime_df['Synopsis'] = self._clean_text(self.anime_df['Synopsis'].fillna(''))
        self.tfidf = TfidfVectorizer(stop_words='english')
        self.synopsis_encoded = self.tfidf.fit_transform(self.anime_df['Synopsis'])

    def _clean_text(self, text_series):
        return text_series.apply(self._spacy_clean)

    def _spacy_clean(self, text):
        doc = self.nlp(text.lower())
        return ' '.join(token.lemma_ for token in doc if not token.is_stop and not token.is_punct and token.is_alpha)

    def _calculate_recency_boost(self, release_year):
        year = release_year if pd.notna(release_year) else self.anime_df['Release_year'].min()
        min_year = self.anime_df['Release_year'].min()
        max_year = self.anime_df['Release_year'].max()
        return (year - min_year) / (max_year - min_year) if max_year != min_year else 0

    def _calculate_anime_similarity(self, idx):
        genres_sim = cosine_similarity(self.genres_encoded[idx:idx+1], self.genres_encoded)[0]
        studios_sim = cosine_similarity(self.studios_encoded[idx:idx+1], self.studios_encoded)[0]
        synopsis_sim = cosine_similarity(self.synopsis_encoded[idx:idx+1], self.synopsis_encoded)[0]
        type_sim = (self.anime_df['Type'] == self.anime_df.iloc[idx]['Type']).astype(float).values
        source_sim = (self.anime_df['Source'] == self.anime_df.iloc[idx]['Source']).astype(float).values
        episodes_sim = (self.anime_df['Episodes_Binned'] == self.anime_df.iloc[idx]['Episodes_Binned']).astype(float).values

        combined_sim = (
            self.weights['genres'] * genres_sim +
            self.weights['synopsis'] * synopsis_sim +
            self.weights['type'] * type_sim +
            self.weights['studios'] * studios_sim +
            self.weights['episodes'] * episodes_sim +
            self.weights['source'] * source_sim
        )

        sim_scores = np.array(list(enumerate(combined_sim)))
        sorted_sim_scores = sim_scores[sim_scores[:, 1].argsort()[::-1]]
        top_sim = sorted_sim_scores[1:min(52, len(self.anime_df))]

        top_indices = top_sim[:, 0].astype(int)
        sim_scores_top = top_sim[:, 1]
        return sim_scores_top, top_indices

    def get_anime_recommendations1(self, title, user_id, n=10, similarity_weight=0.85, recency_weight=0.2, svd_weight=0.6):
        match = self.anime_df[self.anime_df['Name'] == title]
        if match.empty:
            raise ValueError(f"Anime '{title}' not found.")
        idx = match.index[0]

        sim_scores_top, top_indices = self._calculate_anime_similarity(idx)
        recs = self.anime_df.iloc[top_indices].copy()
        recs['similarity_score'] = sim_scores_top
        recs['recency_score'] = recs['Release_year'].apply(self._calculate_recency_boost)
        recs['end_year'] = recs['Release_year'].fillna(self.current_year)
        recs['episodes'] = pd.to_numeric(recs['Episodes'], errors='coerce').fillna(self.median_episodes)

        recs['age_penalty'] = recs.apply(
            lambda row: 0 if row['Status'] == 'Currently Airing' else
            (self.current_year - row['end_year']) * (1 - 0.5 * min(row['episodes'] / 120, 1)), axis=1
        )

        svd_preds = []
        for anime_id in recs['anime_id']:
            try:
                pred = self.svd_model.predict(user_id, anime_id).est
            except Exception:
                pred = self.svd_model.trainset.global_mean
            svd_preds.append(pred)

        recs['svd_pred'] = svd_preds
        rating_weight = max(0, 1 - similarity_weight)
        content_score = rating_weight * recs['weighted_rating'] + similarity_weight * recs['similarity_score']

        recs['final_score'] = (
            ((1 - svd_weight) * content_score + svd_weight * recs['svd_pred']) * (1 - recency_weight) +
            recency_weight * recs['recency_score']
        ) / (1 + recs['age_penalty'] / 10)

        return recs.sort_values('final_score', ascending=False).head(n)[
            ['Image URL', 'Name', 'anime_id', 'Type', 'Genres', 'Score', 'weighted_rating', 'svd_pred', 'final_score', 'age_penalty']
        ]
In [ ]:
recommender = AnimeRecommender1(anime_df, ratings_df,svd_model=SVD_model)
In [ ]:
df = recommender.get_anime_recommendations1(
    title='Fairy Tail: 100 Years Quest',
    user_id=1,
    n=24
)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating svd_pred final_score age_penalty
11 No description has been provided for this image One Piece 21 TV [fantasy, adventure, action] 8.69 8.686696 8.614288 4.854554 0.000000
21578 No description has been provided for this image Edens Zero 2nd Season 50002 TV [fantasy, adventure, scifi, action] 7.43 7.164798 7.302414 4.188849 0.000000
24174 No description has been provided for this image Boruto: Naruto Next Generations Part 2 54687 TV [fantasy, adventure, action] 6.39 6.387130 7.519458 4.065522 0.000000
24886 No description has been provided for this image Dekisokonai to Yobareta Motoeiyuu wa Jikka kara Tsuihou sareta node Sukikatte ni Ikiru Koto ni Shita 55717 TV [fantasy, adventure, action] 6.39 6.387130 7.519458 4.058088 0.000000
22406 No description has been provided for this image Nozomanu Fushi no Boukensha 51648 TV [fantasy, adventure, action] 6.39 6.387130 7.519458 4.056716 0.000000
23556 No description has been provided for this image Sokushi Cheat ga Saikyou sugite, Isekai no Yatsura ga Marude Aite ni Naranai n desu ga. 53730 TV [fantasy, adventure, action] 6.39 6.387130 7.519458 4.055115 0.000000
22758 No description has been provided for this image Ore dake Level Up na Ken 52299 TV [fantasy, adventure, action] 6.39 6.387130 7.519458 3.873439 0.991667
23754 No description has been provided for this image Bleach: Sennen Kessen-hen - Ketsubetsu-tan 53998 TV [fantasy, adventure, action] 6.39 6.387130 8.180449 3.821219 1.983333
24175 No description has been provided for this image Naruto (Shinsaku Anime) 54688 TV [fantasy, adventure, action] 6.39 6.387130 7.519458 3.563505 1.966667
16329 No description has been provided for this image Dragon Quest: Dai no Daibouken (2020) 40906 TV [fantasy, adventure, action] 7.74 7.643075 8.136377 3.563224 2.916667
22481 No description has been provided for this image Nanatsu no Taizai: Mokushiroku no Yonkishi 51794 TV [fantasy, adventure, action] 6.39 6.387130 7.519458 3.558762 1.983333
22788 No description has been provided for this image Shangri-La Frontier: Kusoge Hunter, Kamige ni Idoman to su 52347 TV [fantasy, adventure, action] 6.39 6.387130 7.519458 3.558162 1.983333
24677 No description has been provided for this image Naruto (2023) 55453 TV [fantasy, adventure, comedy, action] 6.39 6.387130 7.519458 3.550593 1.983333
22190 No description has been provided for this image Ragna Crimson 51297 TV [fantasy, action] 6.39 6.387130 7.519458 3.548639 1.983333
23432 No description has been provided for this image Boukensha ni Naritai to Miyako ni Deteitta Musume ga S-Rank ni Natteta 53494 TV [fantasy, adventure, action] 6.39 6.387130 7.519458 3.548144 1.983333
15568 No description has been provided for this image Tensei shitara Slime Datta Ken 2nd Season 39551 TV [fantasy, adventure, comedy, action] 8.39 8.382957 8.160297 3.371147 3.800000
16644 No description has been provided for this image Itai no wa Iya nanode Bougyoryoku ni Kyokufuri Shitai to Omoimasu. 2 41514 TV [fantasy, adventure, comedy, action] 7.21 7.182646 6.747344 3.294321 1.900000
16626 No description has been provided for this image Tensei shitara Slime Datta Ken 2nd Season Part 2 41487 TV [fantasy, adventure, comedy, action] 8.33 8.321181 7.845924 3.260111 3.800000
16095 No description has been provided for this image Arifureta Shokugyou de Sekai Saikyou 2nd Season 40507 TV [fantasy, adventure, action] 7.18 7.169850 7.147056 3.197214 2.850000
22235 No description has been provided for this image Orient: Awajishima Gekitou-hen 51368 TV [fantasy, adventure, action] 7.04 6.978657 7.047267 3.163184 2.850000
17060 No description has been provided for this image Heion Sedai no Idaten-tachi 42625 TV [fantasy, adventure, action] 7.64 7.609725 7.489363 3.117344 3.816667
17034 No description has been provided for this image Kaizoku Oujo 42544 TV [fantasy, adventure, action] 7.08 7.060602 7.377949 3.053535 3.800000
15554 No description has been provided for this image Kuutei Dragons 39531 TV [fantasy, adventure] 6.96 6.898991 7.957808 3.038907 4.750000
16630 No description has been provided for this image Nanatsu no Taizai: Funnu no Shinpan 41491 TV [fantasy, adventure, action] 6.58 6.578161 6.988408 2.946293 3.600000
In [ ]:
df = recommender.get_anime_recommendations1(
    title='Fairy Tail: 100 Years Quest',
    user_id=2,
    n=24
)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type Genres Score weighted_rating svd_pred final_score age_penalty
11 No description has been provided for this image One Piece 21 TV [fantasy, adventure, action] 8.69 8.686696 9.239926 5.154860 0.000000
21578 No description has been provided for this image Edens Zero 2nd Season 50002 TV [fantasy, adventure, scifi, action] 7.43 7.164798 7.746519 4.402019 0.000000
24174 No description has been provided for this image Boruto: Naruto Next Generations Part 2 54687 TV [fantasy, adventure, action] 6.39 6.387130 7.951687 4.272992 0.000000
24886 No description has been provided for this image Dekisokonai to Yobareta Motoeiyuu wa Jikka kara Tsuihou sareta node Sukikatte ni Ikiru Koto ni Shita 55717 TV [fantasy, adventure, action] 6.39 6.387130 7.951687 4.265558 0.000000
22406 No description has been provided for this image Nozomanu Fushi no Boukensha 51648 TV [fantasy, adventure, action] 6.39 6.387130 7.951687 4.264185 0.000000
23556 No description has been provided for this image Sokushi Cheat ga Saikyou sugite, Isekai no Yatsura ga Marude Aite ni Naranai n desu ga. 53730 TV [fantasy, adventure, action] 6.39 6.387130 7.951687 4.262585 0.000000
22758 No description has been provided for this image Ore dake Level Up na Ken 52299 TV [fantasy, adventure, action] 6.39 6.387130 7.951687 4.062191 0.991667
23754 No description has been provided for this image Bleach: Sennen Kessen-hen - Ketsubetsu-tan 53998 TV [fantasy, adventure, action] 6.39 6.387130 8.528788 3.960748 1.983333
24175 No description has been provided for this image Naruto (Shinsaku Anime) 54688 TV [fantasy, adventure, action] 6.39 6.387130 7.951687 3.736878 1.966667
22481 No description has been provided for this image Nanatsu no Taizai: Mokushiroku no Yonkishi 51794 TV [fantasy, adventure, action] 6.39 6.387130 7.951687 3.731894 1.983333
22788 No description has been provided for this image Shangri-La Frontier: Kusoge Hunter, Kamige ni Idoman to su 52347 TV [fantasy, adventure, action] 6.39 6.387130 7.951687 3.731294 1.983333
24677 No description has been provided for this image Naruto (2023) 55453 TV [fantasy, adventure, comedy, action] 6.39 6.387130 7.951687 3.723724 1.983333
22190 No description has been provided for this image Ragna Crimson 51297 TV [fantasy, action] 6.39 6.387130 7.951687 3.721771 1.983333
23432 No description has been provided for this image Boukensha ni Naritai to Miyako ni Deteitta Musume ga S-Rank ni Natteta 53494 TV [fantasy, adventure, action] 6.39 6.387130 7.951687 3.721275 1.983333
16329 No description has been provided for this image Dragon Quest: Dai no Daibouken (2020) 40906 TV [fantasy, adventure, action] 7.74 7.643075 8.212294 3.591435 2.916667
16644 No description has been provided for this image Itai no wa Iya nanode Bougyoryoku ni Kyokufuri Shitai to Omoimasu. 2 41514 TV [fantasy, adventure, comedy, action] 7.21 7.182646 7.376227 3.547988 1.900000
15568 No description has been provided for this image Tensei shitara Slime Datta Ken 2nd Season 39551 TV [fantasy, adventure, comedy, action] 8.39 8.382957 8.324226 3.428166 3.800000
16626 No description has been provided for this image Tensei shitara Slime Datta Ken 2nd Season Part 2 41487 TV [fantasy, adventure, comedy, action] 8.33 8.321181 8.293030 3.415627 3.800000
22235 No description has been provided for this image Orient: Awajishima Gekitou-hen 51368 TV [fantasy, adventure, action] 7.04 6.978657 7.495493 3.330615 2.850000
17060 No description has been provided for this image Heion Sedai no Idaten-tachi 42625 TV [fantasy, adventure, action] 7.64 7.609725 7.953487 3.278584 3.816667
16095 No description has been provided for this image Arifureta Shokugyou de Sekai Saikyou 2nd Season 40507 TV [fantasy, adventure, action] 7.18 7.169850 7.293229 3.251816 2.850000
15554 No description has been provided for this image Kuutei Dragons 39531 TV [fantasy, adventure] 6.96 6.898991 8.164820 3.106274 4.750000
21032 No description has been provided for this image Saihate no Paladin 48761 TV [fantasy, adventure, action] 6.84 6.833423 7.528400 3.096776 3.800000
17034 No description has been provided for this image Kaizoku Oujo 42544 TV [fantasy, adventure, action] 7.08 7.060602 7.421295 3.068612 3.800000
In [ ]:
class AnimeRecommender1:
    def __init__(self, anime_df, ratings_df, svd_model):
        self.nlp = spacy.load("en_core_web_sm")
        self.anime_df = anime_df.copy()
        self.ratings_df = ratings_df.copy()
        self.svd_model = svd_model
        self.current_year = datetime.now().year

        self._preprocess_data()
        self._create_feature_matrices()

        self.weights = {
            'genres': 0.30,
            'synopsis': 0.35,
            'type': 0.15,
            'studios': 0.10,
            'episodes': 0.05,
            'source': 0.05
        }

    def _preprocess_data(self):
        self.anime_df['Score'] = self.anime_df['Score'].replace('[^0-9.]', '', regex=True)
        self.anime_df['Scored By'] = self.anime_df['Scored By'].replace('[^0-9]', '', regex=True)
        self.anime_df['Score'] = pd.to_numeric(self.anime_df['Score'], errors='coerce')
        self.anime_df['Scored By'] = pd.to_numeric(self.anime_df['Scored By'], errors='coerce')
        self.anime_df['Score'].fillna(self.anime_df['Score'].median(), inplace=True)
        self.anime_df['Scored By'].fillna(self.anime_df['Scored By'].median(), inplace=True)
        self.anime_df['Release_year'] = self.anime_df['Aired'].str.extract(r'(\d{4})').astype(float)

        def normalize_genre_list(genre_string):
            if genre_string == 'UNKNOWN' or pd.isna(genre_string):
                return []
            genres = re.split(r',\s*', genre_string)
            return list(set([re.sub(r'[^\w\s]', '', g).strip().lower() for g in genres]))

        self.anime_df['Genres'] = self.anime_df['Genres'].apply(normalize_genre_list)
        self.anime_df['Studios'] = self.anime_df['Studios'].apply(normalize_genre_list)

        C = self.anime_df['Score'].mean()
        m = self.anime_df['Scored By'].quantile(0.65)
        self.anime_df['weighted_rating'] = (
            (self.anime_df['Scored By'] / (self.anime_df['Scored By'] + m)) * self.anime_df['Score'] +
            (m / (self.anime_df['Scored By'] + m)) * C
        )

    def _create_feature_matrices(self):
        self.mlb_genres = MultiLabelBinarizer(sparse_output=True)
        self.genres_encoded = self.mlb_genres.fit_transform(self.anime_df['Genres'])

        self.mlb_studios = MultiLabelBinarizer(sparse_output=True)
        self.studios_encoded = self.mlb_studios.fit_transform(self.anime_df['Studios'])

        self.ohe_type = OneHotEncoder(sparse_output=True)
        self.type_encoded = self.ohe_type.fit_transform(self.anime_df[['Type']])

        self.ohe_source = OneHotEncoder(sparse_output=True)
        self.source_encoded = self.ohe_source.fit_transform(self.anime_df[['Source']])

        self.anime_df['Episodes'] = pd.to_numeric(self.anime_df['Episodes'], errors='coerce')
        self.median_episodes = self.anime_df['Episodes'].median()
        self.anime_df['Episodes'].fillna(self.median_episodes, inplace=True)

        self.bins = [0, 1, 12, 24, 50, np.inf]
        self.labels = ['1', '2-12', '13-24', '25-50', '51+']
        self.anime_df['Episodes_Binned'] = pd.cut(self.anime_df['Episodes'], bins=self.bins, labels=self.labels)
        self.ohe_episodes = OneHotEncoder(sparse_output=True)
        self.episodes_encoded = self.ohe_episodes.fit_transform(self.anime_df[['Episodes_Binned']])

        self.anime_df['Synopsis'] = self._clean_text(self.anime_df['Synopsis'].fillna(''))
        self.tfidf = TfidfVectorizer(stop_words='english')
        self.synopsis_encoded = self.tfidf.fit_transform(self.anime_df['Synopsis'])

    def _clean_text(self, text_series):
        return text_series.apply(self._spacy_clean)

    def _spacy_clean(self, text):
        doc = self.nlp(text.lower())
        return ' '.join(token.lemma_ for token in doc if not token.is_stop and not token.is_punct and token.is_alpha)

    def _calculate_recency_boost(self, release_year):
        year = release_year if pd.notna(release_year) else self.anime_df['Release_year'].min()
        min_year = self.anime_df['Release_year'].min()
        max_year = self.anime_df['Release_year'].max()
        return (year - min_year) / (max_year - min_year) if max_year != min_year else 0

    def _calculate_anime_similarity(self, idx):
        genres_sim = cosine_similarity(self.genres_encoded[idx:idx+1], self.genres_encoded)[0]
        studios_sim = cosine_similarity(self.studios_encoded[idx:idx+1], self.studios_encoded)[0]
        synopsis_sim = cosine_similarity(self.synopsis_encoded[idx:idx+1], self.synopsis_encoded)[0]
        type_sim = (self.anime_df['Type'] == self.anime_df.iloc[idx]['Type']).astype(float).values
        source_sim = (self.anime_df['Source'] == self.anime_df.iloc[idx]['Source']).astype(float).values
        episodes_sim = (self.anime_df['Episodes_Binned'] == self.anime_df.iloc[idx]['Episodes_Binned']).astype(float).values

        combined_sim = (
            self.weights['genres'] * genres_sim +
            self.weights['synopsis'] * synopsis_sim +
            self.weights['type'] * type_sim +
            self.weights['studios'] * studios_sim +
            self.weights['episodes'] * episodes_sim +
            self.weights['source'] * source_sim
        )

        sim_scores = np.array(list(enumerate(combined_sim)))
        sorted_sim_scores = sim_scores[sim_scores[:, 1].argsort()[::-1]]
        top_sim = sorted_sim_scores[1:min(52, len(self.anime_df))]

        top_indices = top_sim[:, 0].astype(int)
        sim_scores_top = top_sim[:, 1]
        return sim_scores_top, top_indices

    def get_anime_recommendations1(self, title, user_id, n=10, similarity_weight=0.85, recency_weight=0.2):
        match = self.anime_df[self.anime_df['Name'] == title]
        if match.empty:
            raise ValueError(f"Anime '{title}' not found.")
        idx = match.index[0]

        sim_scores_top, top_indices = self._calculate_anime_similarity(idx)
        recs = self.anime_df.iloc[top_indices].copy()
        recs['similarity_score'] = sim_scores_top
        recs['recency_score'] = recs['Release_year'].apply(self._calculate_recency_boost)
        recs['end_year'] = recs['Release_year'].fillna(self.current_year)
        recs['episodes'] = pd.to_numeric(recs['Episodes'], errors='coerce').fillna(self.median_episodes)

        recs['age_penalty'] = recs.apply(
            lambda row: 0 if row['Status'] == 'Currently Airing' else
            (self.current_year - row['end_year']) * (1 - 0.5 * min(row['episodes'] / 120, 1)), axis=1
        )

        if user_id not in set(self.ratings_df['user_id']):
            # Cold-start fallback: no SVD available, use content-based only
            content_score = (
                (1 - similarity_weight) * recs['weighted_rating'] + similarity_weight * recs['similarity_score']
            )
            recs['final_score'] = (
                content_score * (1 - recency_weight) + recs['recency_score'] * recency_weight
            ) / (1 + recs['age_penalty'] / 10)
            recs['svd_pred'] = np.nan
        else:
            svd_preds = []
            for anime_id in recs['anime_id']:
                try:
                    pred = self.svd_model.predict(user_id, anime_id).est
                except Exception:
                    pred = self.svd_model.trainset.global_mean
                svd_preds.append(pred)

            user_rating_count = self.ratings_df[self.ratings_df['user_id'] == user_id].shape[0]
            if user_rating_count < 10:
              svd_weight = 0.5
            elif user_rating_count < 50:
              svd_weight = 0.6
            else:
              svd_weight = 0.7

            recs['svd_pred'] = svd_preds
            rating_weight = max(0, 1 - similarity_weight)
            content_score = rating_weight * recs['weighted_rating'] + similarity_weight * recs['similarity_score']

            recs['final_score'] = (
                ((1 - svd_weight) * content_score + svd_weight * recs['svd_pred']) * (1 - recency_weight) +
                recency_weight * recs['recency_score']
            ) / (1 + recs['age_penalty'] / 10)

        return recs.sort_values('final_score', ascending=False).head(n)[
            ['Image URL', 'Name', 'anime_id', 'Type', 'svd_pred', 'final_score']
        ]
    def get_recommendations_by_genres_simple(self, genres, n=10):
      if isinstance(genres, str):
        genres = [genres]

      input_genres = {g.strip().lower() for g in genres}
      if not input_genres:
        raise ValueError("No valid genres provided.")

      # Normalize genres per anime
      genre_sets = self.anime_df['Genres'].apply(lambda g_list: {g.strip().lower() for g in g_list})
      self.anime_df['has_all_genres'] = genre_sets.apply(
        lambda anime_genres: input_genres.issubset(anime_genres)
      )

      recommendations = self.anime_df[self.anime_df['has_all_genres']].copy()
      current_year = self.current_year

      recommendations['end_year'] = recommendations['Release_year'].fillna(current_year)
      recommendations['episodes'] = pd.to_numeric(recommendations['Episodes'], errors='coerce').fillna(self.median_episodes)

      # 🔥 Stronger age penalty
      recommendations['age_penalty'] = recommendations.apply(
        lambda row: 0 if row['Status'] == 'Currently Airing' else
        (current_year - row['end_year']) * (1 - 0.5 * min(row['episodes'] / 120, 1)),
        axis=1
    )

      recommendations = recommendations.sort_values(
        by=['weighted_rating', 'age_penalty'], ascending=[False, True]
        ).head(n)
      return recommendations[['Image URL', 'Name', 'Genres', 'weighted_rating', 'age_penalty']]
In [ ]:
anime_df = pd.read_csv('/content/drive/MyDrive/Anime Recommender System/anime_filtered.csv')
recommender = AnimeRecommender1(anime_df, ratings_df, svd_model=SVD_model)
In [ ]:
df = recommender.get_anime_recommendations1(
    title='Kimetsu no Yaiba: Yuukaku-hen',
    user_id=1,
    n=24
)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type svd_pred final_score
23543 No description has been provided for this image Hirogaru Sky! Precure 53716 TV 7.775836 4.904126
21905 No description has been provided for this image Yu☆Gi☆Oh! Go Rush!! 50607 TV 7.334715 4.626674
24875 No description has been provided for this image Kimetsu no Yaiba: Hashira Geiko-hen 55701 TV 7.519458 4.573433
23669 No description has been provided for this image Ao no Exorcist (Shin Series) 53889 TV 7.519458 4.553033
22048 No description has been provided for this image Kimetsu no Yaiba: Katanakaji no Sato-hen 51019 TV 8.193908 4.399936
21793 No description has been provided for this image Mato Seihei no Slave 50392 TV 7.519458 4.319778
20893 No description has been provided for this image Maou Gakuin no Futekigousha: Shijou Saikyou no Maou no Shiso, Tensei shite Shison-tachi no Gakkou e Kayou II 48417 TV 6.535789 4.212508
22042 No description has been provided for this image Jujutsu Kaisen 2nd Season 51009 TV 7.853121 4.119205
18172 No description has been provided for this image Chainsaw Man 44511 TV 8.046383 3.986269
22190 No description has been provided for this image Ragna Crimson 51297 TV 7.519458 3.963279
23417 No description has been provided for this image Boushoku no Berserk 53439 TV 7.519458 3.955846
24265 No description has been provided for this image Kikansha no Mahou wa Tokubetsu desu 54852 TV 7.519458 3.955463
22049 No description has been provided for this image Helck 51020 TV 7.421664 3.915582
22748 No description has been provided for this image Nokemono-tachi no Yoru 52274 TV 7.093905 3.790933
21207 No description has been provided for this image High Card 49154 TV 7.034771 3.776708
21533 No description has been provided for this image Kimetsu no Yaiba: Mugen Ressha-hen 49926 TV 8.047120 3.716786
21515 No description has been provided for this image Tensei shitara Ken deshita 49891 TV 7.288049 3.618903
22235 No description has been provided for this image Orient: Awajishima Gekitou-hen 51368 TV 7.047267 3.499370
17060 No description has been provided for this image Heion Sedai no Idaten-tachi 42625 TV 7.489363 3.450843
20904 No description has been provided for this image The Legend of Heroes: Sen no Kiseki - Northern War 48441 TV 6.423645 3.450117
14539 No description has been provided for this image Kimetsu no Yaiba 38000 TV 8.049135 3.342700
21031 No description has been provided for this image Gaikotsu Kishi-sama, Tadaima Isekai e Odekakechuu 48760 TV 6.608047 3.312190
16060 No description has been provided for this image Kimetsu no Yaiba Movie: Mugen Ressha-hen 40456 Movie 7.743131 3.304943
18914 No description has been provided for this image Orient 45560 TV 6.404930 3.209440
In [ ]:
df = recommender.get_anime_recommendations1(
    title='Kimetsu no Yaiba: Yuukaku-hen',
    user_id=4,
    n=24
)
df
# df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

# display(HTML(df.to_html(escape=False)))
Out[ ]:
Image URL Name anime_id Type svd_pred final_score
23543 https://cdn.myanimelist.net/images/anime/1762/... Hirogaru Sky! Precure 53716 TV 7.597894 4.805134
21905 https://cdn.myanimelist.net/images/anime/1624/... Yu☆Gi☆Oh! Go Rush!! 50607 TV 7.136368 4.515923
24875 https://cdn.myanimelist.net/images/anime/1230/... Kimetsu no Yaiba: Hashira Geiko-hen 55701 TV 7.079678 4.327156
23669 https://cdn.myanimelist.net/images/anime/1187/... Ao no Exorcist (Shin Series) 53889 TV 7.079678 4.306756
21685 https://cdn.myanimelist.net/images/anime/1926/... Seiken Gakuin no Makentsukai 50184 TV 7.079678 4.297561
21793 https://cdn.myanimelist.net/images/anime/1406/... Mato Seihei no Slave 50392 TV 7.079678 4.097866
22048 https://cdn.myanimelist.net/images/anime/1765/... Kimetsu no Yaiba: Katanakaji no Sato-hen 51019 TV 7.531537 4.092264
22042 https://cdn.myanimelist.net/images/anime/1600/... Jujutsu Kaisen 2nd Season 51009 TV 7.485360 3.947345
18172 https://cdn.myanimelist.net/images/anime/1806/... Chainsaw Man 44511 TV 7.947433 3.943268
20893 https://cdn.myanimelist.net/images/anime/1475/... Maou Gakuin no Futekigousha: Shijou Saikyou no... 48417 TV 5.865756 3.838076
22190 https://cdn.myanimelist.net/images/anime/1702/... Ragna Crimson 51297 TV 7.079678 3.757763
23417 https://cdn.myanimelist.net/images/anime/1801/... Boushoku no Berserk 53439 TV 7.079678 3.750914
24265 https://cdn.myanimelist.net/images/anime/1630/... Kikansha no Mahou wa Tokubetsu desu 54852 TV 7.079678 3.750230
22049 https://cdn.myanimelist.net/images/anime/1879/... Helck 51020 TV 7.062594 3.749607
22748 https://cdn.myanimelist.net/images/anime/1087/... Nokemono-tachi no Yoru 52274 TV 6.824937 3.664806
21207 https://cdn.myanimelist.net/images/anime/1803/... High Card 49154 TV 6.672107 3.606303
21533 https://cdn.myanimelist.net/images/anime/1065/... Kimetsu no Yaiba: Mugen Ressha-hen 49926 TV 7.760512 3.601069
21515 https://cdn.myanimelist.net/images/anime/1191/... Tensei shitara Ken deshita 49891 TV 6.736706 3.379105
22235 https://cdn.myanimelist.net/images/anime/1085/... Orient: Awajishima Gekitou-hen 51368 TV 6.756744 3.373771
17060 https://cdn.myanimelist.net/images/anime/1293/... Heion Sedai no Idaten-tachi 42625 TV 7.155274 3.316798
21031 https://cdn.myanimelist.net/images/anime/1361/... Gaikotsu Kishi-sama, Tadaima Isekai e Odekakechuu 48760 TV 6.526765 3.277065
16060 https://cdn.myanimelist.net/images/anime/1704/... Kimetsu no Yaiba Movie: Mugen Ressha-hen 40456 Movie 7.647820 3.269365
20904 https://cdn.myanimelist.net/images/anime/1894/... The Legend of Heroes: Sen no Kiseki - Northern... 48441 TV 5.901256 3.204889
14539 https://cdn.myanimelist.net/images/anime/1286/... Kimetsu no Yaiba 38000 TV 7.660849 3.202840
In [ ]:
df = recommender.get_anime_recommendations1(
    title='Kimetsu no Yaiba: Yuukaku-hen',
    user_id=499999999,
    n=24
)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type svd_pred final_score
22048 No description has been provided for this image Kimetsu no Yaiba: Katanakaji no Sato-hen 51019 TV NaN 1.437633
20893 No description has been provided for this image Maou Gakuin no Futekigousha: Shijou Saikyou no Maou no Shiso, Tensei shite Shison-tachi no Gakkou e Kayou II 48417 TV NaN 1.383529
23543 No description has been provided for this image Hirogaru Sky! Precure 53716 TV NaN 1.374168
21905 No description has been provided for this image Yu☆Gi☆Oh! Go Rush!! 50607 TV NaN 1.277073
21533 No description has been provided for this image Kimetsu no Yaiba: Mugen Ressha-hen 49926 TV NaN 1.245945
18172 No description has been provided for this image Chainsaw Man 44511 TV NaN 1.245837
21793 No description has been provided for this image Mato Seihei no Slave 50392 TV NaN 1.208660
24875 No description has been provided for this image Kimetsu no Yaiba: Hashira Geiko-hen 55701 TV NaN 1.208456
21207 No description has been provided for this image High Card 49154 TV NaN 1.169196
23669 No description has been provided for this image Ao no Exorcist (Shin Series) 53889 TV NaN 1.140456
21515 No description has been provided for this image Tensei shitara Ken deshita 49891 TV NaN 1.122883
22748 No description has been provided for this image Nokemono-tachi no Yoru 52274 TV NaN 1.115787
22190 No description has been provided for this image Ragna Crimson 51297 TV NaN 1.115509
22042 No description has been provided for this image Jujutsu Kaisen 2nd Season 51009 TV NaN 1.115509
22049 No description has been provided for this image Helck 51020 TV NaN 1.108854
22436 No description has been provided for this image Hyouken no Majutsushi ga Sekai wo Suberu 51711 TV NaN 1.095980
23417 No description has been provided for this image Boushoku no Berserk 53439 TV NaN 1.090731
24265 No description has been provided for this image Kikansha no Mahou wa Tokubetsu desu 54852 TV NaN 1.089456
21031 No description has been provided for this image Gaikotsu Kishi-sama, Tadaima Isekai e Odekakechuu 48760 TV NaN 1.088318
22235 No description has been provided for this image Orient: Awajishima Gekitou-hen 51368 TV NaN 1.074215
16060 No description has been provided for this image Kimetsu no Yaiba Movie: Mugen Ressha-hen 40456 Movie NaN 1.070059
14539 No description has been provided for this image Kimetsu no Yaiba 38000 TV NaN 1.066900
17060 No description has been provided for this image Heion Sedai no Idaten-tachi 42625 TV NaN 1.059244
18914 No description has been provided for this image Orient 45560 TV NaN 1.040878
In [ ]:
df = recommender.get_recommendations_by_genres_simple([ 'scifi','action']	, n=50)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name Genres weighted_rating age_penalty
9880 No description has been provided for this image Gintama° [scifi, comedy, action] 9.040355 12.481034
5989 No description has been provided for this image Gintama' [scifi, comedy, action] 9.019494 18.689781
7240 No description has been provided for this image Gintama': Enchousen [scifi, comedy, action] 9.000788 20.537456
15525 No description has been provided for this image Gintama: The Final [drama, comedy, action, scifi] 8.968517 5.256040
12179 No description has been provided for this image Gintama. [scifi, comedy, action] 8.947376 11.519446
833 No description has been provided for this image Gintama [scifi, comedy, action] 8.928261 17.118840
2647 No description has been provided for this image Code Geass: Hangyaku no Lelouch R2 [drama, award winning, scifi, action] 8.906124 26.838975
7228 No description has been provided for this image Gintama Movie 2: Kanketsu-hen - Yorozuya yo Eien Nare [scifi, comedy, action] 8.876192 19.642834
14206 No description has been provided for this image Gintama.: Shirogane no Tamashii-hen - Kouhan-sen [scifi, comedy, action] 8.831842 9.727805
13818 No description has been provided for this image Gintama.: Shirogane no Tamashii-hen [scifi, comedy, action] 8.767080 9.813892
0 No description has been provided for this image Cowboy Bebop [award winning, scifi, action] 8.745454 46.541358
1431 No description has been provided for this image Code Geass: Hangyaku no Lelouch [drama, award winning, scifi, action] 8.696970 30.671254
20964 No description has been provided for this image 86 Part 2 [drama, scifi, action] 8.692836 5.014130
1822 No description has been provided for this image Tengen Toppa Gurren Lagann [scifi, adventure, award winning, action] 8.625455 28.477074
16931 No description has been provided for this image Cyberpunk: Edgerunners [scifi, action] 8.600006 3.581476
3271 No description has been provided for this image Evangelion: 3.0+1.0 Thrice Upon a Time [suspense, scifi, award winning, action, drama] 8.582592 5.256040
3711 No description has been provided for this image Tengen Toppa Gurren Lagann Movie 2: Lagann-hen [scifi, action] 8.531098 27.741545
728 No description has been provided for this image Koukaku Kidoutai: Stand Alone Complex 2nd GIG [scifi, action, mystery] 8.483671 34.424345
13213 No description has been provided for this image Gintama.: Porori-hen [scifi, comedy, action] 8.481844 11.468922
5008 No description has been provided for this image Gintama Movie 1: Shinyaku Benizakura-hen [scifi, comedy, action] 8.479563 25.674156
438 No description has been provided for this image Koukaku Kidoutai: Stand Alone Complex [award winning, scifi, action] 8.397903 38.395112
19267 No description has been provided for this image Vivy: Fluorite Eye's Song [suspense, scifi, action] 8.394183 4.992138
1 No description has been provided for this image Cowboy Bebop: Tengoku no Tobira [scifi, action] 8.363114 45.127383
20 No description has been provided for this image Neon Genesis Evangelion [avant garde, suspense, scifi, award winning, action, drama] 8.346630 52.813875
8677 No description has been provided for this image Kiseijuu: Sei no Kakuritsu [horror, scifi, action] 8.336886 15.992403
6993 No description has been provided for this image Psycho-Pass [suspense, scifi, action, mystery] 8.335466 19.723195
3269 No description has been provided for this image Evangelion: 2.0 You Can (Not) Advance [drama, scifi, action] 8.299379 27.741545
16608 No description has been provided for this image 86 [drama, scifi, action] 8.270491 5.036122
4677 No description has been provided for this image Redline [scifi, action] 8.262984 27.741545
24 No description has been provided for this image Koukaku Kidoutai [suspense, scifi, award winning, action, mystery] 8.259542 58.983721
4817 No description has been provided for this image Gintama: Shiroyasha Koutan [scifi, comedy, action] 8.251004 29.834953
6654 No description has been provided for this image Uchuu Senkan Yamato 2199 [drama, scifi, action] 8.242538 19.361302
8526 No description has been provided for this image Gintama: Yorinuki Gintama-san on Theater 2D [scifi, comedy, action] 8.229437 21.532663
6424 No description has been provided for this image Kidou Senshi Gundam: The Origin [scifi, action] 8.216677 15.452709
2 No description has been provided for this image Trigun [adventure, scifi, action] 8.210988 46.541358
11631 No description has been provided for this image Kidou Senshi Gundam: Tekketsu no Orphans 2nd Season [drama, scifi, action] 8.188491 12.511755
18480 No description has been provided for this image World Trigger 3rd Season [scifi, action] 8.187516 4.970146
28 No description has been provided for this image Akira [adventure, supernatural, scifi, horror, action] 8.153587 75.862776
14835 No description has been provided for this image Toaru Kagaku no Railgun T [fantasy, scifi, action] 8.134640 6.180039
5862 No description has been provided for this image Gintama: Shinyaku Benizakura-hen [scifi, comedy, action] 8.125551 25.674156
2368 No description has been provided for this image Kidou Senshi Gundam 00 [drama, scifi, action] 8.084751 28.744465
1845 No description has been provided for this image Darker than Black: Kuro no Keiyakusha [scifi, action, mystery] 8.053130 28.744465
3375 No description has been provided for this image Kidou Senshi Gundam 00 Second Season [drama, scifi, action] 8.048096 26.838975
4547 No description has been provided for this image Kidou Senshi Gundam Unicorn [drama, scifi, action] 8.039891 25.029616
10831 No description has been provided for this image Kidou Senshi Gundam: Tekketsu no Orphans [drama, scifi, action] 8.025321 14.198002
203 No description has been provided for this image FLCL [avant garde, scifi, comedy, action] 8.023111 46.401565
7354 No description has been provided for this image Toaru Kagaku no Railgun S [fantasy, scifi, action] 8.005639 17.752520
16330 No description has been provided for this image World Trigger 2nd Season [scifi, action] 8.005060 5.014130
2532 No description has been provided for this image Evangelion: 1.0 You Are (Not) Alone [drama, award winning, scifi, action] 7.991460 31.953149
23296 No description has been provided for this image Kidou Senshi Gundam: Suisei no Majo Season 2 [scifi, action] 7.985896 0.000000
In [ ]:
import os
import joblib
import spacy
import pandas as pd
import numpy as np
from sklearn.preprocessing import MultiLabelBinarizer, OneHotEncoder
from sklearn.feature_extraction.text import TfidfVectorizer
from scipy.sparse import load_npz, save_npz
from datetime import datetime

class AnimeRecommender1:
    def __init__(self, ratings_df, svd_model, raw_anime_csv="/content/drive/MyDrive/Anime Recommender System/anime-dataset-2023.csv",
                 cache_dir="/content/drive/MyDrive/Anime Recommender System/cache"):
        self.nlp = spacy.load("en_core_web_sm", disable=["parser", "ner"])
        self.ratings_df = ratings_df.copy()
        self.svd_model = svd_model
        self.current_year = datetime.now().year
        self.cache_dir = cache_dir
        self.raw_anime_csv = raw_anime_csv

        os.makedirs(cache_dir, exist_ok=True)
        self._ensure_cache()

        self.weights = {
            'genres': 0.30,
            'synopsis': 0.35,
            'type': 0.15,
            'studios': 0.10,
            'episodes': 0.05,
            'source': 0.05
        }

    def _ensure_cache(self):
        cd = self.cache_dir
        cache_files = [
            "anime_df_cleaned.pkl", "tfidf_matrix.npz", "tfidf_vocab.pkl",
            "genres_encoded.npz", "studios_encoded.npz", "type_encoded.npz",
            "source_encoded.npz", "episodes_encoded.npz"
        ]
        all_exist = all(os.path.exists(os.path.join(cd, f)) for f in cache_files)
        if not all_exist:
            print("🛠️ Generating and caching features (first run)...")
            self._generate_and_cache_all()
        else:
            print("🔁 Loading cached anime data and feature matrices...")
        self._load_cached_data()

    def _generate_and_cache_all(self):
        cd = self.cache_dir
        anime_df = pd.read_csv(self.raw_anime_csv)

        def fast_normalize(col):
            return col.fillna('').str.lower().str.replace(r'[^\w\s,]', '', regex=True).str.split(',\s*')

        anime_df['Score'] = pd.to_numeric(anime_df['Score'].str.replace('[^0-9.]', '', regex=True), errors='coerce')
        anime_df['Scored By'] = pd.to_numeric(anime_df['Scored By'].str.replace('[^0-9]', '', regex=True), errors='coerce')
        anime_df['Score'].fillna(anime_df['Score'].median(), inplace=True)
        anime_df['Scored By'].fillna(anime_df['Scored By'].median(), inplace=True)
        anime_df['Release_year'] = pd.to_numeric(anime_df['Aired'].str.extract(r'(\d{4})')[0], errors='coerce')

        anime_df['Genres'] = fast_normalize(anime_df['Genres']).apply(lambda lst: list(set([g.strip() for g in lst if g != ''])))
        anime_df['Studios'] = fast_normalize(anime_df['Studios']).apply(lambda lst: list(set([g.strip() for g in lst if g != ''])))

        C = anime_df['Score'].mean()
        m = anime_df['Scored By'].quantile(0.65)
        anime_df['weighted_rating'] = ((anime_df['Scored By'] / (anime_df['Scored By'] + m)) * anime_df['Score'] +
                                       (m / (anime_df['Scored By'] + m)) * C)

        mlb_genres = MultiLabelBinarizer(sparse_output=True)
        genres_encoded = mlb_genres.fit_transform(anime_df['Genres'])
        save_npz(os.path.join(cd, "genres_encoded.npz"), genres_encoded)

        mlb_studios = MultiLabelBinarizer(sparse_output=True)
        studios_encoded = mlb_studios.fit_transform(anime_df['Studios'])
        save_npz(os.path.join(cd, "studios_encoded.npz"), studios_encoded)

        ohe_type = OneHotEncoder(sparse_output=True)
        type_encoded = ohe_type.fit_transform(anime_df[['Type']])
        save_npz(os.path.join(cd, "type_encoded.npz"), type_encoded)

        ohe_source = OneHotEncoder(sparse_output=True)
        source_encoded = ohe_source.fit_transform(anime_df[['Source']])
        save_npz(os.path.join(cd, "source_encoded.npz"), source_encoded)

        anime_df['Episodes'] = pd.to_numeric(anime_df['Episodes'], errors='coerce')
        median_episodes = anime_df['Episodes'].median()
        anime_df['Episodes'].fillna(median_episodes, inplace=True)

        bins = [0, 1, 12, 24, 50, np.inf]
        labels = ['1', '2-12', '13-24', '25-50', '51+']
        anime_df['Episodes_Binned'] = pd.cut(anime_df['Episodes'], bins=bins, labels=labels)

        ohe_episodes = OneHotEncoder(sparse_output=True)
        episodes_encoded = ohe_episodes.fit_transform(anime_df[['Episodes_Binned']])
        save_npz(os.path.join(cd, "episodes_encoded.npz"), episodes_encoded)

        anime_df['Synopsis'] = anime_df['Synopsis'].fillna('')
        anime_df['cleaned_synopsis'] = self._parallel_clean(anime_df['Synopsis'])
        joblib.dump(anime_df['cleaned_synopsis'], os.path.join(cd, "synopsis_cleaned.pkl"))

        tfidf = TfidfVectorizer(stop_words='english', max_features=10000)
        tfidf_matrix = tfidf.fit_transform(anime_df['cleaned_synopsis'])
        save_npz(os.path.join(cd, "tfidf_matrix.npz"), tfidf_matrix)
        joblib.dump(tfidf.vocabulary_, os.path.join(cd, "tfidf_vocab.pkl"))
        joblib.dump(anime_df, os.path.join(cd, "anime_df_cleaned.pkl"))
        print("✅ All preprocessing completed and cached.")

    def _parallel_clean(self, texts):
        docs = list(self.nlp.pipe(texts, batch_size=64))
        return [
            ' '.join(token.lemma_ for token in doc if token.is_alpha and not token.is_stop and not token.is_punct)
            for doc in docs
        ]

    def _load_cached_data(self):
        cd = self.cache_dir
        self.anime_df = joblib.load(os.path.join(cd, "anime_df_cleaned.pkl"))
        self.synopsis_encoded = load_npz(os.path.join(cd, "tfidf_matrix.npz"))
        self.tfidf_vocab = joblib.load(os.path.join(cd, "tfidf_vocab.pkl"))
        self.genres_encoded = load_npz(os.path.join(cd, "genres_encoded.npz"))
        self.studios_encoded = load_npz(os.path.join(cd, "studios_encoded.npz"))
        self.type_encoded = load_npz(os.path.join(cd, "type_encoded.npz"))
        self.source_encoded = load_npz(os.path.join(cd, "source_encoded.npz"))
        self.episodes_encoded = load_npz(os.path.join(cd, "episodes_encoded.npz"))
        self.median_episodes = self.anime_df['Episodes'].median()
        print("✅ All cached data loaded successfully.")

    def _calculate_recency_boost(self, release_year):
        year = release_year if pd.notna(release_year) else self.anime_df['Release_year'].min()
        min_year = self.anime_df['Release_year'].min()
        max_year = self.anime_df['Release_year'].max()
        return (year - min_year) / (max_year - min_year) if max_year != min_year else 0

    def _calculate_anime_similarity(self, idx):
        from sklearn.metrics.pairwise import cosine_similarity

        genres_sim = cosine_similarity(self.genres_encoded[idx:idx+1], self.genres_encoded)[0]
        studios_sim = cosine_similarity(self.studios_encoded[idx:idx+1], self.studios_encoded)[0]
        synopsis_sim = cosine_similarity(self.synopsis_encoded[idx:idx+1], self.synopsis_encoded)[0]
        type_sim = (self.anime_df['Type'] == self.anime_df.iloc[idx]['Type']).astype(float).values
        source_sim = (self.anime_df['Source'] == self.anime_df.iloc[idx]['Source']).astype(float).values
        episodes_sim = (self.anime_df['Episodes_Binned'] == self.anime_df.iloc[idx]['Episodes_Binned']).astype(float).values

        combined_sim = (
            self.weights['genres'] * genres_sim +
            self.weights['synopsis'] * synopsis_sim +
            self.weights['type'] * type_sim +
            self.weights['studios'] * studios_sim +
            self.weights['episodes'] * episodes_sim +
            self.weights['source'] * source_sim
        )

        sim_scores = np.array(list(enumerate(combined_sim)))
        sorted_sim_scores = sim_scores[sim_scores[:, 1].argsort()[::-1]]
        top_sim = sorted_sim_scores[1:min(52, len(self.anime_df))]

        top_indices = top_sim[:, 0].astype(int)
        sim_scores_top = top_sim[:, 1]
        return sim_scores_top, top_indices

    def get_anime_recommendations1(self, title, user_id, n=10, similarity_weight=0.85, recency_weight=0.2):
        match = self.anime_df[self.anime_df['Name'] == title]
        if match.empty:
            raise ValueError(f"Anime '{title}' not found.")
        idx = match.index[0]

        sim_scores_top, top_indices = self._calculate_anime_similarity(idx)
        recs = self.anime_df.iloc[top_indices].copy()
        recs['similarity_score'] = sim_scores_top
        recs['recency_score'] = recs['Release_year'].apply(self._calculate_recency_boost)
        recs['end_year'] = recs['Release_year'].fillna(self.current_year)
        recs['episodes'] = pd.to_numeric(recs['Episodes'], errors='coerce').fillna(self.median_episodes)

        recs['age_penalty'] = recs.apply(
            lambda row: 0 if row['Status'] == 'Currently Airing' else
            (self.current_year - row['end_year']) * (1 - 0.5 * min(row['episodes'] / 120, 1)), axis=1
        )

        if user_id not in set(self.ratings_df['user_id']):
            content_score = (
                (1 - similarity_weight) * recs['weighted_rating'] + similarity_weight * recs['similarity_score']
            )
            recs['final_score'] = (
                content_score * (1 - recency_weight) + recs['recency_score'] * recency_weight
            ) / (1 + recs['age_penalty'] / 10)
            recs['svd_pred'] = np.nan
        else:
            svd_preds = []
            for anime_id in recs['anime_id']:
                try:
                    pred = self.svd_model.predict(user_id, anime_id).est
                except Exception:
                    pred = self.svd_model.trainset.global_mean
                svd_preds.append(pred)

            user_rating_count = self.ratings_df[self.ratings_df['user_id'] == user_id].shape[0]
            if user_rating_count < 10:
                svd_weight = 0.5
            elif user_rating_count < 50:
                svd_weight = 0.6
            else:
                svd_weight = 0.7

            recs['svd_pred'] = svd_preds
            rating_weight = max(0, 1 - similarity_weight)
            content_score = rating_weight * recs['weighted_rating'] + similarity_weight * recs['similarity_score']

            recs['final_score'] = (
                ((1 - svd_weight) * content_score + svd_weight * recs['svd_pred']) * (1 - recency_weight) +
                recency_weight * recs['recency_score']
            ) / (1 + recs['age_penalty'] / 10)

        return recs.sort_values('final_score', ascending=False).head(n)[
            ['Image URL', 'Name', 'anime_id', 'Type', 'svd_pred', 'final_score']
        ]

    def get_recommendations_by_genres_simple(self, genres, n=10):
        if isinstance(genres, str):
            genres = [genres]

        input_genres = {g.strip().lower() for g in genres}
        if not input_genres:
            raise ValueError("No valid genres provided.")

        genre_sets = self.anime_df['Genres'].apply(lambda g_list: {g.strip().lower() for g in g_list})
        self.anime_df['has_all_genres'] = genre_sets.apply(
            lambda anime_genres: input_genres.issubset(anime_genres)
        )

        recommendations = self.anime_df[self.anime_df['has_all_genres']].copy()
        current_year = self.current_year

        recommendations['end_year'] = recommendations['Release_year'].fillna(current_year)
        recommendations['episodes'] = pd.to_numeric(recommendations['Episodes'], errors='coerce').fillna(self.median_episodes)

        recommendations['age_penalty'] = recommendations.apply(
            lambda row: 0 if row['Status'] == 'Currently Airing' else
            (current_year - row['end_year']) * (1 - 0.5 * min(row['episodes'] / 120, 1)),
            axis=1
        )

        recommendations['final_score'] = recommendations['weighted_rating'] / (1 + (recommendations['age_penalty'] / 10))

        recommendations = recommendations.sort_values(by='final_score', ascending=False).head(n)

        return recommendations[['Image URL', 'Name', 'Genres', 'weighted_rating', 'age_penalty', 'final_score']]
In [ ]:
recommender = AnimeRecommender1(ratings_df, svd_model=SVD_model)
🔁 Loading cached anime data and feature matrices...
✅ All cached data loaded successfully.
In [ ]:
df = recommender.get_anime_recommendations1(
    title='Fate/stay night: Unlimited Blade Works 2nd Season',
    user_id=20000000000,
    n=24
)
# df
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type svd_pred final_score
22048 No description has been provided for this image Kimetsu no Yaiba: Katanakaji no Sato-hen 51019 TV NaN 1.304393
20430 No description has been provided for this image Kimetsu no Yaiba: Yuukaku-hen 47778 TV NaN 1.149130
21533 No description has been provided for this image Kimetsu no Yaiba: Mugen Ressha-hen 49926 TV NaN 1.110795
24875 No description has been provided for this image Kimetsu no Yaiba: Hashira Geiko-hen 55701 TV NaN 1.103021
11630 No description has been provided for this image Fate/stay night Movie: Heaven's Feel - III. Spring Song 33050 Movie NaN 1.068723
11629 No description has been provided for this image Fate/stay night Movie: Heaven's Feel - II. Lost Butterfly 33049 Movie NaN 1.004636
16352 No description has been provided for this image Enen no Shouboutai: Ni no Shou 40956 TV NaN 0.995372
14539 No description has been provided for this image Kimetsu no Yaiba 38000 TV NaN 0.988310
14613 No description has been provided for this image Fate/Grand Order: Zettai Majuu Sensen Babylonia 38084 TV NaN 0.976281
16089 No description has been provided for this image Maou Gakuin no Futekigousha: Shijou Saikyou no Maou no Shiso, Tensei shite Shison-tachi no Gakkou e Kayou 40496 TV NaN 0.946744
16524 No description has been provided for this image Mars Red 41265 TV NaN 0.939426
14945 No description has been provided for this image Enen no Shouboutai 38671 TV NaN 0.927888
16358 No description has been provided for this image Back Arrow 40964 TV NaN 0.926908
16560 No description has been provided for this image The God of High School 41353 TV NaN 0.916826
16558 No description has been provided for this image Noblesse 41345 TV NaN 0.900579
9312 No description has been provided for this image Fate/stay night Movie: Heaven's Feel - I. Presage Flower 25537 Movie NaN 0.888241
14163 No description has been provided for this image Sarazanmai 37426 TV NaN 0.887312
12475 No description has been provided for this image Fate/Apocrypha 34662 TV NaN 0.847556
15488 No description has been provided for this image Granbelm 39417 TV NaN 0.833975
8617 No description has been provided for this image Fate/stay night: Unlimited Blade Works 22297 TV NaN 0.828481
13373 No description has been provided for this image Garo: Vanishing Line 36144 TV NaN 0.805367
13076 No description has been provided for this image Toji no Miko 35589 TV NaN 0.802411
12175 No description has been provided for this image Tales of Zestiria the Cross 2nd Season 34086 TV NaN 0.796874
13289 No description has been provided for this image Persona 5 the Animation 36023 TV NaN 0.785652
In [ ]:
df = recommender.get_recommendations_by_genres_simple([ 'scifi','romance', 'action']	, n=50)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name Genres weighted_rating age_penalty final_score
21951 No description has been provided for this image Mahouka Koukou no Rettousei (Zoku-hen) [fantasy, action, scifi, romance] 6.387130 0.000000 6.387130
22702 No description has been provided for this image Date A Live V [action, scifi, romance] 6.387130 0.000000 6.387130
24772 No description has been provided for this image Macross (Shinsaku Animation) [action, scifi, romance] 6.387130 0.000000 6.387130
16612 No description has been provided for this image Date A Live IV [action, scifi, romance] 7.746146 2.850000 6.028129
16090 No description has been provided for this image Mahouka Koukou no Rettousei: Raihousha-hen [fantasy, action, scifi, romance] 7.269632 4.729167 4.935535
20157 No description has been provided for this image Gekijou Tanpen Macross Frontier: Toki no Meikyuu [action, scifi, romance] 6.541423 3.983333 4.678014
20436 No description has been provided for this image Ai Zai Xiyuan Qian 2nd Season [fantasy, action, scifi, romance] 6.386648 3.733333 4.650471
13676 No description has been provided for this image Date A Live III [action, scifi, romance] 7.182833 5.700000 4.575053
13216 No description has been provided for this image Darling in the FranXX [action, drama, scifi, romance] 7.208504 6.300000 4.422395
17902 No description has been provided for this image Chu Feng: Yi Dian Zhi Zi [fantasy, action, scifi, romance] 6.346420 4.750000 4.302657
16311 No description has been provided for this image Ai Zai Xiyuan Qian [fantasy, action, scifi, romance] 6.358454 5.700000 4.049971
14559 No description has been provided for this image Beatless Final Stage [action, drama, scifi, romance] 6.758023 6.883333 4.002778
9655 No description has been provided for this image Macross Δ [action, scifi, romance] 7.213781 8.025000 4.002098
13591 No description has been provided for this image Beatless [action, drama, scifi, romance] 6.215648 6.416667 3.786182
11040 No description has been provided for this image Gakusen Toshi Asterisk 2nd Season [fantasy, ecchi, action, comedy, romance, scifi] 6.995652 8.550000 3.771241
8305 No description has been provided for this image Mahouka Koukou no Rettousei [fantasy, action, scifi, romance] 7.406821 9.808333 3.739245
9140 No description has been provided for this image Date A Live Movie: Mayuri Judgment [action, scifi, romance] 7.315063 9.958333 3.665167
8000 No description has been provided for this image Date A Live II [action, scifi, romance] 7.186278 10.541667 3.498391
10538 No description has been provided for this image Gakusen Toshi Asterisk [fantasy, ecchi, action, comedy, romance, scifi] 6.817911 9.500000 3.496365
11057 No description has been provided for this image Accel World: Infinite∞Burst [action, scifi, romance] 6.606556 8.962500 3.484011
14070 No description has been provided for this image Beatless Intermission [action, drama, scifi, romance] 5.819581 6.883333 3.446939
13895 No description has been provided for this image Cutie Honey Universe [action, scifi, romance, comedy] 5.669904 6.650000 3.405348
10864 No description has been provided for this image Hundred [action, scifi, romance, ecchi] 6.310695 8.550000 3.401992
6597 No description has been provided for this image Accel World [action, scifi, romance] 7.226102 11.700000 3.330001
11628 No description has been provided for this image Zegapain ADP [action, scifi, romance] 6.290003 8.962500 3.317075
11087 No description has been provided for this image Masou Gakuen HxH [fantasy, ecchi, action, comedy, romance, scifi] 6.133505 8.550000 3.306472
6198 No description has been provided for this image Aquarion Evol [fantasy, action, scifi, romance] 7.053481 11.591667 3.266761
4922 No description has been provided for this image Macross F Movie 2: Sayonara no Tsubasa [action, scifi, romance, award winning] 7.758669 13.941667 3.240655
8481 No description has been provided for this image Captain Earth [action, scifi, romance] 6.399017 9.854167 3.223009
7775 No description has been provided for this image Freezing Vibration [ecchi, action, drama, romance, scifi] 6.713316 11.400000 3.137064
3131 No description has been provided for this image Macross F [action, scifi, romance, award winning] 7.850851 15.229167 3.111815
7047 No description has been provided for this image Accel World EX [action, scifi, romance] 7.079104 12.891667 3.092437
10459 No description has been provided for this image Aquarion Logos [fantasy, action, scifi, romance] 5.845082 8.916667 3.089911
6621 No description has been provided for this image Zetman [supernatural, action, drama, romance, horror, scifi] 6.827165 12.295833 3.062081
5559 No description has been provided for this image Star Driver: Kagayaki no Takuto [action, scifi, romance] 7.159537 13.437500 3.054736
10175 No description has been provided for this image Chu Feng: B.E.E [fantasy, action, comedy, romance, scifi] 5.994350 9.750000 3.035114
6822 No description has been provided for this image Star Driver the Movie [action, scifi, romance] 6.542405 11.950000 2.980594
4074 No description has been provided for this image Macross F Movie 1: Itsuwari no Utahime [action, scifi, romance] 7.646773 15.933333 2.948627
5727 No description has been provided for this image Freezing [ecchi, action, drama, romance, scifi] 6.795726 13.300000 2.916621
7212 No description has been provided for this image Macross FB7: Ore no Uta wo Kike! [action, scifi, romance] 6.332608 12.945833 2.759807
72 No description has been provided for this image Kidou Senshi Gundam SEED [award winning, action, drama, romance, scifi] 7.724560 18.208333 2.738396
73 No description has been provided for this image Kidou Senshi Gundam SEED Destiny [action, drama, scifi, romance] 7.158412 16.625000 2.688605
793 No description has been provided for this image Zegapain [action, scifi, romance] 7.163313 16.941667 2.658823
3923 No description has been provided for this image Kurozuka [action, drama, romance, horror, scifi] 6.844540 16.150000 2.617415
3078 No description has been provided for this image Genius Party [fantasy, action, romance, scifi, avant garde] 7.047031 17.475000 2.564889
449 No description has been provided for this image Sousei no Aquarion [fantasy, action, scifi, romance] 7.052144 17.833333 2.533704
2564 No description has been provided for this image Dragonaut: The Resonance [fantasy, action, drama, romance, scifi] 6.589017 16.125000 2.522112
3045 No description has been provided for this image Kemeko Deluxe! [ecchi, action, comedy, romance, scifi] 6.534407 16.150000 2.498817
4633 No description has been provided for this image Urusei Yatsura: The Shougaibutsu Suieitaikai [action, scifi, romance, comedy] 6.727476 16.929167 2.498212
374 No description has been provided for this image Seikai no Senki III [action, scifi, romance] 7.440590 19.833333 2.494053
In [ ]:
df = recommender.get_recommendations_by_genres_simple(['fantasy', 'adventure', 'action']	, n=50)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name Genres weighted_rating age_penalty final_score
11 No description has been provided for this image One Piece [fantasy, action, adventure] 8.686696 0.000000 8.686696
19600 No description has been provided for this image Jigokuraku [fantasy, action, adventure] 8.224549 0.000000 8.224549
21578 No description has been provided for this image Edens Zero 2nd Season [fantasy, action, scifi, adventure] 7.164798 0.000000 7.164798
23659 No description has been provided for this image Pokemon (2023) [fantasy, action, adventure, comedy] 7.112476 0.000000 7.112476
16617 No description has been provided for this image Bleach: Sennen Kessen-hen [fantasy, action, adventure] 9.048079 2.837500 7.048163
22054 No description has been provided for this image Doupo Cangqiong: Nian Fan [fantasy, action, adventure] 6.968240 0.000000 6.968240
21385 No description has been provided for this image Tunshi Xingkong 2nd Season [fantasy, action, scifi, adventure] 6.952457 0.000000 6.952457
23239 No description has been provided for this image Dungeon ni Deai wo Motomeru no wa Machigatteiru Darou ka IV: Fuka Shou - Yakusai-hen [fantasy, action, adventure] 8.199359 1.908333 6.885396
20156 No description has been provided for this image Wanmei Shijie [fantasy, action, adventure] 6.836767 0.000000 6.836767
22968 No description has been provided for this image Shen Yin Wangzuo 2nd Season [fantasy, action, adventure] 6.798776 0.000000 6.798776
21388 No description has been provided for this image Yi Nian Yong Heng: Chuan Cheng Pian [fantasy, action, adventure] 6.779368 0.000000 6.779368
23047 No description has been provided for this image Isekai de Cheat Skill wo Te ni Shita Ore wa, Genjitsu Sekai wo mo Musou Suru: Level Up wa Jinsei wo Kaeta [fantasy, action, adventure] 6.591589 0.000000 6.591589
16770 No description has been provided for this image Ling Jian Zun 4th Season [fantasy, action, adventure, romance] 6.578649 0.000000 6.578649
21122 No description has been provided for this image Wu Shang Shen Di 2nd Season [fantasy, action, adventure, supernatural] 6.526427 0.000000 6.526427
22469 No description has been provided for this image Xingchen Bian 5th Season [fantasy, action, adventure, romance] 6.476171 0.000000 6.476171
23948 No description has been provided for this image Yao Shen Ji 6th Season [fantasy, action, adventure, romance] 6.456534 0.000000 6.456534
23122 No description has been provided for this image Bai Lian Cheng Shen [fantasy, action, adventure] 6.448433 0.000000 6.448433
24035 No description has been provided for this image Lian Qi Shi Wan Nian [fantasy, action, adventure] 6.425276 0.000000 6.425276
23023 No description has been provided for this image Wan Jie Du Zun 2nd Season [fantasy, action, adventure] 6.422149 0.000000 6.422149
23427 No description has been provided for this image Binghuo Mochu 2 [fantasy, action, adventure] 6.421938 0.000000 6.421938
22936 No description has been provided for this image Wangu Shenhua [fantasy, action, adventure] 6.410487 0.000000 6.410487
23854 No description has been provided for this image Jian Yu Feng Yun 2nd Season [fantasy, action, adventure] 6.387130 0.000000 6.387130
21377 No description has been provided for this image Shanhe Jian Xin 2nd Season [fantasy, action, adventure] 6.387130 0.000000 6.387130
23155 No description has been provided for this image Arifureta Shokugyou de Sekai Saikyou 3rd Season [fantasy, action, adventure] 6.387130 0.000000 6.387130
23300 No description has been provided for this image Jun You Yun 2nd Season [fantasy, action, adventure] 6.387130 0.000000 6.387130
22249 No description has been provided for this image Liaotian Qun De Richang Shenghuo [fantasy, action, adventure, comedy] 6.387130 0.000000 6.387130
23568 No description has been provided for this image Knights of the Zodiac: Saint Seiya 3rd Season [fantasy, action, scifi, adventure] 6.387130 0.000000 6.387130
23556 No description has been provided for this image Sokushi Cheat ga Saikyou sugite, Isekai no Yatsura ga Marude Aite ni Naranai n desu ga. [fantasy, action, adventure] 6.387130 0.000000 6.387130
23482 No description has been provided for this image Bye-Bye, Earth [fantasy, action, adventure] 6.387130 0.000000 6.387130
21094 No description has been provided for this image Overlord Movie 3: Sei Oukoku-hen [fantasy, action, adventure] 6.387130 0.000000 6.387130
24039 No description has been provided for this image Fanren Xiu Xian Chuan: Chongzhi Ban [fantasy, action, adventure] 6.387130 0.000000 6.387130
24042 No description has been provided for this image Ishura [fantasy, action, adventure] 6.387130 0.000000 6.387130
22406 No description has been provided for this image Nozomanu Fushi no Boukensha [fantasy, action, adventure] 6.387130 0.000000 6.387130
23451 No description has been provided for this image Sword Art Online (Original Movie) [fantasy, action, adventure, romance] 6.387130 0.000000 6.387130
23433 No description has been provided for this image Jing Cui Xian Zun Part 2 [fantasy, action, adventure] 6.387130 0.000000 6.387130
24156 No description has been provided for this image Fangkemeng: Bu Yuan Zhi Dao de Fangxing Baokemeng?! [fantasy, action, adventure, comedy] 6.387130 0.000000 6.387130
21801 No description has been provided for this image Tian Bao Fuyao Lu 3rd Season [fantasy, action, adventure, supernatural] 6.387130 0.000000 6.387130
24174 No description has been provided for this image Boruto: Naruto Next Generations Part 2 [fantasy, action, adventure] 6.387130 0.000000 6.387130
22183 No description has been provided for this image Emo Faze [fantasy, action, adventure] 6.387130 0.000000 6.387130
21796 No description has been provided for this image Tian Guan Ci Fu 2nd Season [fantasy, supernatural, adventure, action, drama] 6.387130 0.000000 6.387130
24886 No description has been provided for this image Dekisokonai to Yobareta Motoeiyuu wa Jikka kara Tsuihou sareta node Sukikatte ni Ikiru Koto ni Shita [fantasy, action, adventure] 6.387130 0.000000 6.387130
21759 No description has been provided for this image Seirei Gensouki 2nd Season [fantasy, action, adventure, romance] 6.387130 0.000000 6.387130
22556 No description has been provided for this image Da Wang Rao Ming 2 [fantasy, action, adventure, comedy] 6.387130 0.000000 6.387130
21652 No description has been provided for this image Yuan Zun [fantasy, action, adventure] 6.387130 0.000000 6.387130
21514 No description has been provided for this image Tsuki ga Michibiku Isekai Douchuu 2nd Season [fantasy, action, adventure, comedy] 6.387130 0.000000 6.387130
24828 No description has been provided for this image MY WIFE IS A DEMON QUEEN [fantasy, action, adventure, romance] 6.387130 0.000000 6.387130
21472 No description has been provided for this image Fairy Tail: 100 Years Quest [fantasy, action, adventure] 6.387130 0.000000 6.387130
24797 No description has been provided for this image Gu Wu Gaoshou Zai Dushi 3rd Season [fantasy, action, adventure] 6.387130 0.000000 6.387130
24777 No description has been provided for this image Si Ge Yongzhe [fantasy, adventure, action, comedy, romance] 6.387130 0.000000 6.387130
24765 No description has been provided for this image Jian Gu [fantasy, action, adventure] 6.387130 0.000000 6.387130
In [ ]:
df = recommender.get_recommendations_by_genres_simple(['horror', 'action']	, n=50)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name Genres weighted_rating age_penalty final_score
14170 No description has been provided for this image Chimera [horror, action, supernatural] 6.387130 0.000000 6.387130
23140 No description has been provided for this image Berserk: Ougon Jidai-hen - Memorial Edition [fantasy, adventure, action, drama, horror] 7.673791 2.837500 5.977636
14942 No description has been provided for this image Dorohedoro [fantasy, action, comedy, horror] 8.048611 4.750000 5.456685
23844 No description has been provided for this image Zom 100: Zombie ni Naru made ni Shitai 100 no Koto [supernatural, suspense, action, comedy, horror] 6.387130 1.983333 5.330011
24008 No description has been provided for this image Biohazard: Death Island [horror, action, scifi] 6.387130 1.991667 5.326307
23881 No description has been provided for this image Muja [horror, action] 6.387130 2.987500 4.917906
23021 No description has been provided for this image Kinemaquia PV [horror, action, supernatural] 6.343686 2.987500 4.884455
17645 No description has been provided for this image Tenkuu Shinpan [horror, action, mystery] 6.706470 3.800000 4.859761
12419 No description has been provided for this image Koutetsujou no Kabaneri Movie 3: Unato Kessen [fantasy, action, drama, horror] 7.653065 5.975000 4.790651
16394 No description has been provided for this image Dorohedoro: Ma no Omake [fantasy, action, comedy, horror] 7.055402 4.875000 4.743128
21089 No description has been provided for this image Ling Long: Incarnation Special [suspense, action, drama, horror, scifi] 6.535984 3.983333 4.674125
17924 No description has been provided for this image Ling Long: Incarnation Final Chapter [suspense, action, drama, horror, scifi] 6.527820 3.966667 4.673857
12774 No description has been provided for this image Devilman: Crybaby [horror, action, supernatural, avant garde] 7.756334 6.708333 4.642195
23604 No description has been provided for this image Chikajou no Mamono [horror, action, suspense] 6.387130 3.983333 4.567673
17238 No description has been provided for this image Biohazard: Infinite Darkness [horror, action, scifi] 6.256654 3.933333 4.490422
16922 No description has been provided for this image Ling Long: Incarnation Part 2 [suspense, action, drama, horror, scifi] 6.647807 4.875000 4.469114
16836 No description has been provided for this image Bem Movie: Become Human [horror, action, supernatural] 6.621090 4.979167 4.420199
15634 No description has been provided for this image Ling Long: Incarnation [suspense, action, drama, horror, scifi] 6.728516 5.850000 4.245121
8677 No description has been provided for this image Kiseijuu: Sei no Kakuritsu [horror, action, scifi] 8.336886 9.900000 4.189390
11876 No description has been provided for this image Koutetsujou no Kabaneri Movie 2: Moeru Inochi [fantasy, action, drama, horror] 7.439158 7.966667 4.140533
17242 No description has been provided for this image Ling Long: Incarnation Middle Chapter [suspense, action, drama, horror, scifi] 6.589379 5.975000 4.124807
11751 No description has been provided for this image Ajin Part 2 [horror, action, supernatural, mystery] 7.567470 8.512500 4.087762
10960 No description has been provided for this image Ajin [horror, action, supernatural, mystery] 7.393813 8.512500 3.993957
17537 No description has been provided for this image Fire Emblem Heroes Book III Movie:Cohort of the Dead [fantasy, action, supernatural, horror] 6.355354 5.975000 3.978312
11613 No description has been provided for this image Danganronpa 3: The End of Kibougamine Gakuen - Zetsubou-hen [horror, action, mystery] 7.369897 8.587500 3.964975
12206 No description has been provided for this image Super Danganronpa 2.5: Komaeda Nagito to Sekai no Hakaimono [horror, action, suspense, mystery] 7.115634 7.966667 3.960464
11875 No description has been provided for this image Koutetsujou no Kabaneri Movie 1: Tsudou Hikari [fantasy, action, drama, horror] 7.434561 8.962500 3.920665
9798 No description has been provided for this image Koutetsujou no Kabaneri [fantasy, action, drama, horror] 7.266267 8.550000 3.917125
12182 No description has been provided for this image Danganronpa 3: The End of Kibougamine Gakuen - Kibou-hen [horror, action, mystery] 7.402755 8.962500 3.903892
11210 No description has been provided for this image Danganronpa 3: The End of Kibougamine Gakuen - Mirai-hen [horror, action, mystery] 7.221937 8.550000 3.893227
11171 No description has been provided for this image Gantz:O [horror, action, drama, scifi] 7.379877 8.962500 3.891827
14405 No description has been provided for this image Tokyo Ghoul:re 2nd Season [fantasy, action, horror] 6.429838 6.650000 3.861764
14081 No description has been provided for this image Mo Ri Shu Guang [supernatural, suspense, action, horror, boys love] 6.306844 6.416667 3.841732
11091 No description has been provided for this image Biohazard: Vendetta [horror, action, scifi] 6.895031 7.966667 3.837679
13588 No description has been provided for this image Tokyo Ghoul:re [fantasy, action, horror] 6.370037 6.650000 3.825848
13670 No description has been provided for this image Ajin Part 2 OVA [horror, action, supernatural, mystery] 6.871137 7.966667 3.824381
8619 No description has been provided for this image Tokyo Ghoul [fantasy, action, horror] 7.788620 10.450000 3.808616
24801 No description has been provided for this image Castlevania (Netflix animated series) [fantasy, action, adventure, horror] 6.387130 6.933333 3.771927
24830 No description has been provided for this image Castlevania [fantasy, adventure, action, drama, horror] 6.387130 6.933333 3.771927
24340 No description has been provided for this image Life of the Dead Episode 7 [horror, action, suspense] 6.387130 6.970833 3.763592
11155 No description has been provided for this image Ajin OVA [horror, action, supernatural, mystery] 7.108905 8.925000 3.756357
12168 No description has been provided for this image Berserk 2nd Season [fantasy, adventure, action, drama, horror] 6.556780 7.600000 3.725443
6671 No description has been provided for this image Berserk: Ougon Jidai-hen III - Kourin [fantasy, adventure, action, drama, horror] 8.176690 11.950000 3.725144
10643 No description has been provided for this image Ajin Part 2: Shoutotsu [horror, action, supernatural, mystery] 7.029073 8.962500 3.706828
10644 No description has been provided for this image Ajin Part 3: Shougeki [horror, action, supernatural, mystery] 7.026792 8.962500 3.705625
10642 No description has been provided for this image Ajin Part 1: Shoudou [horror, action, supernatural, mystery] 7.338186 9.958333 3.676753
12408 No description has been provided for this image Terra Formars: Earth-hen [horror, action, scifi] 6.218910 6.941667 3.670778
13765 No description has been provided for this image Xue Se Cang Qiong [fantasy, suspense, adventure, mystery, action, horror] 6.286284 7.133333 3.669037
14277 No description has been provided for this image Devilman: Crybaby - Digest Eizou [horror, action, supernatural] 6.215971 6.970833 3.662737
10513 No description has been provided for this image Tokyo Ghoul: "Jack" [fantasy, action, horror] 7.288512 9.958333 3.651864
In [ ]:
df = recommender.get_recommendations_by_genres_simple([ 'romance','action']	, n=50)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name Genres weighted_rating age_penalty final_score
16770 No description has been provided for this image Ling Jian Zun 4th Season [fantasy, action, adventure, romance] 6.578649 0.000000 6.578649
21268 No description has been provided for this image Wan Jie Xian Zong 5th Season [fantasy, action, romance] 6.487966 0.000000 6.487966
22469 No description has been provided for this image Xingchen Bian 5th Season [fantasy, action, adventure, romance] 6.476171 0.000000 6.476171
23948 No description has been provided for this image Yao Shen Ji 6th Season [fantasy, action, adventure, romance] 6.456534 0.000000 6.456534
22139 No description has been provided for this image Long Wang Dian 2nd Season [action, romance, comedy] 6.387130 0.000000 6.387130
24777 No description has been provided for this image Si Ge Yongzhe [fantasy, adventure, action, comedy, romance] 6.387130 0.000000 6.387130
24775 No description has been provided for this image Ruler of the Land [fantasy, action, drama, comedy, romance, ecchi] 6.387130 0.000000 6.387130
24828 No description has been provided for this image MY WIFE IS A DEMON QUEEN [fantasy, action, adventure, romance] 6.387130 0.000000 6.387130
22702 No description has been provided for this image Date A Live V [action, scifi, romance] 6.387130 0.000000 6.387130
22734 No description has been provided for this image Baozou Xia Ri [action, romance, comedy] 6.387130 0.000000 6.387130
21759 No description has been provided for this image Seirei Gensouki 2nd Season [fantasy, action, adventure, romance] 6.387130 0.000000 6.387130
23451 No description has been provided for this image Sword Art Online (Original Movie) [fantasy, action, adventure, romance] 6.387130 0.000000 6.387130
23414 No description has been provided for this image Maou no Ore ga Dorei Elf wo Yome ni Shitanda ga, Dou Medereba Ii? [fantasy, action, romance] 6.387130 0.000000 6.387130
17900 No description has been provided for this image Bai She Chuan: Bai Suzhen [fantasy, action, romance] 6.387130 0.000000 6.387130
24772 No description has been provided for this image Macross (Shinsaku Animation) [action, scifi, romance] 6.387130 0.000000 6.387130
22893 No description has been provided for this image Ta Chengle Bing Jiao Junwang De Bai Yueguang [fantasy, action, romance] 6.387130 0.000000 6.387130
21951 No description has been provided for this image Mahouka Koukou no Rettousei (Zoku-hen) [fantasy, action, scifi, romance] 6.387130 0.000000 6.387130
21904 No description has been provided for this image Ayakashi Triangle [supernatural, action, comedy, romance, ecchi] 6.323771 0.000000 6.323771
16612 No description has been provided for this image Date A Live IV [action, scifi, romance] 7.746146 2.850000 6.028129
21739 No description has been provided for this image Sword Art Online: Progressive Movie - Kuraki Yuuyami no Scherzo [fantasy, action, adventure, romance] 7.555626 2.987500 5.817614
23932 No description has been provided for this image Kekkon Yubiwa Monogatari [fantasy, action, romance, ecchi] 6.387130 0.991667 5.810884
23649 No description has been provided for this image Yozakura-san Chi no Daisakusen [action, romance, comedy] 6.387130 0.991667 5.810884
21534 No description has been provided for this image Genjitsu Shugi Yuusha no Oukoku Saikenki Part 2 [fantasy, action, romance] 7.423565 2.837500 5.782719
20994 No description has been provided for this image Koi wa Sekai Seifuku no Ato de [action, romance, comedy] 7.419155 2.850000 5.773662
22923 No description has been provided for this image Tensei Kizoku no Isekai Boukenroku: Jichou wo Shiranai Kamigami no Shito [fantasy, action, romance] 6.635464 1.900000 5.576020
24445 No description has been provided for this image Da Zhu Zai Nian Fan [fantasy, action, adventure, romance] 6.387130 1.566667 5.522014
21738 No description has been provided for this image Yao Shen Ji 5th Season [fantasy, action, adventure, romance] 6.756378 2.266667 5.507917
18096 No description has been provided for this image Doupo Cangqiong 4th Season [fantasy, supernatural, adventure, action, romance] 7.368729 3.600000 5.418183
22555 No description has been provided for this image Hua Jianghu: Bu Liang Ren VI [fantasy, action, drama, romance] 6.387130 1.900000 5.367336
18174 No description has been provided for this image Koroshi Ai [action, romance] 6.883943 2.850000 5.357154
21908 No description has been provided for this image Rurouni Kenshin: Meiji Kenkaku Romantan (2023) [action, romance] 6.387130 1.983333 5.330011
21563 No description has been provided for this image Kimi to Boku no Saigo no Senjou, Aruiwa Sekai ga Hajimaru Seisen Season II [fantasy, action, romance] 6.387130 1.983333 5.330011
20432 No description has been provided for this image Sekai Saikou no Ansatsusha, Isekai Kizoku ni Tensei suru [fantasy, mystery, action, drama, romance] 7.353479 3.800000 5.328608
22263 No description has been provided for this image Engage Kiss [action, romance, comedy] 6.829794 2.837500 5.320190
21929 No description has been provided for this image Xingchen Bian: Po Tian Mi Ju [fantasy, action, adventure, romance] 6.733938 2.800000 5.260889
16716 No description has been provided for this image Genjitsu Shugi Yuusha no Oukoku Saikenki [fantasy, action, romance] 7.231725 3.783333 5.246717
22505 No description has been provided for this image Shu Ling Ji 3 [fantasy, action, romance] 6.387130 2.250000 5.213984
22053 No description has been provided for this image Doupo Cangqiong: Yuanqi [fantasy, action, adventure, romance] 6.706171 2.962500 5.173517
24222 No description has been provided for this image Ayakashi Triangle Recap [supernatural, action, comedy, romance, ecchi] 6.128855 1.991667 5.110928
18004 No description has been provided for this image Seirei Gensouki [fantasy, action, adventure, romance] 7.053035 3.800000 5.110895
18181 No description has been provided for this image Isekai Meikyuu de Harem wo [fantasy, adventure, action, romance, ecchi] 6.566849 2.850000 5.110389
16227 No description has been provided for this image Yao Shen Ji 4th Season [fantasy, action, adventure, romance] 6.967184 3.916667 5.006360
16090 No description has been provided for this image Mahouka Koukou no Rettousei: Raihousha-hen [fantasy, action, scifi, romance] 7.269632 4.729167 4.935535
21302 No description has been provided for this image Xingchen Bian: Xingchen Yao Hai [fantasy, action, adventure, romance] 6.694893 3.800000 4.851372
22814 No description has been provided for this image Long Wang Dian [action, romance, comedy] 6.387130 3.166667 4.850985
21383 No description has been provided for this image Xue Ying Ling Zhu 3rd Season [fantasy, action, adventure, romance] 6.533166 3.566667 4.815602
16905 No description has been provided for this image Wu Dong Qian Kun 2nd Season [fantasy, action, adventure, romance] 6.974597 4.750000 4.728540
17200 No description has been provided for this image Wan Jie Xian Zong 4th Season [fantasy, action, romance] 6.602748 4.000000 4.716249
13994 No description has been provided for this image Douluo Dalu [fantasy, action, adventure, romance] 7.641607 6.241667 4.704940
18012 No description has been provided for this image Xie Wang Zhui Qi: Yishi Qingcheng [fantasy, action, drama, comedy, romance] 6.925415 4.750000 4.695197
In [ ]:
df = recommender.get_recommendations_by_genres_simple(['fantasy', 'action']	, n=50)
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name Genres weighted_rating age_penalty final_score
11 No description has been provided for this image One Piece [fantasy, action, adventure] 8.686696 0.000000 8.686696
19600 No description has been provided for this image Jigokuraku [fantasy, action, adventure] 8.224549 0.000000 8.224549
22709 No description has been provided for this image Mashle [fantasy, action, comedy] 7.553219 0.000000 7.553219
22090 No description has been provided for this image NieR:Automata Ver1.1a [fantasy, action, scifi] 7.355421 0.000000 7.355421
13312 No description has been provided for this image Fate/Grand Order [fantasy, action] 7.285004 0.000000 7.285004
23475 No description has been provided for this image Dead Mount Death Play [fantasy, action, supernatural] 7.240476 0.000000 7.240476
21578 No description has been provided for this image Edens Zero 2nd Season [fantasy, action, scifi, adventure] 7.164798 0.000000 7.164798
23659 No description has been provided for this image Pokemon (2023) [fantasy, action, adventure, comedy] 7.112476 0.000000 7.112476
22048 No description has been provided for this image Kimetsu no Yaiba: Katanakaji no Sato-hen [fantasy, action] 8.467293 1.908333 7.110393
16617 No description has been provided for this image Bleach: Sennen Kessen-hen [fantasy, action, adventure] 9.048079 2.837500 7.048163
22054 No description has been provided for this image Doupo Cangqiong: Nian Fan [fantasy, action, adventure] 6.968240 0.000000 6.968240
21385 No description has been provided for this image Tunshi Xingkong 2nd Season [fantasy, action, scifi, adventure] 6.952457 0.000000 6.952457
23543 No description has been provided for this image Hirogaru Sky! Precure [fantasy, action] 6.923455 0.000000 6.923455
23239 No description has been provided for this image Dungeon ni Deai wo Motomeru no wa Machigatteiru Darou ka IV: Fuka Shou - Yakusai-hen [fantasy, action, adventure] 8.199359 1.908333 6.885396
20893 No description has been provided for this image Maou Gakuin no Futekigousha: Shijou Saikyou no Maou no Shiso, Tensei shite Shison-tachi no Gakkou e Kayou II [fantasy, action] 6.884430 0.000000 6.884430
20156 No description has been provided for this image Wanmei Shijie [fantasy, action, adventure] 6.836767 0.000000 6.836767
20973 No description has been provided for this image Black Clover: Mahou Tei no Ken [fantasy, action, comedy] 8.162355 1.991667 6.806690
22968 No description has been provided for this image Shen Yin Wangzuo 2nd Season [fantasy, action, adventure] 6.798776 0.000000 6.798776
21388 No description has been provided for this image Yi Nian Yong Heng: Chuan Cheng Pian [fantasy, action, adventure] 6.779368 0.000000 6.779368
16584 No description has been provided for this image Wushen Zhuzai [fantasy, action, drama] 6.778840 0.000000 6.778840
22429 No description has been provided for this image Kaminaki Sekai no Kamisama Katsudou [fantasy, action, comedy] 6.759057 0.000000 6.759057
18172 No description has been provided for this image Chainsaw Man [fantasy, action] 8.584003 2.850000 6.680158
16856 No description has been provided for this image Arknights [fantasy, action] 6.602246 0.000000 6.602246
23047 No description has been provided for this image Isekai de Cheat Skill wo Te ni Shita Ore wa, Genjitsu Sekai wo mo Musou Suru: Level Up wa Jinsei wo Kaeta [fantasy, action, adventure] 6.591589 0.000000 6.591589
16770 No description has been provided for this image Ling Jian Zun 4th Season [fantasy, action, adventure, romance] 6.578649 0.000000 6.578649
21122 No description has been provided for this image Wu Shang Shen Di 2nd Season [fantasy, action, adventure, supernatural] 6.526427 0.000000 6.526427
20844 No description has been provided for this image Kage no Jitsuryokusha ni Naritakute! [fantasy, action, comedy] 8.315181 2.750000 6.521711
21331 No description has been provided for this image Ni Tian Zhizun [fantasy, action] 6.517756 0.000000 6.517756
21268 No description has been provided for this image Wan Jie Xian Zong 5th Season [fantasy, action, romance] 6.487966 0.000000 6.487966
22469 No description has been provided for this image Xingchen Bian 5th Season [fantasy, action, adventure, romance] 6.476171 0.000000 6.476171
21139 No description has been provided for this image Mahou Shoujo Magical Destroyers [fantasy, action] 6.470741 0.000000 6.470741
21386 No description has been provided for this image Quanzhi Fashi VI [fantasy, action] 6.464126 0.000000 6.464126
23948 No description has been provided for this image Yao Shen Ji 6th Season [fantasy, action, adventure, romance] 6.456534 0.000000 6.456534
23122 No description has been provided for this image Bai Lian Cheng Shen [fantasy, action, adventure] 6.448433 0.000000 6.448433
17589 No description has been provided for this image Jue Shi Wu Hun [fantasy, action] 6.441052 0.000000 6.441052
24035 No description has been provided for this image Lian Qi Shi Wan Nian [fantasy, action, adventure] 6.425276 0.000000 6.425276
23023 No description has been provided for this image Wan Jie Du Zun 2nd Season [fantasy, action, adventure] 6.422149 0.000000 6.422149
23427 No description has been provided for this image Binghuo Mochu 2 [fantasy, action, adventure] 6.421938 0.000000 6.421938
22936 No description has been provided for this image Wangu Shenhua [fantasy, action, adventure] 6.410487 0.000000 6.410487
22893 No description has been provided for this image Ta Chengle Bing Jiao Junwang De Bai Yueguang [fantasy, action, romance] 6.387130 0.000000 6.387130
22866 No description has been provided for this image Xian Wu Chuan [fantasy, action, adventure] 6.387130 0.000000 6.387130
21451 No description has been provided for this image Xiuluo Wu Shen [fantasy, action] 6.387130 0.000000 6.387130
22864 No description has been provided for this image Yi Nian Yong Heng Xiao Juchang [fantasy, action, comedy] 6.387130 0.000000 6.387130
22737 No description has been provided for this image Wo Cong Zhu Tian Wan Jie Guilai [fantasy, action] 6.387130 0.000000 6.387130
21435 No description has been provided for this image Fate/kaleid liner Prisma☆Illya (Zoku-hen) [fantasy, action] 6.387130 0.000000 6.387130
21237 No description has been provided for this image Youjo Senki II [fantasy, action] 6.387130 0.000000 6.387130
24266 No description has been provided for this image Maou 2099 [fantasy, action, scifi] 6.387130 0.000000 6.387130
24156 No description has been provided for this image Fangkemeng: Bu Yuan Zhi Dao de Fangxing Baokemeng?! [fantasy, action, adventure, comedy] 6.387130 0.000000 6.387130
24196 No description has been provided for this image Bai Lian Feisheng Lu [fantasy, action, adventure] 6.387130 0.000000 6.387130
22249 No description has been provided for this image Liaotian Qun De Richang Shenghuo [fantasy, action, adventure, comedy] 6.387130 0.000000 6.387130
In [ ]:
recommender = AnimeRecommender1(ratings_df, svd_model=SVD_model)
🛠️ Generating and caching features (first run)...
✅ All preprocessing completed and cached.
✅ All cached data loaded successfully.
In [ ]:
df = recommender.get_anime_recommendations1(
    title='Darling in the FranXX',
    user_id=1,
    n=24
)
# df
df['Image URL'] = df['Image URL'].apply(lambda x: f'<img src="{x}" width="100"/>')

display(HTML(df.to_html(escape=False)))
Image URL Name anime_id Type svd_pred final_score
21948 No description has been provided for this image Lycoris Recoil 50709 TV 7.479177 3.720411
20964 No description has been provided for this image 86 Part 2 48569 TV 7.972586 3.672763
16608 No description has been provided for this image 86 41457 TV 7.866722 3.614240
16309 No description has been provided for this image SSSS.Dynazenon 40870 TV 7.568760 3.475140
21073 No description has been provided for this image Cardfight!! Vanguard: overDress Season 2 48862 TV 7.434672 3.402961
22263 No description has been provided for this image Engage Kiss 51417 TV 6.319085 3.177520
16266 No description has been provided for this image Hypnosis Mic: Division Rap Battle - Rhyme Anima 40803 TV 7.165139 3.086045
13591 No description has been provided for this image Beatless 36516 TV 6.985848 2.695937
11508 No description has been provided for this image Senki Zesshou Symphogear AXZ 32836 TV 7.403490 2.673891
8855 No description has been provided for this image Shigatsu wa Kimi no Uso 23273 TV 8.366180 2.638317
10540 No description has been provided for this image Soukyuu no Fafner: Dead Aggressor - Exodus Part 2 30549 TV 8.175402 2.635609
12271 No description has been provided for this image Grancrest Senki 34279 TV 6.684960 2.632233
9655 No description has been provided for this image Macross Δ 28013 TV 7.449904 2.615518
11072 No description has been provided for this image Kiznaiver 31798 TV 7.236734 2.484391
9604 No description has been provided for this image Plastic Memories 27775 TV 7.475861 2.445603
7558 No description has been provided for this image Soukyuu no Fafner: Dead Aggressor - Exodus 17080 TV 7.318508 2.387288
10460 No description has been provided for this image Classroom☆Crisis 30383 TV 6.959962 2.279592
7299 No description has been provided for this image Senki Zesshou Symphogear G 15793 TV 7.600541 2.247569
11157 No description has been provided for this image Bubuki Buranki 32023 TV 6.501526 2.235694
8424 No description has been provided for this image Buddy Complex 21437 TV 7.055803 2.198688
6358 No description has been provided for this image Guilty Crown 10793 TV 7.615118 2.118129
8823 No description has been provided for this image M3: Sono Kuroki Hagane 23133 TV 6.585564 2.113426
3375 No description has been provided for this image Kidou Senshi Gundam 00 Second Season 3927 TV 7.836909 1.961011
5559 No description has been provided for this image Star Driver: Kagayaki no Takuto 8934 TV 7.229457 1.954424
In [ ]: