Bikin Projek AI Untuk Rekomendasi Anime
Proyek ini bertujuan untuk mengembangkan sistem rekomendasi berbasis kolaborasi untuk anime. Sistem ini memanfaatkan data pengguna dan anime untuk merekomendasikan anime yang relevan.
Project Overview
Proyek ini penting karena:
Anime memiliki basis penggemar yang luas, dan sistem rekomendasi dapat meningkatkan pengalaman pengguna dalam menemukan konten yang mereka sukai.
Dengan semakin banyaknya pilihan, rekomendasi yang akurat membantu pengguna mengurangi waktu pencarian.
Business Understanding
Problem Statements
Bagaimana cara merekomendasikan anime kepada pengguna berdasarkan preferensi mereka?
Bagaimana mengidentifikasi anime yang serupa dengan anime yang telah ditonton oleh pengguna?
Goals
Memberikan rekomendasi anime yang relevan berdasarkan preferensi pengguna.
Mengidentifikasi anime yang serupa dengan anime favorit pengguna untuk rekomendasi yang lebih personal.
Solution Approach
Collaborative Filtering Berbasis Pengguna: Menggunakan kemiripan antar pengguna untuk merekomendasikan anime.
Collaborative Filtering Berbasis Item: Menggunakan kemiripan antar item (anime) untuk memberikan rekomendasi.
Data Understanding
Dataset yang digunakan:
Anime Recommendations Database https://www.kaggle.com/datasets/CooperUnion/anime-recommendations-database
import kagglehub
path = kagglehub.dataset_download("CooperUnion/anime-recommendations-database")
import shutil
shutil.move(path, "dataset")
import pandas as pd
base_anime_df = pd.read_csv("dataset/anime.csv")
base_rating_df = pd.read_csv("dataset/rating.csv")
Dataset terdiri dari dua file:
Anime Dataset
anime_id: ID unik untuk setiap anime.
name: Nama lengkap anime.
genre: Daftar genre anime.
type: Jenis anime (TV, movie, OVA, dll).
episodes: Jumlah episode.
rating: Rating rata-rata (1-10).
members: Jumlah anggota komunitas untuk anime tersebut.
Anime Dataset memiliki 12294 baris data dengan missing value pada beberapa kolom namun tanpa data duplikat.
Rating Dataset
user_id: ID unik pengguna.
anime_id: ID anime yang diberi rating.
rating: Rating yang diberikan pengguna (-1 untuk "ditonton tetapi tidak diberi rating").
Rating dataset memiliki 7813737 baris data. Tidak terdapat missing value namun terdapat data duplikat
Data Preparation
Menghapus Nilai Null dan Duplikat: Nilai null dan data duplikat dihapus untuk memastikan data yang bersih.
anime_df.dropna(inplace=True) anime_df.reset_index(inplace=True) rating_df.dropna(inplace=True) rating_df.reset_index(inplace=True)
Menghapus nilai -1 para Rating: Mengubah nilai -1 pada kolom rating menjadi NaN dan menghapusnya.
rating_df['rating'].replace(-1, float('NaN'), inplace=True) rating_df.dropna(inplace=True)
Encoding Genre: Genre diubah ke format one-hot encoding karena setiap anime dapat memiliki lebih dari satu genre.
from sklearn.preprocessing import LabelEncoder from sklearn.preprocessing import MultiLabelBinarizer anime_df['genre_list'] = anime_df['genre'].dropna().apply(lambda x: x.split(', ')) mlb = MultiLabelBinarizer() genre_encoded = mlb.fit_transform(anime_df['genre_list']) genre_anime_df = pd.DataFrame(genre_encoded, columns=mlb.classes_) anime_df = pd.concat([anime_df, genre_anime_df], axis=1) le = LabelEncoder() anime_df['type'] = le.fit_transform(anime_df['type']) anime_df['rating'] = pd.to_numeric(anime_df['rating']) anime_df.to_csv('dataset/anime_clean.csv')
Menggabungkan Dataset: Dataset anime dan rating digabungkan untuk analisis lebih lanjut.
join_df = pd.merge(rating_df, anime_df[['anime_id', 'rating']], on='anime_id') join_df.to_csv('dataset/join_df.csv')
Membuat pivot table: Data yang sudah digabung dibuat pivot table antara user dan anime dengan value ratingnya.
import pandas as pd import numpy as np data = pd.read_csv('dataset/join_df.csv') anime_df_clean = pd.read_csv('dataset/anime_clean.csv') user_item_matrix = data.pivot_table(index='user_id', columns='anime_id', values='rating_x').fillna(0)
Membuat dataframe Non Zero Count: Membuat dataframe baru dari pivot table kemudian hanya diambil data user yang pernah merating anime atau count dari ratingnya lebih besar dari 0.
non_zero_counts = (user_item_matrix != 0).sum(axis=1)
Filter data: Data di filter berdasarkan aktivitas user yang sudah merating lebih dari sama dengan 250 anime. Hal ini dilakukan untuk mengefisiensikan memori.
filtered_matrix = user_item_matrix[non_zero_counts >= 250]
Modeling
from sklearn.metrics.pairwise import cosine_similarity
user_similarity = cosine_similarity(filtered_matrix)
item_similarity = cosine_similarity(filtered_matrix.T)
Pendekatan Collaborative Filtering Berbasis Pengguna
Menggunakan kemiripan cosine antar pengguna untuk merekomendasikan anime berdasarkan pengguna lain yang memiliki preferensi serupa. Cara Kerja Algoritma ini adalah:
Memeriksa Validitas Pengguna
Memastikan apakah `user_id` yang diberikan ada dalam dataset. Jika tidak, kembalikan daftar kosong.
Mencari Pengguna yang Mirip
Menggunakan Cosine Similarity untuk menghitung skor kemiripan antar pengguna.
Memilih `n_users` pengguna yang paling mirip dengan `user_id` yang diberikan.
Mengidentifikasi Item yang Dirating dan Belum Dirating
Item yang Sudah Dirating: Item yang telah dirating oleh pengguna.
Item yang Belum Dirating: Item yang belum dirating oleh pengguna (calon untuk direkomendasikan).
Membuat Rekomendasi
Untuk setiap item yang belum dirating:
Periksa rating dari pengguna lain yang mirip.
Hitung rata-rata rating jika ada pengguna mirip yang telah merating item tersebut.
Tambahkan item ke daftar rekomendasi jika rata-rata rating > 7.
Urutkan item rekomendasi berdasarkan rata-rata rating dari yang tertinggi.
Mengambil Detail Item yang Direkomendasikan
Ambil detail (misalnya, judul, genre) dari `n_items` rekomendasi terbaik berdasarkan dataset anime.
Menghitung Relevansi Rekomendasi
Gunakan Cosine Similarity untuk membandingkan fitur item yang sudah dirating dengan item yang direkomendasikan.
Kembalikan skor rata-rata kemiripan (`avg_cosine_similarity`) sebagai ukuran relevansi.
def get_similar_users_recommendations(user_id, n_users=5, n_items=10): if user_id not in filtered_matrix.index: return [] user_idx = filtered_matrix.index.get_loc(user_id) list_similar_users = user_similarity[user_idx].argsort()[::-1][1:n_users+1] list_user_rated_item_id = filtered_matrix.columns[filtered_matrix.loc[user_id] != 0] list_rated_anime = anime_df_clean[anime_df_clean['anime_id'].isin(list_user_rated_item_id)] list_user_unrated_item_id = filtered_matrix.columns[filtered_matrix.loc[user_id] == 0] list_recommendation_items = [] for item_id in list_user_unrated_item_id: item_ratings = [] for similar_user_idx in list_similar_users: similar_user_id = filtered_matrix.index[similar_user_idx] rating = filtered_matrix.loc[similar_user_id, item_id] if rating > 0: item_ratings.append(rating) if item_ratings: avg_rating = sum(item_ratings) / len(item_ratings) if avg_rating > 7: list_recommendation_items.append((item_id, avg_rating)) list_recommendation_items.sort(key=lambda x: x[1], reverse=True) anime_ids = [item[0] for item in list_recommendation_items[:n_items]] list_rekomendasi_anime = anime_df_clean[anime_df_clean['anime_id'].isin(anime_ids)] # Menghitung kesamaan rata-rata Cosine similarities = cosine_similarity(list_rated_anime.iloc[:, 10:], list_rekomendasi_anime.iloc[:, 10:]) max_similarity_indices = np.argmax(similarities, axis=0) highest_similarity_rows = list_rated_anime.iloc[max_similarity_indices] highest_similarity_rows['max_similarity'] = similarities[max_similarity_indices, range(similarities.shape[1])] avg_cosine_similarity = np.mean(similarities) return list_rekomendasi_anime, avg_cosine_similarity, highest_similarity_rows
Pendekatan Collaborative Filtering Berbasis Item:
Menggunakan kemiripan cosine antar item untuk merekomendasikan anime yang serupa dengan yang telah dinilai oleh pengguna. Cara Kerja Algoritma ini adalah:
Memeriksa Validitas Pengguna
Memastikan apakah `user_id` yang diberikan ada dalam dataset. Jika tidak, kembalikan daftar kosong.
Mengidentifikasi Item yang Dirated dan Belum Dirated
Item yang Dirated: Item yang telah dirating oleh pengguna.
Item yang Belum Dirated: Item yang belum dirating oleh pengguna (calon untuk direkomendasikan).
Menghitung Skor Item yang Belum Dirated
Untuk setiap item yang belum dirated:
Hitung kemiripan antara item tersebut dan setiap item yang telah dirated oleh pengguna menggunakan Cosine Similarity.
Bobot skor dihitung sebagai hasil kali kemiripan dengan rating pengguna pada item yang mirip.
Total skor dihitung dengan menjumlahkan skor bobot, dan skor dinormalisasi berdasarkan total kemiripan.
Mengurutkan dan Memilih Rekomendasi
Urutkan item yang belum dirated berdasarkan skor tertinggi.
Pilih hingga `n_items` rekomendasi terbaik.
Mengambil Detail Item Rekomendasi
Ambil detail (misalnya, judul, genre) dari rekomendasi item menggunakan dataset anime.
Menghitung Relevansi Rekomendasi
Gunakan Cosine Similarity untuk membandingkan fitur item yang telah dirated dengan item yang direkomendasikan.
Hitung rata-rata kemiripan (`avg_cosine_similarity`) sebagai ukuran relevansi.
def get_similar_items_recommendations(user_id, n_items=10): if user_id not in filtered_matrix.index: return [] user_rated_items = filtered_matrix.columns[filtered_matrix.loc[user_id] > 0] list_rated_anime = anime_df_clean[anime_df_clean['anime_id'].isin(user_rated_items)] user_unrated_items = filtered_matrix.columns[filtered_matrix.loc[user_id] == 0] item_scores = {} for unrated_item in user_unrated_items: score = 0 total_similarity = 0 for rated_item in user_rated_items: similarity = item_similarity[filtered_matrix.columns.get_loc(rated_item)][filtered_matrix.columns.get_loc(unrated_item)] user_rating = filtered_matrix.loc[user_id, rated_item] score += similarity * user_rating total_similarity += abs(similarity) # Menghitung rata-rata similarity # avg_similarity = total_similarity / len(user_rated_items) if len(user_rated_items) > 0 else 0 if total_similarity > 0: item_scores[unrated_item] = score * total_similarity # Urutkan dan ambil n item teratas recommendations = sorted(item_scores.items(), key=lambda x: x[1], reverse=True) anime_ids = [item[0] for item in recommendations[:n_items]] list_rekomendasi_anime = anime_df_clean[anime_df_clean['anime_id'].isin(anime_ids)] # # Menghitung kesamaan rata-rata Cosine similarities = cosine_similarity(list_rated_anime.iloc[:, 10:], list_rekomendasi_anime.iloc[:, 10:]) max_similarity_indices = np.argmax(similarities, axis=0) highest_similarity_rows = list_rated_anime.iloc[max_similarity_indices] highest_similarity_rows['max_similarity'] = similarities[max_similarity_indices, range(similarities.shape[1])] avg_cosine_similarity = np.mean(similarities) return list_rekomendasi_anime, avg_cosine_similarity, highest_similarity_rows
Evaluation
Evaluasi Precission:
Metriks Evaluasi yang digunakan yakni presisi, dengan membagi jumlah item yang relevan dengan jumlah item yang direkomendasikan. Item yang relevan ditentukan dari item yang sudah di rating dan memiliki kemiripan paling tinggi. Perhitungan relevansi dinilai dari genre antara itemnya dengan threshold 95% dari total genre yang sesuai dianggap relevan.
def countPrecission(total_relevant_item, total_recommendation):
precission = total_relevant_item / total_recommendation
return precission
pd.options.mode.chained_assignment = None
data_uji = filtered_matrix.index[:10]
Rekomendasi Berdasarkan Pengguna:
precis = []
for idx in data_uji:
recommendation_user, kemiripan_by_user, highest_similarity_rows = get_similar_users_recommendations(idx)
highest_similarity_rows_genre = highest_similarity_rows.iloc[:, 10:-1]
highest_similarity_rows_genre = highest_similarity_rows_genre.reset_index()
highest_similarity_rows_genre.drop('index', axis=1, inplace=True)
recommendation_user_genre = recommendation_user.iloc[:,10:]
recommendation_user_genre = recommendation_user_genre.reset_index()
recommendation_user_genre.drop('index', axis=1, inplace=True)
threshold = len(recommendation_user_genre.columns) * 0.95
relevant_item = highest_similarity_rows_genre[highest_similarity_rows_genre.apply(lambda row: (recommendation_user_genre.iloc[row.name] == row).sum() > threshold, axis=1)]
precission = countPrecission(len(relevant_item), 10)
precis.append(precission)
print(f"Precission: {precission}")
print(f"Rata-rata Precission: {sum(precis)/len(precis)}")
Hasil evaluasi menunjukkan:
berhasil memberikan 10 rekomendasi anime.
Evaluasi presisi dari hasil rekomendasi menunjukan nilai 0.69
Rekomendasi ini didasarkan pada kemiripan dengan pengguna lain yang memiliki preferensi rating yang serupa.
Rekomendasi Berdasarkan Item:
precis = []
for idx in data_uji:
recommendation_item, kemiripan_by_item, highest_similarity_rows = get_similar_items_recommendations(5)
highest_similarity_rows_genre = highest_similarity_rows.iloc[:, 10:-1]
highest_similarity_rows_genre = highest_similarity_rows_genre.reset_index()
highest_similarity_rows_genre.drop('index', axis=1, inplace=True)
recommendation_item_genre = recommendation_item.iloc[:,10:]
recommendation_item_genre = recommendation_item_genre.reset_index()
recommendation_item_genre.drop('index', axis=1, inplace=True)
threshold = len(recommendation_item_genre.columns) * 0.95
relevant_item = highest_similarity_rows_genre[highest_similarity_rows_genre.apply(lambda row: (recommendation_item_genre.iloc[row.name] == row).sum() > threshold, axis=1)]
precission = countPrecission(len(relevant_item), 10)
precis.append(precission)
print(f"Precission: {precission}")
print(f"Rata-rata Precission: {sum(precis)/len(precis)}")
Hasil evaluasi menunjukkan:
berhasil memberikan 10 rekomendasi anime untuk pengguna yang sama.
Evaluasi presisi dari hasil rekomendasi menunjukan nilai 0.6.
Rekomendasi ini didasarkan pada kemiripan antara anime yang telah dinilai oleh pengguna dan anime yang belum dinilai.
Secara keseluruhan, kedua metode rekomendasi (berbasis pengguna dan item) memberikan hasil yang dapat digunakan untuk membantu pengguna menemukan anime baru yang mungkin mereka sukai berdasarkan preferensi mereka dan perilaku pengguna lain.