機械学習で作る映画・アニメ推薦システム完全ガイド【Python実装例付き】

 

はじめに

NetflixやAmazon Prime Videoなどの動画配信サービスで「あなたにおすすめ」として表示される作品は、どのように選ばれているのでしょうか?その背景には機械学習を活用した高度な推薦システムが存在します。

本記事では、機械学習を使った映画・アニメ推薦システムの構築方法を、初心者にもわかりやすく解説します。実際のPythonコード例も交えながら、推薦システムの仕組みから実装まで詳しく説明していきます。

推薦システムとは?

推薦システム(レコメンドシステム)とは、ユーザーの過去の行動データや嗜好を分析して、そのユーザーが興味を持ちそうなコンテンツを自動的に提案するシステムです。

推薦システムの種類

推薦システムには主に以下の3つのアプローチがあります:

1. 協調フィルタリング(Collaborative Filtering)

  • ユーザー間の類似性に基づいて推薦
  • 「似たようなユーザーが好きな作品を推薦」

2. コンテンツベースフィルタリング(Content-based Filtering)

  • アイテムの特徴に基づいて推薦
  • 「過去に見たアクション映画に似た作品を推薦」

3. ハイブリッド型

  • 上記2つの手法を組み合わせた推薦

協調フィルタリングの実装

最も一般的な協調フィルタリングから実装してみましょう。

必要なライブラリのインストール

pip install pandas numpy scikit-learn matplotlib seaborn

サンプルデータの準備

import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

# サンプル評価データの作成
ratings_data = {
    'user_id': [1,1,1,2,2,2,3,3,3,4,4,4],
    'movie_id': [101,102,103,101,102,104,102,103,104,101,103,104],
    'rating': [5,4,3,4,5,2,3,4,5,5,3,4]
}

ratings_df = pd.DataFrame(ratings_data)
print(ratings_df.head())

ユーザー-アイテム行列の作成

# ユーザー-アイテム行列を作成
user_item_matrix = ratings_df.pivot_table(
    index='user_id', 
    columns='movie_id', 
    values='rating'
).fillna(0)

print("ユーザー-アイテム行列:")
print(user_item_matrix)

コサイン類似度による推薦

# ユーザー間の類似度を計算
user_similarity = cosine_similarity(user_item_matrix)
user_sim_df = pd.DataFrame(
    user_similarity, 
    index=user_item_matrix.index, 
    columns=user_item_matrix.index
)

def recommend_movies(user_id, num_recommendations=3):
    # 対象ユーザーと他ユーザーの類似度を取得
    user_sim_scores = user_sim_df[user_id].sort_values(ascending=False)
    
    # 最も似ているユーザーを特定(自分以外)
    similar_user = user_sim_scores.drop(user_id).index[0]
    
    # 類似ユーザーが高評価した映画を取得
    similar_user_ratings = user_item_matrix.loc[similar_user]
    target_user_ratings = user_item_matrix.loc[user_id]
    
    # 未視聴で高評価の映画を推薦
    recommendations = []
    for movie_id in similar_user_ratings.index:
        if target_user_ratings[movie_id] == 0 and similar_user_ratings[movie_id] > 3:
            recommendations.append((movie_id, similar_user_ratings[movie_id]))
    
    return sorted(recommendations, key=lambda x: x[1], reverse=True)[:num_recommendations]

# ユーザー1への推薦
recommendations = recommend_movies(1)
print(f"ユーザー1への推薦映画: {recommendations}")

行列因子分解による高度な推薦

より精度の高い推薦システムには、行列因子分解を使用します。

from sklearn.decomposition import NMF

# 非負値行列因子分解(NMF)を使用
nmf_model = NMF(n_components=2, random_state=42)
user_features = nmf_model.fit_transform(user_item_matrix)
item_features = nmf_model.components_

# 予測評価値を計算
predicted_ratings = np.dot(user_features, item_features)
predicted_df = pd.DataFrame(
    predicted_ratings,
    index=user_item_matrix.index,
    columns=user_item_matrix.columns
)

def nmf_recommend(user_id, num_recommendations=3):
    user_pred = predicted_df.loc[user_id]
    user_actual = user_item_matrix.loc[user_id]
    
    # 未視聴映画の予測評価値でソート
    unrated_movies = user_pred[user_actual == 0].sort_values(ascending=False)
    
    return unrated_movies.head(num_recommendations).to_dict()

# NMFによる推薦
nmf_recs = nmf_recommend(1)
print(f"NMF推薦結果: {nmf_recs}")

コンテンツベースフィルタリングの実装

映画の特徴情報を使った推薦システムも作成してみましょう。

# 映画の特徴データ
movies_data = {
    'movie_id': [101, 102, 103, 104],
    'title': ['アクション映画A', 'コメディ映画B', 'ドラマ映画C', 'アニメ映画D'],
    'genre': ['アクション', 'コメディ', 'ドラマ', 'アニメ'],
    'year': [2020, 2019, 2021, 2022]
}

movies_df = pd.DataFrame(movies_data)

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import cosine_similarity

# ジャンル特徴量をベクトル化
vectorizer = CountVectorizer()
genre_matrix = vectorizer.fit_transform(movies_df['genre'])

# 映画間の類似度を計算
movie_similarity = cosine_similarity(genre_matrix)

