The data crawled from the popular anime website MyAnimeList.net, and cleaned of duplicates as well as missing values and false data. Following that, autoencoders used to learn embeddings of all the anime titles present in the dataset, which were then used to cluster the same.
Anime (a term derived from the English word animation) is a form of hand-drawn computer animation which originated in Japan and has now developed a cult following around the world. In recent years, the Anime industry has been growing at an enormous pace making billions of dollars in profit every year. Its market has gained attention from major streaming platforms like Netflix and Amazon Prime. In the pre-internet era, Anime enthusiasts discovered new titles through word of mouth. Hence personalized recommendations were not required. Moreover, the number of titles released were quite less to facilitate a data-based approach for personalized recommendations. However, in recent years, with the boom of streaming services and the amount of newly released anime titles, people can watch Anime as much as they like. This calls for a personalized recommendation system for this new generation of Anime watchers.
The data used for training Rikonet was crawled from the popular anime website MyAnimeList.net using the Jikan API. The collected data was cleaned of duplicates as well as missing values and false data and reduced to 6668 anime titles while retaining all the key information.
Following that, autoencoders used to learn embeddings of all the anime titles present in the dataset, which were then used to cluster the same.
The logically opposite clusters of the anime titles are estimated as well.
At run-time, when a user requests a new recommendation list, the user’s context, i.e., the anime titles rated so far is fed into the primary autoencoder, which computes the predicted ratings for the unrated titles.
These ratings are further fed to a hybrid filter, which generates 2 lists, namely - Similar Anime and Anime You May Like, the former showing anime titles similar to the ones the user rated highly and the later showing titles which the user may like based on his overall ratings.
!pip install google_trans_new
Collecting google_trans_new Downloading https://files.pythonhosted.org/packages/f9/7b/9f136106dc5824dc98185c97991d3cd9b53e70a197154dd49f7b899128f6/google_trans_new-1.1.9-py3-none-any.whl Installing collected packages: google-trans-new Successfully installed google-trans-new-1.1.9
from collections import OrderedDict
from tabulate import tabulate
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.nn.init as init
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
from google_trans_new import google_translator
!wget https://github.com/sparsh-ai/reco-data/raw/master/anime/anime_cleaned.csv
!wget https://github.com/sparsh-ai/reco-data/raw/master/anime/anime_genres.csv
!wget https://github.com/sparsh-ai/reco-data/raw/master/anime/clusters.csv
!wget https://github.com/sparsh-ai/reco-data/raw/master/anime/inputFormater.csv
!gdown --id 1LV7VHOTqU5WgBYxfRcUeY31dbhcBqyzb
!gdown --id 14x3TgzhFl-XCHjJHtX-mZrtTSkJgIIey
--2021-06-25 19:04:45-- https://github.com/sparsh-ai/reco-data/raw/master/anime/anime_cleaned.csv Resolving github.com (github.com)... 192.30.255.112 Connecting to github.com (github.com)|192.30.255.112|:443... connected. HTTP request sent, awaiting response... 302 Found Location: https://raw.githubusercontent.com/sparsh-ai/reco-data/master/anime/anime_cleaned.csv [following] --2021-06-25 19:04:45-- https://raw.githubusercontent.com/sparsh-ai/reco-data/master/anime/anime_cleaned.csv Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.111.133, 185.199.108.133, ... Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 6326231 (6.0M) [text/plain] Saving to: ‘anime_cleaned.csv’ anime_cleaned.csv 100%[===================>] 6.03M 39.1MB/s in 0.2s 2021-06-25 19:04:46 (39.1 MB/s) - ‘anime_cleaned.csv’ saved [6326231/6326231] --2021-06-25 19:04:46-- https://github.com/sparsh-ai/reco-data/raw/master/anime/anime_genres.csv Resolving github.com (github.com)... 192.30.255.113 Connecting to github.com (github.com)|192.30.255.113|:443... connected. HTTP request sent, awaiting response... 302 Found Location: https://raw.githubusercontent.com/sparsh-ai/reco-data/master/anime/anime_genres.csv [following] --2021-06-25 19:04:46-- https://raw.githubusercontent.com/sparsh-ai/reco-data/master/anime/anime_genres.csv Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.111.133, 185.199.108.133, ... Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 1346938 (1.3M) [text/plain] Saving to: ‘anime_genres.csv’ anime_genres.csv 100%[===================>] 1.28M --.-KB/s in 0.07s 2021-06-25 19:04:46 (17.6 MB/s) - ‘anime_genres.csv’ saved [1346938/1346938] --2021-06-25 19:04:46-- https://github.com/sparsh-ai/reco-data/raw/master/anime/clusters.csv Resolving github.com (github.com)... 192.30.255.112 Connecting to github.com (github.com)|192.30.255.112|:443... connected. HTTP request sent, awaiting response... 302 Found Location: https://raw.githubusercontent.com/sparsh-ai/reco-data/master/anime/clusters.csv [following] --2021-06-25 19:04:47-- https://raw.githubusercontent.com/sparsh-ai/reco-data/master/anime/clusters.csv Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ... Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 289248 (282K) [text/plain] Saving to: ‘clusters.csv’ clusters.csv 100%[===================>] 282.47K --.-KB/s in 0.02s 2021-06-25 19:04:47 (11.9 MB/s) - ‘clusters.csv’ saved [289248/289248] --2021-06-25 19:04:47-- https://github.com/sparsh-ai/reco-data/raw/master/anime/inputFormater.csv Resolving github.com (github.com)... 192.30.255.112 Connecting to github.com (github.com)|192.30.255.112|:443... connected. HTTP request sent, awaiting response... 302 Found Location: https://raw.githubusercontent.com/sparsh-ai/reco-data/master/anime/inputFormater.csv [following] --2021-06-25 19:04:48-- https://raw.githubusercontent.com/sparsh-ai/reco-data/master/anime/inputFormater.csv Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.111.133, 185.199.108.133, ... Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 35960 (35K) [text/plain] Saving to: ‘inputFormater.csv’ inputFormater.csv 100%[===================>] 35.12K --.-KB/s in 0.001s 2021-06-25 19:04:48 (26.5 MB/s) - ‘inputFormater.csv’ saved [35960/35960] Downloading... From: https://drive.google.com/uc?id=1LV7VHOTqU5WgBYxfRcUeY31dbhcBqyzb To: /content/autoEncoder.pth 291MB [00:01, 149MB/s] Downloading... From: https://drive.google.com/uc?id=14x3TgzhFl-XCHjJHtX-mZrtTSkJgIIey To: /content/similar_anime_genre.csv 175MB [00:00, 212MB/s]
def top_animes(genre, ani_genre, all_anime):
top = []
print("\nTop", genre)
temp = list(ani_genre[ani_genre[genre]==1]['anime_id'])
temp = list(filter(lambda x: x in all_anime.index, temp))
temp.sort(key=lambda x: all_anime['score'][x], reverse=True)
for i in range(5):
r = [i+1, temp[i], all_anime['title'][temp[i]], all_anime['title_english'][temp[i]],
all_anime['score'][temp[i]], all_anime['genre'][temp[i]]]
top.append(r)
table = tabulate(top, headers=['S.No.', 'Anime ID', 'Title', 'English Title',
'Anime Score', 'Anime Genre'], tablefmt='orgtbl')
print(table)
results = pd.read_csv('clusters.csv')
results.head()
anime_id | title | alpha | omega | zeta | |
---|---|---|---|---|---|
0 | 11013 | Inu x Boku SS | 15 | 82 | 135 |
1 | 2104 | Seto no Hanayome | 125 | 157 | 55 |
2 | 5262 | Shugo Chara!! Doki | 130 | 113 | 82 |
3 | 721 | Princess Tutu | 159 | 108 | 97 |
4 | 12365 | Bakuman. 3rd Season | 112 | 55 | 29 |
clusters = []
for i in range(222):
clusters.append([])
for i in range(len(results)):
clusters[results['alpha'][i]].append(results['anime_id'][i])
def getCluster(anime_id, opposite=False):
if opposite == False:
temp = results[results['anime_id'] == anime_id]['alpha'].reset_index(drop=True)
clusterID = temp[0]
return clusters[clusterID]
else:
temp = results[results['anime_id'] == anime_id]['zeta'].reset_index(drop=True)
clusterID = temp[0]
return clusters[clusterID]
input_formater = pd.read_csv("inputFormater.csv")
input_formater.iloc[:5, :5]
Gender | Category2 | Category3 | Category4 | Category5 |
---|
class UserVector(Dataset):
def __init__(self, age, gender, uratings):
if age<11:
self.age=2
elif age<16:
self.age=3
elif age<20:
self.age=4
else:
self.age=5
if gender.lower() == 'male':
self.gender = 0
else:
self.gender = 1
self.data = input_formater
self.data.loc[0, 'Gender'] = self.gender
self.data.loc[0, 'Category'+str(self.age)] = 1
self.columns = list(self.data.columns)
self.aniId_to_ind = pd.Series(data=range(len(self.columns)), index=self.columns)
for aniId in uratings.keys():
self.data.loc[0, str(aniId)] = uratings[aniId]
self.data.fillna(0, inplace=True)
self.data = self.data.iloc[:,:]
self.transform = transforms.Compose([transforms.ToTensor()])
self.data = self.transform(np.array(self.data))
def __len__(self):
return len(self.data[0])
def __getitem__(self, ind):
user_vector = self.data.data[0][ind]
return user_vector
def get_anime_id(self, ind):
return int(self.columns[ind])
def anime_to_index(self):
return self.aniId_to_ind
ani_genre = pd.read_csv("anime_genres.csv", index_col=[0])
ani_genre.head()
anime_id | Sports | Parody | Mecha | Cars | Dementia | Slice of Life | Mystery | Horror | Super Power | Magic | Demons | Shoujo | Space | Military | Seinen | Action | Music | Vampire | Historical | Game | Harem | Samurai | Sci-Fi | Psychological | Josei | Ecchi | Comedy | Fantasy | School | Yuri | Adventure | Drama | Kids | Hentai | Shounen | Thriller | Romance | Shoujo Ai | Supernatural | Police | Yaoi | Martial Arts | Shounen Ai | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 11013 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
1 | 2104 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 5262 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3 | 721 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
4 | 12365 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
# Get similar anime
def similarAnime(uratings, all_anime):
if len(uratings) == 0:
anime_data = all_anime.set_index('anime_id')
top_animes('Shounen', ani_genre, anime_data)
top_animes('Supernatural', ani_genre, anime_data)
top_animes('Romance', ani_genre, anime_data)
top_animes('Slice of Life', ani_genre, anime_data)
return []
else:
temp = list(reversed(uratings.items()))
SimilarAnime = []
i = 0
while i < len(temp) and i < 3:
if temp[i][1] >= 6:
SimilarAnime += getCluster(temp[i][0], opposite=False)
else:
SimilarAnime += getCluster(temp[i][0], opposite=True)
i+=1
return SimilarAnime
# Get Anime You May Like
def animeYouMayLike(age, gender, uratings, model, all_anime, aniId_to_index):
# Get Similar Anime
SimilarAnime = similarAnime(uratings, all_anime)
if len(SimilarAnime) == 0:
return [], []
# User Data Column
user_data = UserVector(age, gender, uratings)
# User Data Loader
user_dl = DataLoader(dataset=user_data, num_workers=1)
# Get model Predictions
preds = model.getPredictedRatings(user_data, user_dl)
preds = preds.reshape(-1)
# Get top predicted anime
animes = list(preds.argsort()[-1000:][::-1])
animes = list(map(user_data.get_anime_id, animes))
# Generate 'Similar Anime' and 'Anime You May Like'
FinalList1 = []
FinalList2 = []
for aniID in animes:
index = int(aniId_to_index.at[aniID])
r = [aniID, all_anime['title'][index], all_anime['title_english'][index], all_anime['genre'][index]]
if aniID in SimilarAnime and len(FinalList1) <10 and aniID not in uratings:
FinalList1.append(r)
elif aniID not in SimilarAnime and len(FinalList2) <10 and aniID not in uratings:
FinalList2.append(r)
elif len(FinalList1) == 10 and len(FinalList2) == 10:
break
return FinalList1, FinalList2
def showRecommendations(age, gender, uratings, model, all_anime, aniId_to_index):
# Get both the lists
List1, List2 = animeYouMayLike(age, gender, uratings, model, all_anime, aniId_to_index)
if len(List1) == 0 and len(List2) == 0:
return
# Tabulate the Results
print("similar Anime")
table = tabulate(List1, headers=['Anime ID', 'JP Title', 'EN Title', 'Genre'], tablefmt='orgtbl')
print(table)
print("Anime You May Like")
table = tabulate(List2, headers=['Anime ID', 'JP Title', 'EN Title', 'Genre'], tablefmt='orgtbl')
print(table)
def activation(input, type):
if type.lower()=='selu':
return F.selu(input)
elif type.lower()=='elu':
return F.elu(input)
elif type.lower()=='relu':
return F.relu(input)
elif type.lower()=='relu6':
return F.relu6(input)
elif type.lower()=='lrelu':
return F.leaky_relu(input)
elif type.lower()=='tanh':
return F.tanh(input)
elif type.lower()=='sigmoid':
return F.sigmoid(input)
elif type.lower()=='swish':
return F.sigmoid(input)*input
elif type.lower()=='identity':
return input
else:
raise ValueError("Unknown non-Linearity Type")
class AutoEncoder(nn.Module):
def __init__(self, layer_sizes, nl_type='selu', is_constrained=True, dp_drop_prob=0.0, last_layer_activations=True):
super(AutoEncoder, self).__init__()
self.layer_sizes = layer_sizes
self.nl_type = nl_type
self.is_constrained = is_constrained
self.dp_drop_prob = dp_drop_prob
self.last_layer_activations = last_layer_activations
if dp_drop_prob>0:
self.drop = nn.Dropout(dp_drop_prob)
self._last = len(layer_sizes) - 2
# Initaialize Weights
self.encoder_weights = nn.ParameterList( [nn.Parameter(torch.rand(layer_sizes[i+1], layer_sizes[i])) for i in range(len(layer_sizes) - 1) ] )
# "Xavier Initialization" ( Understanding the Difficulty in training deep feed forward neural networks - by Glorot, X. & Bengio, Y. )
# ( Values are sampled from uniform distribution )
for weights in self.encoder_weights:
init.xavier_uniform_(weights)
# Encoder Bias
self.encoder_bias = nn.ParameterList( [nn.Parameter(torch.zeros(layer_sizes[i+1])) for i in range(len(layer_sizes) - 1) ] )
reverse_layer_sizes = list(reversed(layer_sizes))
# reversed returns iterator
# Decoder Weights
if is_constrained == False:
self.decoder_weights = nn.ParameterList( [nn.Parameter(torch.rand(reverse_layer_sizes[i+1], reverse_layer_sizes[i])) for i in range(len(reverse_layer_sizes) - 1) ] )
for weights in self.decoder_weights:
init.xavier_uniform_(weights)
self.decoder_bias = nn.ParameterList( [nn.Parameter(torch.zeros(reverse_layer_sizes[i+1])) for i in range(len(reverse_layer_sizes) - 1) ] )
def encode(self,x):
for i,w in enumerate(self.encoder_weights):
x = F.linear(input=x, weight = w, bias = self.encoder_bias[i] )
x = activation(input=x, type=self.nl_type)
# Apply Dropout on the last layer
if self.dp_drop_prob > 0:
x = self.drop(x)
return x
def decode(self,x):
if self.is_constrained == True:
# Weights are tied
for i,w in zip(range(len(self.encoder_weights)),list(reversed(self.encoder_weights))):
x = F.linear(input=x, weight=w.t(), bias = self.decoder_bias[i] )
x = activation(input=x, type=self.nl_type if i != self._last or self.last_layer_activations else 'relu')
else:
for i,w in enumerate(self.decoder_weights):
x = F.linear(input=x, weight = w, bias = self.decoder_weights[i])
x = activation(input=x, type=self.nl_type if i != self._last or self.last_layer_activations else 'relu')
return x
def forward(self,x):
# Forward Pass
return self.decode(self.encode(x))
class PredictionEngine:
def __init__(self):
self.layer_sizes = [6673, 8192, 2048, 512, 256]
self.model = AutoEncoder(layer_sizes=self.layer_sizes, nl_type='selu', is_constrained=True, dp_drop_prob=0.0, last_layer_activations=False)
self.model.load_state_dict(torch.load('autoEncoder.pth'))
try:
self.model = self.model.cuda()
except:
pass
def getPredictedRatings(self, user_dat, user_dl):
for data in user_dl:
inputs = data
try:
inputs = inputs.cuda()
except:
pass
inputs = inputs.float()
outputs = self.model(inputs)
break
return outputs.cpu().detach().numpy()
# Search anime in database
def find_anime(input_anime, name_to_id):
print('Anime Id', '\t', 'Title')
flag = 0
for n in name_to_id.index:
if input_anime in n.lower():
flag = 1
print(name_to_id[n], '\t', n)
return flag
# Load all the datasets
all_anime = pd.read_csv("anime_cleaned.csv")
display(all_anime.head())
anime_id | title | title_english | title_japanese | title_synonyms | image_url | type | source | episodes | status | airing | aired_string | aired | duration | rating | score | scored_by | rank | popularity | members | favorites | background | premiered | broadcast | related | producer | licensor | studio | genre | opening_theme | ending_theme | duration_min | aired_from_year | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 11013 | Inu x Boku SS | Inu X Boku Secret Service | 妖狐×僕SS | Youko x Boku SS | https://myanimelist.cdn-dena.com/images/anime/... | TV | Manga | 12 | Finished Airing | False | Jan 13, 2012 to Mar 30, 2012 | {'from': '2012-01-13', 'to': '2012-03-30'} | 24 min. per ep. | PG-13 - Teens 13 or older | 7.63 | 139250 | 1274.0 | 231 | 283882 | 2809 | Inu x Boku SS was licensed by Sentai Filmworks... | Winter 2012 | Fridays at Unknown | {'Adaptation': [{'mal_id': 17207, 'type': 'man... | Aniplex, Square Enix, Mainichi Broadcasting Sy... | Sentai Filmworks | David Production | Comedy, Supernatural, Romance, Shounen | ['"Nirvana" by MUCC'] | ['#1: "Nirvana" by MUCC (eps 1, 11-12)', '#2: ... | 24.0 | 2012.0 |
1 | 2104 | Seto no Hanayome | My Bride is a Mermaid | 瀬戸の花嫁 | The Inland Sea Bride | https://myanimelist.cdn-dena.com/images/anime/... | TV | Manga | 26 | Finished Airing | False | Apr 2, 2007 to Oct 1, 2007 | {'from': '2007-04-02', 'to': '2007-10-01'} | 24 min. per ep. | PG-13 - Teens 13 or older | 7.89 | 91206 | 727.0 | 366 | 204003 | 2579 | NaN | Spring 2007 | Unknown | {'Adaptation': [{'mal_id': 759, 'type': 'manga... | TV Tokyo, AIC, Square Enix, Sotsu | Funimation | Gonzo | Comedy, Parody, Romance, School, Shounen | ['"Romantic summer" by SUN&LUNAR'] | ['#1: "Ashita e no Hikari (明日への光)" by Asuka Hi... | 24.0 | 2007.0 |
2 | 5262 | Shugo Chara!! Doki | Shugo Chara!! Doki | しゅごキャラ!!どきっ | Shugo Chara Ninenme, Shugo Chara! Second Year | https://myanimelist.cdn-dena.com/images/anime/... | TV | Manga | 51 | Finished Airing | False | Oct 4, 2008 to Sep 25, 2009 | {'from': '2008-10-04', 'to': '2009-09-25'} | 24 min. per ep. | PG - Children | 7.55 | 37129 | 1508.0 | 1173 | 70127 | 802 | NaN | Fall 2008 | Unknown | {'Adaptation': [{'mal_id': 101, 'type': 'manga... | TV Tokyo, Sotsu | NaN | Satelight | Comedy, Magic, School, Shoujo | ['#1: "Minna no Tamago (みんなのたまご)" by Shugo Cha... | ['#1: "Rottara Rottara (ロッタラ ロッタラ)" by Buono! ... | 24.0 | 2008.0 |
3 | 721 | Princess Tutu | Princess Tutu | プリンセスチュチュ | NaN | https://myanimelist.cdn-dena.com/images/anime/... | TV | Original | 38 | Finished Airing | False | Aug 16, 2002 to May 23, 2003 | {'from': '2002-08-16', 'to': '2003-05-23'} | 16 min. per ep. | PG-13 - Teens 13 or older | 8.21 | 36501 | 307.0 | 916 | 93312 | 3344 | Princess Tutu aired in two parts. The first pa... | Summer 2002 | Fridays at Unknown | {'Adaptation': [{'mal_id': 1581, 'type': 'mang... | Memory-Tech, GANSIS, Marvelous AQL | ADV Films | Hal Film Maker | Comedy, Drama, Magic, Romance, Fantasy | ['"Morning Grace" by Ritsuko Okazaki'] | ['"Watashi No Ai Wa Chiisaikeredo" by Ritsuko ... | 16.0 | 2002.0 |
4 | 12365 | Bakuman. 3rd Season | Bakuman. | バクマン。 | Bakuman Season 3 | https://myanimelist.cdn-dena.com/images/anime/... | TV | Manga | 25 | Finished Airing | False | Oct 6, 2012 to Mar 30, 2013 | {'from': '2012-10-06', 'to': '2013-03-30'} | 24 min. per ep. | PG-13 - Teens 13 or older | 8.67 | 107767 | 50.0 | 426 | 182765 | 2082 | NaN | Fall 2012 | Unknown | {'Adaptation': [{'mal_id': 9711, 'type': 'mang... | NHK, Shueisha | NaN | J.C.Staff | Comedy, Drama, Romance, Shounen | ['#1: "Moshimo no Hanashi (もしもの話)" by nano.RIP... | ['#1: "Pride on Everyday" by Sphere (eps 1-13)... | 24.0 | 2012.0 |
all_anime.image_url[0]
'https://myanimelist.cdn-dena.com/images/anime/12/35893.jpg'
from PIL import Image
import requests
from io import BytesIO
def id_to_image(anime_id):
url = all_anime.loc[all_anime['anime_id']==anime_id, 'image_url'].values[0]
url = url.split('/')
url = ['https://cdn.myanimelist.net'] + url[3:]
url = '/'.join(url)
response = requests.get(url)
img = Image.open(BytesIO(response.content))
return img
id_to_image(12365)
all_anime_small = all_anime.sample(200, random_state=42)
translator = google_translator()
all_anime_small['title_english_new'] = all_anime_small.apply(lambda row: translator.translate(row.title_japanese), axis=1)
all_anime_small.title_english_new.unique()
array(['<Harmony /> Harmony ', 'Pocket Monster Diamond & Pearl Dialga VS Parcia VS Dur Cry ', 'Tokiwa coming! ', 'Crayon Shin-chan Cho ~ Hero of the Cold Call Calling a Storm ', 'Aim for the top! & Top 2! Combine Movie version !! ', 'Great Teacher Onida ', 'White album ', 'Fruit 5 sisters ', 'Love, Chunibyo & Other Delusions! Depth of Field ~ Love and Hatred Theater ', 'Manipulate Dreamnote ', "Dragon Ball Genie Castle's Sleeve Princess ", 'Angel cup ', 'Attack on Titan Omnibus "From that day" ', 'Fire bird 鳳 編 編 ', "Pikachu's sparkling! ", 'Eye Shield 21 Phantom Golden Bowl ', 'Giant God Gogue <Giant Gogg> ', 'My wife is a magic girl ', 'Sengoku Musou SP Sanada chapter ', 'Wolf Fafner Right of Left ~ Single Program ~ ', 'ef - a tale of memories. ~prologue~ ', 'Galactic Hero Legend: My Conqueries of the Stars ', 'Yuuki Yuki is a brave ', 'I enjoyed the firefly ', 'OKAWARI-BOY Starzan S ', 'Pretty Girls Squadron Battle Skipper ', "Digimon Adventure 02 Deer Bellomon's Counterattack ", 'Sixteen sword ', 'DRIFTERS ', "Mori's apron ", 'Sakura capsule ', 'Maria looks like-spring ~ ', "And it's ×! ", 'Negima! ', 'Movie Crayon Shin-chan Very! Kung Fu Boys-Large Noodles Large ', 'Dance with Devils ', 'Akikan! Kang Shiroki!? Hot spring panic ', 'Blackstra ', 'Ala Ta Kangatari-Leather Gods- ', 'Tales of Symphonia Tece Ala Hen again-I want to journal of laughing! ~ ', 'Lady Lady! ! ', 'Cyborg 009 ', 'Astronomical method ', 'Michiko and hatchin ', '2nd ', 'Sin Seven Great Sin Short Animation "Confession" ', 'ARISE -GHOST in The Shell- Border: 2 Ghost Whispers ', 'Movie Pretty Cure All Stars DX2 Hope Light ☆ Protect Rainbage Eell! ', 'Kanedaichi Shonen Case Book R [Returns] ', 'Curtain ROCK ', 'Money Wars Target Waterfront Planning ', 'It is important for magic ', 'Back of important family, its hands. ', 'Dangan Ronpa 3-The End Of Yuki Mine Gakuen-Hope Hen ', "Morino's rice tough ", 'Mob Psycho 100 ', 'St. Liman Sisters Pacopaco Diary The Animation ', 'August 26th ', "Movie version Magical Girl Madoka ☆ Magica Rebellion's Story ", 'Break blade ', "Urawa's style ", 'Gakuen Apocalypse HighSchool of the Dead Drifters of the Dead ', 'UNICO ', 'Maid either ', 'Super Short Comics ', 'Wind Invitation ', 'Minamakebetsu ', 'Rainyman ', 'Machine Hayabusa ', 'Castle Fantasia-Holy Dairy War ~ ', 'ONE ~ To the sparkling season ~ True Stories ', 'Mahoromo Summer TV Special ', 'Tamagotchi! × World Conquest in Tamagotchi ', 'Ponko Tsuranda Saga ', 'Golden Corda BLUE ♪ SKY ', 'Azuki-chan ', 'Movie version Boundaries-I & # 039; LL BE HERE-Postcards "Promise Bonds" Dance PV ', 'TWO-MIX: WHITE REFLECTION ', 'Dimension loop ', 'Make love to me seriously! ', 'Gregory Horror Show-The Blode Karte ', 'Knights Busters Corporation ', 'Shimoon ', 'Ryuga Seven Reservations SD Character Short Movie ', 'Jungle Great Emperor ', 'Chimonal ', 'Amanatsu ', 'Fighting Legend A genius who danced in Akagi darkness ', 'Gate key paz 21 ', 'Golden Hero Gordran ', 'Battery Larline ', 'Mobile Suit Gundam 00 ', 'Ilike Ichi-Lecti, a candidate for an empty battle ', 'Hipila-kun ', 'Detective Conan episode ONE smaller the detective ', 'Laughing target ', 'At the center of the blue world ', 'Ng Knight ムネ ムネ & 40 ', 'Witch Hunter ROBIN ', 'Acupuncturist ', 'Junjo Girl Etosetra ', 'Arcade gamer fluctu ', 'Flame Alpenrose Judy & Randy ', 'Ultrasonic Warrior Bogman ', '"Devilman Crybaby" digest video ', 'Durarara !! × 2 Appendix 4.5 episodes "My heart is pot task" ', 'Nostalgic children ', 'Sendaruta superstan shell orion ', 'Nyanpuku Nyaruma ', 'Rhodes Island Senki Heroes Knight ', 'Magical play: jumping out !! Hanamaru Great Adventure ', 'Galactic Hero Legend Gaiden Helical Labyrinth ', 'Brake angel -Infinity- ', 'Tengen breakthrough Glen Lagan Kirameki ★ Yoko BOX ~ Pieces of Sweet STARS ~ ', 'Tegami Gakuen ', 'Bible Black Only Edition ', 'Hackle Berry Fin Story ', 'DR. Slan!! Summer vacation of exciting heart ', "Harmern's violin play ", 'Sweet Valerian ', 'Tomb ', 'Break the magic ', 'Code Geass Lelouch of the Rebellion ', 'Crayon Shin-chan ', 'Vaulter! ! Matsutaro ', 'Bakemono child ', 'ACCA 13 District Supervision Class ', 'Douro Continent ', 'Secret Association Claws Provided Operation Operation Operation Meeting ', 'Mobile Battleship Nadesico The Prince of Darkness ', 'Initials <Initial> D Battle STAGE ', 'Phantom 〜Requiem for the Phantom〜 ', 'Hidamari sketch ', 'Rozen Maiden Aubertew ', 'Naruto Shippuden ', 'Gokujo. ~ Pole Late Women High Dormitory Story ~ ', 'Movie version Detective Conan 11th striker ', 'Good luck ', 'Nyar Ani Members My Love (Kraft Teacher) ', 'SIN Seven Great Sins Episode 4.5 "The Devil\'s Office ..." ', 'Ryu Oto! ', "Fi Brain ~ God's Puzzle Envades! Rayzel ", 'Tsukiuta. The Animation ', 'Speed grapher ', 'Giant killing ', 'CODE-E ', 'Youth × machine gun ', 'Miracle Girl Limit ', 'Spring girl ', 'Sea tristia ', 'Carnival ', 'Night shift ward ', 'Nontan ', 'Health, (Hells Angels) ', 'U-う 日 日 ', 'Star Driver Shine tact ', 'Pokemon Phantom Pokemon Lugia Bomb ', 'Maiden is in love with me ', 'Taishida Mobius Line Chitty ', 'My sister and its friends are too erotic and my crotch is Yabai ', 'School Girl Strikers Animation Channel ', 'Tokyo Gaple Tourgul [Pinto] ', 'Black Jack Movie version ', 'Three villains of Time Bokan Counterattack ', 'Young trees ', 'Akikan! ', 'A story from "glorious genius" ', 'My three sisters ', 'ARISE -GHOST in the shell- border: 3 ghost tears ', 'Nano core dusk ', 'Seto bride OVA ', 'Grave ', 'Budget ', 'Tutor Hitman REBORN! Bongolemile Total appeared! Bongolian scholarship trip, coming !! ', 'Tomo with animation DVD 1.5 volumes ', 'Service of Victoria Made Maria ', 'Movie Doraemon Nobita Mermaid Battle ', 'Click here for Katsushika-ku Kameni Park in front of the park-The final day Batsu Mitsuyoshi last day- ', "Movie Doraemon Nobita's Antarctic Kachikuchi Great Adventure ", 'There is no money ', "Idrish Seven Special Program Don't look back! ", 'Osomatsu ', 'Fire Journey [Fire Force] Dana Site 999.9 [Fourenain] ', 'Mobile Suit Gundam ', 'Yona ', 'Double-tailed Petit BD & DVD Vol.1 Release Commemorative Hen ', 'Wakaco sake ', 'One Piece! Pirate Baseball King ', 'Aim for the top 2! Diebuster ', 'Dragon Kotaro ', 'Umi things-Coto that you got ', 'Fafner Dead Aggressor Exodus ', 'Super-grave Gravion ', 'Copeperion ', 'Super Health Century Orgas ', 'A sunday without God ', 'Ganslinger Girl-I L TEATRINO-OVA ', 'Siri-pink ', 'A Channel + SMILE (Plus Smile) ', 'ORANGE (orange) '], dtype=object)
name_to_id = pd.Series(list(all_anime['anime_id']), index=all_anime['title'])
aniId_to_index = pd.Series(all_anime.index, index=all_anime['anime_id'])
print("Starting...\n")
# Load the AutoEncoder
model = PredictionEngine()
# Get basic information from the user
age = int(input("Enter Age: "))
gender = input("Enter Gender (Male/Female): ")
input_ratings = OrderedDict()
# Let the user rate some animes
print("\nIt is recommended to rate atleast 5 animes in the beginning.")
print("Note:- Currently search mechanism searches for anime using the Japanese Title only.")
# List for storing the user ratings of recommended table
user_score = []
c = 1
# Start the recommendation process
k1 = input("\nStart the process? [y/n]: ")
while k1 == 'y' or k1 == 'Y':
# If user want to search and rate
k2 = input("\nSearch and rate? [y/n]: ")
while k2 == 'y' or k2 == 'Y':
p = 'n'
while p == 'n' or p == 'N':
input_anime = input("Enter Anime title: ")
flag = find_anime(input_anime.lower(), name_to_id)
if flag==0:
print("\nAnime not found in dataset. Please try searching only a part of the title or another anime!!")
continue
p = input("Anime found? [y/n]: ")
aniId = int(input("Enter anime id: "))
rate = int(input("Your rating (1 - 10): "))
if not type(rate) is int:
raise TypeError("Only integers are allowed")
input_ratings[aniId] = rate
k2 = input("Search and rate more? [y/n]: ")
# Main Game
showRecommendations(age, gender, input_ratings, model, all_anime, aniId_to_index)
# If user want to rate anime from above list
k2 = input("\nRate anime from above list? [y/n]:")
while k2 == 'y' or k2 == 'Y':
aniId = int(input("Enter anime id: "))
rate = int(input("Your rating (1 - 10): "))
input_ratings[aniId] = rate
k2 = input("Rate again from above list? [y/n]: ")
k2 = int(input("Your score for the table of recommended anime (1 - 10):"))
user_score.append([c, k2])
c += 1
k1 = input("\nKeep going? [y/n]: ")
# Displaying the user score over iterations
print('\n\nTable of user scores')
table = tabulate(user_score, headers=['Iterations', 'User Score'], tablefmt='grid')
print(table)
Starting... Enter Age: 25 Enter Gender (Male/Female): Male It is recommended to rate atleast 5 animes in the beginning. Note:- Currently search mechanism searches for anime using the Japanese Title only. Start the process? [y/n]: y Search and rate? [y/n]: y Enter Anime title: magic Anime Id Title 33358 Mahou no Star Magical Emi: Finale! Finale! 23831 Mahou Shoujo Madoka★Magica Movie 3: Hangyaku no Monogatari - Magica Quartet x Nisioisin 2038 Mahou no Star Magical Emi 30030 Jewelpet Magical Change 5080 Quiz Magic Academy: The Original Animation 4017 Magical Moe 36760 Detective Conan: The Magician of Starlight 8443 Mahou no Star Magical Emi: Semishigure 941 Renkin San-kyuu Magical? Pokaan 34104 Knight's & Magic 1367 Detective Conan Movie 08: Magician of the Silver Sky 17725 Magical☆Star Kanon 100% 11979 Mahou Shoujo Madoka★Magica Movie 2: Eien no Monogatari 11981 Mahou Shoujo Madoka★Magica Movie 3: Hangyaku no Monogatari 8310 Magic Kaito 1563 Magic Knight Rayearth II 18115 Magi: The Kingdom of Magic 1489 Renkin San-kyuu Magical? Pokaan Specials 9506 Prism Magical: Prism Generations! 33299 Magic-Kyun! Renaissance 349 Magical Canan 11977 Mahou Shoujo Madoka★Magica Movie 1: Hajimari no Monogatari 9756 Mahou Shoujo Madoka★Magica 10690 Magic Tree House 15915 Magical Hat 1270 Black Magic M-66 14513 Magi: The Labyrinth of Magic 435 Magic Knight Rayearth 25517 Magic Kaito 1412 7549 Quiz Magic Academy: The Original Animation 2 2369 Rental Magica 5274 Magical★Taruruuto-kun 15407 Magical Suite Prism Nana 32153 Mahou Shoujo Madoka★Magica: Concept Movie Anime found? [y/n]: y Enter anime id: 10690 Your rating (1 - 10): 7 Search and rate more? [y/n]: y Enter Anime title: play Anime Id Title 3768 Play Ball Anime found? [y/n]: y Enter anime id: 3768 Your rating (1 - 10): 6 Search and rate more? [y/n]: y Enter Anime title: good Anime Id Title 31699 Good Morning!!! Doronjo 8626 Good Morning 1056 Good Morning Call Anime found? [y/n]: y Enter anime id: 31699 Your rating (1 - 10): 8 Search and rate more? [y/n]: y Enter Anime title: scare Anime Id Title 33113 Scared Rider Xechs 4684 Scarecrowman Anime found? [y/n]: y Enter anime id: 4684 Your rating (1 - 10): 9 Search and rate more? [y/n]: y Enter Anime title: ice Anime Id Title 74 Gakuen Alice 34350 Alice to Zouroku 33687 Cyborg 009: Call of Justice 3 16021 Miracle Psychicer Seizan 35382 Yuri!!! on Ice: Yuri Plisetsky GPF in Barcelona EX - Welcome to The Madness 117 El Hazard: The Magnificent World 30066 L/R: Licensed by Royal Special 35914 Catchy-kun no Nice Catch! 26359 Persona 4 the Golden Animation: Thank you Mr. Accomplice 27969 Hana to Alice: Satsujin Jiken 10832 Ikoku Meiro no Croisée: Yune & Alice 31633 Sushi Police 33685 Cyborg 009: Call of Justice 1 29317 Saenai Heroine no Sodatekata: Ai to Seishun no Service-kai 21305 Trick or Alice 1346 AD Police 33686 Cyborg 009: Call of Justice 2 36803 Servamp Movie: Alice in the Garden 2169 Ice 4713 Heart no Kuni no Alice: Wonderful Wonder World 35818 Love Kome: We Love Rice 2nd Season 1180 Hyper Police 36096 Ice Fist 32548 Imawa no Kuni no Alice 5646 Deep Voice 32995 Yuri!!! on Ice 2572 Fushigi no Kuni no Alice 34402 Love Kome: We Love Rice 1477 City Hunter: The Secret Service 1456 L/R: Licensed by Royal 118 El Hazard 2: The Magnificent World 577 Kagihime Monogatari Eikyuu Alice Rinbukyoku 2725 Tenchi Muyou!: Galaxy Police Mihoshi Space Adventure 36001 Alice or Alice: Siscon Niisan to Futago no Imouto 29093 Grisaia no Meikyuu: Caprice no Mayu 0 29837 Yakushiji Ryouko no Kaiki Jikenbo: Hamachou, Voice & Fiction 8812 Alice SOS 24781 Imawa no Kuni no Alice (OVA) 10849 Shinryaku! Ika Musume: Ika Ice Tabena-ika? 2056 Cosmo Police Justy 35338 Saenai Heroine no Sodatekata ♭: Koi to Junjou no Service-kai 18119 Servant x Service Anime found? [y/n]: y Enter anime id: 2056 Your rating (1 - 10): 7 Search and rate more? [y/n]: y Enter Anime title: play Anime Id Title 3768 Play Ball Anime found? [y/n]: n Enter Anime title: time Anime Id Title 1933 Growlanser IV: Wayfarer of the Time 1194 Coyote Ragtime Show 779 Detective Conan Movie 01: The Timed Skyscraper 17895 Golden Time 35254 Time Bokan: Gyakushuu no San Akunin 37665 Yoshida no Time Slip Fumai-kou 33341 Time Travel Shoujo: Mari Waka to 8-nin no Kagakusha-tachi 37051 Petit☆Dream Stars! Let's La Cooking? Showtime! 33845 Free! Movie 1: Timeless Medley - Kizuna 35191 Free! Movie 2: Timeless Medley - Yakusoku 10178 Otona Joshi no Anime Time 677 Sentimental Journey 33142 Re:Zero kara Hajimeru Break Time 2820 Time Travel Tondekeman! 32174 The iDOLM@STER Cinderella Girls: Anytime, Anywhere with Cinderella. 3915 Time Bokan 9393 T.P. Sakura: Time Paladin Sakura 1689 Byousoku 5 Centimeter 34787 Idol Time PriPara 33026 Time Bokan 24 25491 Megumi to Taiyou III: Kajuu Gummi Tweet Fantasy - Timeline World 34776 Eureka Seven AO Final Episode: One More Time - Lord Don't Slow Me Down 14991 Harem Time The Animation 37859 Free! Movie 2: Timeless Medley - Yakusoku: Character Butai Aisatsu 37858 Free! Movie 1: Timeless Medley - Kizuna: Character Butai Aisatsu Anime found? [y/n]: y Enter anime id: 37858 Your rating (1 - 10): 9 Search and rate more? [y/n]: n similar Anime | Anime ID | JP Title | EN Title | Genre | |------------+----------------------------------------+-------------------------------------------+--------------------------------------------------------| | 1724 | Saint October | nan | Adventure, Fantasy | | 1771 | Ring ni Kakero 1: Nichibei Kessen-hen | Ring ni Kakero 1 Episode: The Pacific War | Action, Sports, Shounen | | 1155 | Melty Lancer | nan | Adventure, Comedy, Sci-Fi, Space | | 2723 | D4 Princess | nan | Action, Sci-Fi, Comedy, Magic, Mecha | | 8353 | Ketsuinu | nan | Comedy | | 980 | Rikujou Bouei-tai Mao-chan | Ground Defense Force! Mao-chan | Comedy, Kids, Magic, Military, Sci-Fi | | 6331 | Ten Little Gall Force | nan | Action, Military, Sci-Fi, Space, Comedy, Parody, Mecha | | 36204 | Tokimeki Restaurant☆☆☆ MIRACLE6 Movie | nan | Music, Romance | | 2781 | Saint Luminous Jogakuin | St. Luminous Mission High School | Mystery, Psychological, Supernatural | | 15545 | Oshiri Kajiri Mushi (TV) | Bottom Biting Bug | Comedy, Kids | Anime You May Like | Anime ID | JP Title | EN Title | Genre | |------------+------------------------------------------------+-----------------------------------------+------------------------------------------------------| | 30851 | Q Transformers: Saranaru Ninki Mono e no Michi | nan | Slice of Life, Parody, Mecha | | 33473 | Tokyo Futago Athletic | Tokyo Twins Athletic Tournament | Comedy, Sports | | 5267 | Gamba no Bouken | Adventure of Gamba | Adventure, Kids | | 7308 | Mirai Shounen Conan (Movie) | Future Boy Conan Movie | Adventure, Drama, Sci-Fi | | 35805 | Cinderella Girls Gekijou Specials | THE IDOLM@STER CINDERELLA GIRLS Theater | Slice of Life, Comedy | | 3281 | Kinnikuman: Kinnikusei Oui Soudatsu-hen | nan | Action, Comedy, Sports, Shounen | | 16009 | Kamisama no Inai Nichiyoubi | Sunday Without God | Fantasy, Mystery | | 2092 | Kiss wa Hitomi ni Shite | nan | Comedy, Romance, Shoujo | | 7904 | Kemono no Souja Erin Recap | nan | Adventure, Slice of Life, Historical, Drama, Fantasy | | 1537 | Genshi Shounen Ryuu | Ryu the Primitive Boy | Action, Sci-Fi, Adventure, Romance, Shounen | Rate anime from above list? [y/n]:n Your score for the table of recommended anime (1 - 10):6 Keep going? [y/n]: n Table of user scores +--------------+--------------+ | Iterations | User Score | +==============+==============+ | 1 | 6 | +--------------+--------------+
rated_anime = [10690, 3768, 31699, 2056, 37858]
ratings = [7, 6, 8, 7, 9]
rated_anime_images = [id_to_image(id) for id in rated_anime]
plt.figure(figsize=(20,10))
columns = 5
for i, image in enumerate(rated_anime_images):
plt.subplot(len(rated_anime_images) / columns + 1, columns, i + 1)
plt.gca().set_title(ratings[i])
plt.imshow(image)
similar_anime = [1724, 1771, 1155, 2723, 8353]
similar_anime_images = [id_to_image(id) for id in similar_anime]
plt.figure(figsize=(20,10))
columns = 5
for i, image in enumerate(similar_anime_images):
plt.subplot(len(similar_anime_images) / columns + 1, columns, i + 1)
plt.imshow(image)
personalized_anime = [30851, 33473, 5267, 7308, 35805]
personalized_anime_images = [id_to_image(id) for id in personalized_anime]
plt.figure(figsize=(20,10))
columns = 5
for i, image in enumerate(personalized_anime_images):
plt.subplot(len(personalized_anime_images) / columns + 1, columns, i + 1)
plt.imshow(image)