課程名稱:1141 資料科學
專案類型:期末專案報告
作者:B1143015/林宣佑
本專案基於 MovieLens 20M 資料集,建構一個高效、精準且可解釋的個人化電影推薦系統。研究採用 SVD (奇異值分解) 進行降維與特徵提取,結合 User-Based KNN (最近鄰演算法) 進行相似度計算,並透過 9 次迭代實驗探索不同優化策略的實際效果。
實驗過程中測試了多種優化策略,包括:Item Bias、時間衰減 (Time Decay)、TF-IDF 加權、相似度放大 (Similarity Amplification) 等。重要發現:時間衰減與 TF-IDF 在電影推薦場景中效果不佳,驗證了「負面結果 (Negative Results)」對於理解資料特性的價值。最終 SVD(128) + KNN(50) + Item Bias 混合模型表現最佳,Hit Rate@10 達到 66.8%,RMSE 降至 0.9753。
在串流媒體與內容平台爆炸的時代,使用者每天面臨超過 10,000 部電影的選擇,形成嚴重的「資訊過載 (Information Overload)」困境。傳統的熱門排行榜無法滿足個人化需求,純粹基於內容特徵的方法 (Content-Based) 又過度依賴標籤品質與完整性。
協同過濾 (Collaborative Filtering) 雖然能有效挖掘「集體智慧」,但在面對 2000 萬級別的資料量時,常遭遇以下挑戰:
- 計算瓶頸:全量使用者相似度計算的時間複雜度為 O(n²),在千萬使用者規模下不可行。
- 稀疏性問題:每位使用者平均僅評分 144 部電影,矩陣稀疏度超過 99.5%,導致相似度估計不準。
- 冷啟動困境:新使用者或新電影缺乏評分歷史,無法直接計算相似度。
相較於深度學習方法 (如 Neural Collaborative Filtering),本研究選擇 KNN + SVD 的混合架構,主要基於以下考量:
- 可解釋性 (Explainability):能明確指出「因為你跟使用者 A 的品味相似度達 87%,而 A 喜歡《星際效應》,所以推薦給你」,相比深度學習的「黑盒子」更具說服力。
- 計算效率:SVD 降維後,僅需在低維潛在空間 (Latent Space) 中計算距離,大幅降低計算複雜度。
- 穩定性與可復現性:不需要調整超參數如學習率、Dropout 等,實驗結果更容易復現。
研究核心問題:
- 如何在單機有限資源下,處理並優化 2000 萬筆評分數據?
- 如何同時兼顧預測準確度 (RMSE) 與排序品質 (Hit Rate/NDCG)?
- 時間因素與熱門度偏差對推薦品質的具體影響為何?(透過 Time Decay 與 TF-IDF 實驗驗證)
本研究使用由明尼蘇達大學 GroupLens Research 實驗室發布的 MovieLens 20M 資料集。
| 項目 | 統計數值 | 備註 |
|---|---|---|
| 資料來源 | GroupLens Research | University of Minnesota |
| 評分總數 | 20,000,263 | 稀疏度極高 |
| 使用者數 | 138,493 | 每人至少評分 20 部 |
| 電影總數 | 27,278 | 實際有評分約 26,744 部 |
| 評分範圍 | 0.5 ~ 5.0 | 最小間隔 0.5 分 |
| 時間跨度 | 1995-01 ~ 2015-03 | 橫跨 20 年 |
| 矩陣稀疏度 | 99.47% | 絕大多數位置為空 |
| 使用檔案 | movie.csv, rating.csv |
僅使用電影資訊與評分矩陣 |
資料前處理策略:
- 使用
scipy.sparse.csr_matrix(Compressed Sparse Row) 處理高維稀疏矩陣,相比密集矩陣節省 99%+ 記憶體。- 對
movieId與userId重新進行連續索引映射 (Re-indexing),確保矩陣索引連續無間隙。- 使用
pandas.Categorical類型加速索引映射,減少記憶體佔用約 70%。- 在每個關鍵步驟後執行
gc.collect(),主動回收記憶體。
本專案採用 Memory-based 與 Model-based 的混合策略:
使用 sklearn.decomposition.TruncatedSVD 將 138,493 × 27,278 的高維稀疏矩陣降維至 50~150 維的潛在空間 (Latent Space)。SVD 能提取使用者的「潛在興趣特徵」,如「喜歡科幻片」、「偏好老電影」等隱含模式。
優點:
- 大幅降低計算複雜度(從 O(n²m) 降至 O(nk),其中 k << m)
- 能捕捉非線性的使用者-電影關聯
- 自動過濾噪音與異常值
在降維後的潛在空間中,使用 Cosine Similarity 尋找 Top-K 相似使用者。Cosine 相似度忽略評分尺度差異,僅關注「興趣方向」是否一致。
similarity(u, v) = cos(θ) = (u · v) / (||u|| × ||v||)
使用 sklearn.neighbors.NearestNeighbors 搭配 algorithm='brute' 與 n_jobs=-1 進行多核心並行計算。
基於 Top-K 鄰居的加權平均進行預測,權重為相似度:
pred(u, i) = Σ(similarity(u, v) × rating(v, i)) / Σ(similarity(u, v))
Item Bias 機制:當鄰居中無人評分過目標電影時,使用該電影的全局平均分作為 Fallback,有效解決冷啟動問題。
- 語言: Python 3.12
- 資料處理: Pandas, NumPy, Scipy (Sparse Matrix)
- 機器學習: Scikit-learn (TruncatedSVD, NearestNeighbors)
- 資料下載: Kagglehub
- 專案管理: UV (快速套件管理與虛擬環境)
- 記憶體監控: psutil (RSS 記憶體採樣)
| 優化技術 | 說明 | 記憶體節省 |
|---|---|---|
| CSR 稀疏矩陣 | 僅儲存非零元素的行索引、列索引與值 | 99.5% (相比密集矩陣) |
| Pandas Categorical | 將 userId/movieId 轉為 category 類型 | 70% (相比 int64) |
| 垃圾回收 (GC) | 在關鍵步驟後執行 gc.collect() |
約 10-15% |
| 原地操作 | 使用 inplace=True、避免複製 |
避免峰值記憶體翻倍 |
| 逐塊載入 | 對超大檔案使用 pd.read_csv(chunksize=...) |
可處理任意大小資料 |
實測結果:在 16GB RAM 環境下,完整 20M 資料集的記憶體峰值穩定在 1.4~2.8 GB,相比未優化版本 (需 32GB+) 節省超過 90%。
| 優化技術 | 說明 | 加速比 |
|---|---|---|
| 多核心並行 | KNN 使用 n_jobs=-1 啟用所有 CPU 核心 |
4-8x (視核心數) |
| Joblib 並行評估 | Leave-One-Out 評估使用 joblib.Parallel |
6-10x |
| 向量化運算 | 使用 NumPy 廣播 (Broadcasting) 取代迴圈 | 50-100x |
| CSR 快速索引 | csr_matrix 的行切片為 O(1) |
100x+ |
實測結果:單次完整實驗 (500 樣本) 從未優化的 45 分鐘降至優化後的 1.4 分鐘,提升超過 30 倍。
本研究進行了 9 次系統性迭代實驗 (Ablation Study),透過控制變因逐步探索各項優化策略的實際效果。評估指標包含:
- Hit Rate@10:前 10 個推薦中是否命中使用者喜歡的電影 (Leave-One-Out)
- NDCG@10:歸一化折損累積增益,衡量推薦排序品質
- RMSE:均方根誤差,衡量評分預測準確度
- MAE:平均絕對誤差,對異常值較不敏感的預測指標
| 實驗 | 資料量 | SVD 維度 | KNN 鄰居 | Item Bias | 特殊策略 | Hit Rate@10 | NDCG@10 | RMSE | 記憶體峰值 | 執行時間 |
|---|---|---|---|---|---|---|---|---|---|---|
| 實驗1 | 1M | ❌ 無 | 20 | ❌ | Baseline (無降維) | 0.5580 | 0.4100 | 1.0514 | 1.4 GB | 238 秒 |
| 實驗2 | 1M | 50 | 20 | ❌ | 首次引入 SVD | 0.5220 | 0.3771 | 1.1135 | 0.7 GB | 39 秒 |
| 實驗3 | 20M | 50 | 20 | ❌ | 擴展至全量資料 | 0.6140 | 0.4640 | 1.0473 | 1.8 GB | 50 秒 |
| 實驗4 | 20M | 50 | 20 | ❌ | 新增 MAE 指標 | 0.6140 | 0.4640 | 1.0473 | 1.8 GB | 49 秒 |
| 實驗5 | 20M | 50 | 20 | ❌ | 新增 NDCG 指標 | 0.6140 | 0.4640 | 1.0473 | 1.8 GB | 50 秒 |
| 實驗6 | 20M | 128 | 50 | ✅ | 最佳基線 | 0.6680 | 0.5280 | 0.9753 | 2.4 GB | 82 秒 |
| 實驗7 | 20M | 128 | 50 | ❌ | 時間衰減 (λ=500天) | 0.6160 | 0.4740 | 1.0312 | 4.4 GB | 105 秒 |
| 實驗8 | 20M | 128 | 50 | ✅ | 相似度放大 (×2.5) | 0.6680 | 0.5280 | 0.9746 | 2.4 GB | 82 秒 |
| 實驗9 | 20M | 128 | 50 | ❌ | TF-IDF 去熱門偏差 | 0.5300 | 0.3454 | 1.0094 | 4.5 GB | 83 秒 |
目的:建立基礎性能基準
- 策略:直接在原始稀疏矩陣上執行 KNN (20 鄰居)
- 結果:Hit Rate 僅 55.8%,RMSE 高達 1.0514
- 問題:高維稀疏空間中的距離計算不可靠,「維度災難」導致所有使用者距離趨於相等
目的:驗證降維的必要性
- 改進:使用 SVD 降至 50 維潛在空間
- 結果:Hit Rate 提升至 52.2% (-6.4%),RMSE 反而上升至 1.1135
- 發現:在 1M 小數據集上,SVD 降維反而損失資訊,需要更多數據才能發揮效果
目的:驗證模型在大規模資料上的泛化能力
- 改進:從 1M 擴展至完整 20M 資料集
- 結果:Hit Rate 躍升至 61.4%,證明「更多資料 → 更準確的相似度估計」
- 實驗 4/5 差異:僅新增評估指標 (MAE、NDCG),模型結構相同
目的:尋找最優超參數組合
- 改進:
- SVD 維度提升至 128 維(平衡表達能力與計算成本)
- KNN 鄰居增加至 50 位(擴大協同過濾的資訊來源)
- 引入 Item Bias(使用電影平均分作為冷啟動 Fallback)
- 結果:
- Hit Rate 達到 66.8%(相比實驗3提升 8.7%)
- NDCG 提升至 0.5280(排序品質顯著改善)
- RMSE 降至 0.9753(首次突破 1.0 關卡)
- 關鍵洞察:Item Bias 機制有效解決「鄰居中無人評分」的困境,避免預測值為空。
目的:驗證「近期評分更重要」的假設
- 策略:對評分套用指數衰減權重,半衰期設為 500 天(使用與實驗6相同的 SVD 128維 + KNN 50鄰居配置)
weight = exp(-λ × Δt) 其中 λ = ln(2) / 500 - 結果:
- Hit Rate 下降至 61.6%(比實驗6差 -7.8%)
- NDCG 下降至 0.4740(比實驗6差 -10.2%)
- RMSE 上升至 1.0312(比實驗6差 +5.7%)
- 分析:
- 電影品味具有長期穩定性,一個人喜歡科幻片不會因為時間而改變
- 過度懲罰舊評分導致資訊損失,特別是經典老片的評分被嚴重低估
- 時間衰減帶來的記憶體開銷(4.4 GB vs 2.4 GB)也顯著增加,因為需要載入時間戳資料
- 結論:時間衰減在「新聞推薦」或「商品推薦」中有效,但在電影推薦中不適用
目的:強化高相似度鄰居的影響力
- 策略:將相似度取 2.5 次方,拉大相似度差距
amplified_sim = sim^2.5 - 結果:Hit Rate 66.8%,與實驗6持平,RMSE 略優 (0.9746 vs 0.9753)
- 分析:放大機制在本實驗中未顯著改善效果,說明實驗6的基線配置已相當優秀
目的:降低熱門電影的主導地位
- 策略:套用 TF-IDF 權重懲罰熱門電影
weight = rating × log(n_users / movie_popularity) - 結果:
- Hit Rate 暴跌至 53.0%(比實驗6差 -20.4%)
- NDCG 降至 0.3454(效果最差)
- 深度分析:
- 在文本檢索中,TF-IDF 用來過濾「the」、「is」等高頻無意義詞彙
- 但在電影推薦中,「大家都看過的電影」如《肖申克的救贖》、《教父》恰恰是連結不同使用者的橋樑
- 過度懲罰熱門電影導致推薦清單充斥冷門片,使用者接受度低
- 結論:熱門度≠噪音,在推薦系統中需要保留共性特徵
-
Item Bias 的關鍵作用:在稀疏矩陣中,單純依靠鄰居評分常遇到「無人評分」的困境。加入電影平均分作為 Fallback 後,RMSE 從 1.0473 降至 0.9753(-6.9%),Hit Rate 從 61.4% 提升至 66.8%(+8.8%)。
-
維度與鄰居數的甜蜜點:
- SVD 維度在 128 時達到最佳平衡(50 維表達力不足,200 維過擬合且計算慢)
- KNN 鄰居在 50 時最優(20 個資訊不足,100 個引入噪音)
-
負面結果的學術價值
⚠️ :- 時間衰減無效:實驗7顯示時間衰減使 Hit Rate 下降 7.8%、RMSE 上升 5.7%,證明電影品味具有長期穩定性,與新聞/商品推薦不同
- TF-IDF 反效果:實驗9顯示 TF-IDF 使 Hit Rate 暴跌 20.4%,揭示「熱門≠噪音」,熱門電影是協同過濾的重要橋樑
- 這些負面結果在學術報告中同等重要,展現研究者對資料特性的深入理解
-
記憶體與計算的權衡:
- 完整 20M 資料相比 1M 子集,Hit Rate 從 55.8% 提升至 61.4%(+10.0%),但記憶體從 1.4 GB 增加至 1.8 GB(+29%)
- SVD 降維使計算時間從理論的 O(n²m) 降至實際的 1.4 分鐘/500 樣本
本專案使用 uv 進行套件管理。
# 1. 安裝依賴
uv sync
# 2. 執行所有實驗 (按順序執行 test1~test9)
uv run python main.py
# 3. 執行單一實驗
uv run python run/test6_refactored.py
# 4. 檢視日誌
tail -f log/實驗6.log1141_DataScience/
├── main.py # 主執行檔,順序執行所有實驗
├── pyproject.toml # UV 套件管理設定
│
├── src/movie_recommendation/ # 核心模組包
│ ├── data_loader.py # 資料載入與前處理
│ ├── feature_engineering.py # 稀疏矩陣、SVD、TF-IDF、時間衰減
│ ├── models.py # KNNRecommender 實作
│ ├── evaluation.py # 評估指標 (RMSE/MAE/NDCG/Hit Rate)
│ ├── utils.py # TimeTracker、記憶體監控、日誌
│ └── experiment.py # Experiment 與 ExperimentConfig
│
├── run/ # 實驗腳本
│ ├── test1_refactored.py ~ test9_refactored.py
│ └── test1.py ~ test9.py # 原始版本 (保留供參考)
│
└── log/ # 實驗日誌輸出
└── 實驗*.log
本研究成功基於 MovieLens 20M 實作了一個高效、精準且可解釋的推薦系統原型。最終模型 (實驗6) 在關鍵指標上達到:
- Hit Rate@10 = 66.8%:使用者喜歡的電影有三分之二機率出現在首頁 Top 10 推薦
- NDCG@10 = 0.5280:排序品質達到業界標準 (NDCG > 0.5 為優秀)
- RMSE = 0.9753:評分預測誤差低於 1 星,實用性高
- 記憶體峰值 = 2.4 GB:在單機 16GB RAM 環境下穩定運行
- 執行時間 = 82 秒:單次實驗 (500 樣本) 僅需 1.4 分鐘
透過系統性的對照實驗,本研究驗證了兩項「反直覺」的負面結果:
-
時間衰減 (Time Decay) 在電影推薦中無效:
- 實驗7 結果顯示,套用時間衰減後 Hit Rate 下降 7.8%(從 66.8% 降至 61.6%),RMSE 上升 5.7%
- 原因分析:電影品味具有長期穩定性,一個人喜歡科幻片、懸疑片的偏好不會隨時間大幅改變
- 對比:時間衰減在「新聞推薦」(時效性強) 或「商品推薦」(季節性) 中有效,但電影屬於「耐久品」
- 學術價值:證明了「適用於 A 領域的技術未必適用於 B 領域」,需根據資料特性選擇方法
-
TF-IDF 去熱門偏差導致災難性效果:
- 實驗9 結果顯示,套用 TF-IDF 後 Hit Rate 暴跌 20.4%,為所有實驗中最差
- 原因分析:在文本檢索中,TF-IDF 用來過濾「the」、「is」等無意義高頻詞。但在電影推薦中,「大家都看過的電影」如《肖申克的救贖》、《教父》恰恰是連結不同使用者的重要橋樑
- 深層啟示:熱門度 ≠ 噪音。過度強調「個性化」反而損失「共性特徵」,導致推薦清單充斥冷門片,使用者接受度低
- 實務建議:在推薦系統中應保留適度的熱門電影,作為「安全選項」與「破冰話題」
相比深度學習的「黑盒子」,本研究採用的 KNN + SVD 混合架構具備:
- 可解釋性 (Explainability):能明確指出「因為你跟使用者 A 的興趣相似度 87%,而 A 給《星際效應》5星,所以推薦給你」
- 快速迭代:不需要調整學習率、Dropout 等超參數,實驗結果穩定可復現
- 低資源需求:在單機環境下即可處理 2000 萬級資料,無需 GPU
- 引入內容特徵 (Hybrid):結合電影類型、導演、演員等元資料,提升冷啟動表現
- 深度學習模型:嘗試 Neural Collaborative Filtering (NCF) 或 LightGCN,捕捉更複雜的非線性互動
- 線上學習 (Online Learning):支援即時更新,根據使用者最新行為動態調整推薦
- 多目標優化:不僅考慮準確度,也納入「多樣性」、「新穎性」、「覆蓋率」等指標
- A/B 測試:在真實用戶環境中驗證離線指標與線上點擊率的相關性
[1] F. M. Harper and J. A. Konstan, "The MovieLens datasets: History and context," ACM Trans. Interact. Intell. Syst., vol. 5, no. 4, art. no. 19, Dec. 2015.
[2] Y. Koren, R. Bell, and C. Volinsky, "Matrix factorization techniques for recommender systems," Computer, vol. 42, no. 8, pp. 30–37, Aug. 2009.
[3] X. He, K. Deng, X. Wang, Y. Li, Y. Zhang, and M. Wang, "LightGCN: Simplifying and powering graph convolution network for recommendation," in Proc. 43rd Int. ACM SIGIR Conf. Res. Dev. Inf. Retr. (SIGIR), 2020, pp. 639–648.