def content_based_recommend(movie_id, num_recommendations=2):
    # 映画のインデックスを取得
    movie_idx = movies_df[movies_df['movie_id'] == movie_id].index[0]
    
    # 類似度スコアを取得
    sim_scores = list(enumerate(movie_similarity[movie_idx]))
    sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)
    
    # 上位類似映画を取得(自分以外)
    similar_movies = sim_scores[1:num_recommendations+1]
    movie_indices = [i[0] for i in similar_movies]
    
    return movies_df.iloc[movie_indices][['movie_id', 'title']]

# コンテンツベース推薦
content_recs = content_based_recommend(101)
print("コンテンツベース推薦:")
print(content_recs)

推薦システムの評価方法

推薦システムの性能を測定するための主要な評価指標:

1. RMSE(平均二乗平方根誤差)

from sklearn.metrics import mean_squared_error
import math

def calculate_rmse(actual, predicted):
    mse = mean_squared_error(actual, predicted)
    rmse = math.sqrt(mse)
    return rmse

# 実際の評価値と予測値でRMSE計算
actual_ratings = [4, 5, 3, 2]
predicted_ratings = [4.1, 4.8, 3.2, 2.1]
rmse = calculate_rmse(actual_ratings, predicted_ratings)
print(f"RMSE: {rmse:.3f}")

2. 精度(Precision)と再現率(Recall)

def calculate_precision_recall(recommended, relevant):
    recommended_set = set(recommended)
    relevant_set = set(relevant)
    
    intersection = recommended_set.intersection(relevant_set)
    
    precision = len(intersection) / len(recommended_set) if recommended_set else 0
    recall = len(intersection) / len(relevant_set) if relevant_set else 0
    
    return precision, recall

# 推薦された映画と実際に好きな映画
recommended_movies = [101, 102, 103]
relevant_movies = [101, 104, 105]

precision, recall = calculate_precision_recall(recommended_movies, relevant_movies)
print(f"精度: {precision:.3f}, 再現率: {recall:.3f}")

実用的な推薦システムの構築

より実践的なシステムを構築するためのポイント:

データの前処理

# 評価データのクリーニング
def preprocess_ratings(ratings_df):
    # 評価数が少ないユーザー・映画を除外
    min_ratings = 5
    
    # ユーザーごとの評価数をカウント
    user_counts = ratings_df['user_id'].value_counts()
    valid_users = user_counts[user_counts >= min_ratings].index
    
    # 映画ごとの評価数をカウント
    movie_counts = ratings_df['movie_id'].value_counts()
    valid_movies = movie_counts[movie_counts >= min_ratings].index
    
    # フィルタリング
    filtered_df = ratings_df[
        (ratings_df['user_id'].isin(valid_users)) &
        (ratings_df['movie_id'].isin(valid_movies))
    ]
    
    return filtered_df

冷間始動問題への対応

def handle_cold_start(user_id, user_demographics, popular_movies):
    """新規ユーザーに人気映画を推薦"""
    if user_id not in user_item_matrix.index:
        # 人気映画から年齢層に適した作品を推薦
        age_group = user_demographics.get('age_group', 'adult')
        
        if age_group == 'teen':
            return popular_movies['teen'][:5]
        elif age_group == 'adult':
            return popular_movies['adult'][:5]
        else:
            return popular_movies['general'][:5]

推薦システムの性能向上のコツ

1. 特徴量エンジニアリング

# 時間的要素を考慮した重み付け
def time_weighted_rating(rating, days_ago):
    decay_factor = 0.95
    return rating * (decay_factor ** (days_ago / 30))

# ユーザーの評価傾向を正規化
def normalize_user_ratings(ratings):
    user_mean = ratings.mean()
    user_std = ratings.std()
    return (ratings - user_mean) / user_std

2. アンサンブル手法

def ensemble_recommend(user_id, collaborative_recs, content_recs, weights=[0.7, 0.3]):
    """複数の推薦手法を組み合わせ"""
    final_scores = {}
    
    # 協調フィルタリングの結果に重み付け
    for movie_id, score in collaborative_recs.items():
        final_scores[movie_id] = weights[0] * score
    
    # コンテンツベースの結果を追加
    for movie_id, score in content_recs.items():
        if movie_id in final_scores:
            final_scores[movie_id] += weights[1] * score
        else:
            final_scores[movie_id] = weights[1] * score
    
    return sorted(final_scores.items(), key=lambda x: x[1], reverse=True)

まとめ

機械学習を活用した映画・アニメ推薦システムの構築について解説しました。重要なポイントは以下の通りです:

推薦手法の選択

  • 協調フィルタリング:ユーザー行動データが豊富な場合に効果的
  • コンテンツベース:新しいアイテムにも対応可能
  • ハイブリッド:両手法の利点を活用

実装時の注意点

  • データの前処理とクリーニングが重要
  • 冷間始動問題への対策
  • 評価指標による性能測定
  • リアルタイム性とスケーラビリティの考慮

性能向上のテクニック

  • 特徴量エンジニアリング
  • アンサンブル手法
  • 時系列データの活用
  • ユーザーフィードバックの反映

推薦システムは継続的な改善が必要なシステムです。ユーザーの行動データを蓄積し、定期的にモデルを更新することで、より精度の高い推薦が可能になります。

本記事のサンプルコードを参考に、あなたも機械学習を活用した推薦システムの構築にチャレンジしてみてください。

■テックジム「AIエンジニア養成コース」

■プロンプトだけでオリジナルアプリを開発・公開してみた!!

■AI時代の第一歩!「AI駆動開発コース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<オンライン無料>ゼロから始めるPython爆速講座