概要
- 目的:協調フィルタリング(User-based CF)の仕組みをPythonで理解し、教育分野でのパーソナライズ学習への応用を探る
- 手法:MovieLensデータセットを用い、ユーザー間コサイン類似度とMAEで評価
- 学び:レコメンドは単なるアルゴリズムではなく、学習支援や教材最適化の基盤になり得る
はじめに
業務でレコメンドを扱うことはありませんが、
生徒の探究活動の中で「レコメンドの仕組み」について研究している生徒がいたため、
私自身も理解を深める目的で学んでみることにしました。
データ分析や教育分野では「パーソナライズ」がキーワードになることも多く、
この分野の基礎を押さえておくことは今後の教育DXにも役立つと考えています。
今回は、教育現場での探究にも応用できそうなレコメンドの基本原理を、
Pythonと公開データセットを使って実装しました。
目的
- MovieLensデータセットを用いて、**協調フィルタリング(User-based CF)**の仕組みを理解する
- コサイン類似度によってユーザー間の嗜好の近さを計算し、映画評価を予測する
- 教育分野における「レコメンド思考」の応用を考える
使用データ
-
MovieLens Dataset - 100K (Kaggle)
→ 映画の評価履歴データ(userId, movieId, rating など)
実装コード
# ==============================================
# MovieLensによるレコメンドシステム入門
# 協調フィルタリング(User-based)
# ==============================================
import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.metrics import mean_absolute_error
import matplotlib.pyplot as plt
# --- 1. データ読み込み(MovieLens 100k) ---
ratings = pd.read_csv("ratings.csv")
movies = pd.read_csv("movies.csv")
# --- 2. 行列化(ユーザー×映画) ---
rating_matrix = ratings.pivot_table(index="userId", columns="movieId", values="rating")
print(f"データ行列サイズ: {rating_matrix.shape}")
# --- 3. 類似度計算(ユーザー間コサイン類似度) ---
rating_filled = rating_matrix.fillna(0)
user_similarity = cosine_similarity(rating_filled)
user_sim_df = pd.DataFrame(user_similarity, index=rating_matrix.index, columns=rating_matrix.index)
# --- 4. レコメンド関数(類似ユーザーから予測) ---
def predict_rating(user_id, movie_id, k=5):
similar_users = user_sim_df[user_id].sort_values(ascending=False)[1:k+1].index
sim_scores = user_sim_df.loc[similar_users, user_id]
movie_ratings = rating_matrix.loc[similar_users, movie_id]
return np.dot(movie_ratings.fillna(0), sim_scores) / sim_scores.sum()
# --- 5. 検証データを作成して精度確認 ---
sample = ratings.sample(500, random_state=42)
preds = []
for _, row in sample.iterrows():
try:
preds.append(predict_rating(row.userId, row.movieId))
except:
preds.append(np.nan)
sample["pred"] = preds
sample = sample.dropna()
mae = mean_absolute_error(sample["rating"], sample["pred"])
print(f"\n平均絶対誤差(MAE) = {mae:.3f}")
# --- 6. 実際のおすすめ映画を表示(例:ユーザー1) ---
target_user = 1
user_seen = ratings[ratings["userId"] == target_user]["movieId"].tolist()
user_unseen = [m for m in rating_matrix.columns if m not in user_seen]
pred_scores = {m: predict_rating(target_user, m) for m in user_unseen}
recommend_df = pd.DataFrame(list(pred_scores.items()), columns=["movieId", "pred_score"])
top_movies = recommend_df.merge(movies, on="movieId").sort_values("pred_score", ascending=False).head(5)
print("\n=== ユーザー1へのおすすめ映画 ===")
print(top_movies[["title", "pred_score"]])
# --- 7. 可視化 ---
plt.hist(sample["rating"] - sample["pred"], bins=20, color="skyblue", edgecolor="k")
plt.title("予測誤差の分布(実際−予測)")
plt.xlabel("誤差")
plt.ylabel("頻度")
plt.show()
結果例
...
MAEが2.086というのは、予測誤差が2.0〜2.1点程度という意味です。
映画の評価は主観的な要素が大きいため、精度がどこまでよくなるのか興味があります。
分析の要点
| ステップ | 内容 | 学べること |
|---|---|---|
| ① | ユーザー×映画の行列を作る | データの構造を意識した前処理 |
| ② | コサイン類似度を使う | ユーザーの嗜好パターンを数値化 |
| ③ | 類似ユーザーから重み付き平均 | 協調フィルタリングの核心 |
| ④ | MAEで評価 | モデルの性能を客観的に測定 |
学びと今後
レコメンドは「似ている人が好きなものを薦める」シンプルな仕組みから始まりますが、
この背後には「ベクトル」「類似度」「重み付け平均」など、
数学・統計・機械学習の基本が詰まっています。
生徒の探究活動を支援する立場として、
こうしたアルゴリズムを理解しておくことで、
「AIがどうやっておすすめしているのか?」を正しく説明できるようになるのは大きな収穫でした。
教育への応用を考えて
現時点では、これを直接授業で活用する予定はありませんが、
「生徒の探究テーマを支援するために、自分も一緒に学ぶ」 という姿勢はとても大切だと感じました。
教育データや学習履歴を用いたパーソナライズ学習にも応用可能な考え方であり、
今後どのように教育に生かせるか模索していきたいと思います。
例えば、教育プラットフォーム上で生徒の学習履歴を用いたレコメンドモデル(教材・学習順序・学習仲間など)への応用を検討しています。
また、ユーザー体験を最適化するために、協調フィルタリングと深層学習ベースのハイブリッド化も視野に入れています。
「AIの中身を“使う側”ではなく、“理解する側”へ」
その第一歩として、レコメンドを実装してみました。

