推薦系統基礎概念與資料準備
什麼是推薦系統?
推薦系統是一個資訊過濾系統,它的目標是從大量的物品(商品、電影、文章)中,預測使用者最可能感興趣的那些物品,並將它們呈現給使用者。
推薦系統的三大類型
1. 內容為本推薦 (Content-Based Filtering)
核心概念:推薦與用戶過去喜歡的物品「相似」的物品。
想像你最近在 Netflix 上看了一部「科幻片」,推薦系統就會分析這部電影的特徵(類型:科幻、導演、演員、關鍵詞),然後找出其他也具有「科幻」特徵的電影推薦給你。
優點:
- ✅ 不需要其他用戶的資料
- ✅ 可以推薦冷門物品(新商品也能被推薦)
- ✅ 推薦結果容易解釋(「因為您看過⋯」)
缺點:
- ❌ 推薦結果多樣性低(一直推薦同一類型的東西)
- ❌ 難以發現用戶跨領域的興趣
2. 協同過濾 (Collaborative Filtering)
核心概念:推薦與你「相似的其他用戶」喜歡的物品。
Netflix 發現「喜歡《全面啟動》的人也喜歡《駭客任務》」,所以當你看了《全面啟動》後,系統就會推薦《駭客任務》給你。
優點:
- ✅ 可以跨領域推薦(發現用戶意想不到的興趣)
- ✅ 不需要物品的特徵資料
缺點:
- ❌ 冷啟動問題 (Cold Start):新物品或新用戶沒有歷史資料,無法推薦
- ❌ 計算複雜度高(用戶×物品的矩陣可能非常大)
3. 混合式推薦 (Hybrid Approach)
實務上最強大的推薦系統,通常是內容為本 + 協同過濾的混合體。先用內容為本解決冷啟動,再用協同過濾提升推薦品質。
推薦系統的評價指標
| 指標 | 說明 | 適用場景 | |------|------|---------| | Precision@K | 推薦的 K 個物品中,有多少是用戶真正喜歡的 | 精準度重要(如電商首頁推薦) | | Recall@K | 用戶喜歡的所有物品中,有多少被推薦出來了 | 覆蓋率重要(如探索新內容) | | RMSE | 預測評分與真實評分的誤差 | 評分預測任務 | | MAP@K | 平均精準率均值 | 排序品質評估 |
準備資料集:MovieLens
我們將使用經典的 MovieLens 資料集來實作推薦系統。
import pandas as pd
import numpy as np
# 直接從網路載入 MovieLens 資料集
urls = {
'movies': 'https://files.grouplens.org/datasets/movielens/ml-latest-small/movies.csv',
'ratings': 'https://files.grouplens.org/datasets/movielens/ml-latest-small/ratings.csv',
}
movies = pd.read_csv(urls['movies'])
ratings = pd.read_csv(urls['ratings'])
print("=== 電影資料 ===")
print(f"電影數量: {len(movies)}")
print(movies.head())
print("\n=== 評分資料 ===")
print(f"評分數量: {len(ratings)}")
print(f"使用者數量: {ratings['userId'].nunique()}")
print(f"電影數量: {ratings['movieId'].nunique()}")
print(ratings.head())
# 檢查資料分布
print("\n=== 評分布 ===")
print(ratings['rating'].value_counts().sort_index())
資料預處理
# 使用者-電影評分矩陣
user_movie_matrix = ratings.pivot(
index='userId',
columns='movieId',
values='rating'
)
print(f"使用者-電影矩陣大小: {user_movie_matrix.shape}")
print("稀疏度: {:.2f}%".format(
(1 - user_movie_matrix.notna().sum().sum() /
(user_movie_matrix.shape[0] * user_movie_matrix.shape[1])) * 100
))
# 電影特徵:從 genres 欄位中解析
movies['genres_list'] = movies['genres'].str.split('|')
# One-Hot Encoding 類別
from sklearn.preprocessing import MultiLabelBinarizer
mlb = MultiLabelBinarizer()
genre_matrix = mlb.fit_transform(movies['genres_list'])
genre_df = pd.DataFrame(
genre_matrix,
columns=mlb.classes_,
index=movies['movieId']
)
print("\n=== 電影類型 One-Hot 編碼 ===")
print(f"類型數量: {genre_df.shape[1]}")
print(genre_df.head())
資料分割(時間序列分割)
推薦系統的資料分割不能使用隨機分割,因為使用者過去的行為才能預測未來:
# 將每個用戶的評分按時間排序,取最後 20% 作為測試集
ratings['timestamp'] = pd.to_datetime(ratings['timestamp'], unit='s')
train_data = []
test_data = []
for user_id, user_ratings in ratings.groupby('userId'):
user_ratings = user_ratings.sort_values('timestamp')
split_idx = int(len(user_ratings) * 0.8)
train_data.append(user_ratings.iloc[:split_idx])
test_data.append(user_ratings.iloc[split_idx:])
train_df = pd.concat(train_data)
test_df = pd.concat(test_data)
print(f"訓練集: {len(train_df)} 筆評分")
print(f"測試集: {len(test_df)} 筆評分")
本日總結
在本章中,你學到了:
- ✅ 推薦系統三大類型:內容為本、協同過濾、混合式
- ✅ 評價指標:Precision@K、Recall@K、RMSE、MAP@K
- ✅ MovieLens 資料集:載入與探索
- ✅ 資料預處理:評分矩陣與電影特徵編碼
- ✅ 時間序列分割:依時間順序分割訓練/測試集
下一章,我們將實作內容為本的推薦系統!