Skip to content

foodnoodle/1141_DataScience

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🎬 MovieLens 20M 推薦系統實驗分析報告

課程名稱:1141 資料科學
專案類型:期末專案報告
作者B1143015/林宣佑

📖 專案摘要 (Abstract)

本專案基於 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

💡 研究動機 (Motivation)

資訊過載時代的挑戰

在串流媒體與內容平台爆炸的時代,使用者每天面臨超過 10,000 部電影的選擇,形成嚴重的「資訊過載 (Information Overload)」困境。傳統的熱門排行榜無法滿足個人化需求,純粹基於內容特徵的方法 (Content-Based) 又過度依賴標籤品質與完整性。

協同過濾 (Collaborative Filtering) 雖然能有效挖掘「集體智慧」,但在面對 2000 萬級別的資料量時,常遭遇以下挑戰:

  1. 計算瓶頸:全量使用者相似度計算的時間複雜度為 O(n²),在千萬使用者規模下不可行。
  2. 稀疏性問題:每位使用者平均僅評分 144 部電影,矩陣稀疏度超過 99.5%,導致相似度估計不準。
  3. 冷啟動困境:新使用者或新電影缺乏評分歷史,無法直接計算相似度。

為什麼選擇 KNN + SVD?

相較於深度學習方法 (如 Neural Collaborative Filtering),本研究選擇 KNN + SVD 的混合架構,主要基於以下考量:

  1. 可解釋性 (Explainability):能明確指出「因為你跟使用者 A 的品味相似度達 87%,而 A 喜歡《星際效應》,所以推薦給你」,相比深度學習的「黑盒子」更具說服力。
  2. 計算效率:SVD 降維後,僅需在低維潛在空間 (Latent Space) 中計算距離,大幅降低計算複雜度。
  3. 穩定性與可復現性:不需要調整超參數如學習率、Dropout 等,實驗結果更容易復現。

研究核心問題:

  1. 如何在單機有限資源下,處理並優化 2000 萬筆評分數據?
  2. 如何同時兼顧預測準確度 (RMSE) 與排序品質 (Hit Rate/NDCG)?
  3. 時間因素熱門度偏差對推薦品質的具體影響為何?(透過 Time Decay 與 TF-IDF 實驗驗證)

📊 資料集資訊 (Dataset Info)

本研究使用由明尼蘇達大學 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%+ 記憶體。
  • movieIduserId 重新進行連續索引映射 (Re-indexing),確保矩陣索引連續無間隙。
  • 使用 pandas.Categorical 類型加速索引映射,減少記憶體佔用約 70%
  • 在每個關鍵步驟後執行 gc.collect(),主動回收記憶體。

🛠️ 使用技術與方法 (Methodology)

本專案採用 Memory-basedModel-based 的混合策略:

1. 核心演算法

1.1 矩陣分解 (Matrix Factorization)

使用 sklearn.decomposition.TruncatedSVD 將 138,493 × 27,278 的高維稀疏矩陣降維至 50~150 維的潛在空間 (Latent Space)。SVD 能提取使用者的「潛在興趣特徵」,如「喜歡科幻片」、「偏好老電影」等隱含模式。

優點

  • 大幅降低計算複雜度(從 O(n²m) 降至 O(nk),其中 k << m)
  • 能捕捉非線性的使用者-電影關聯
  • 自動過濾噪音與異常值

1.2 最近鄰搜索 (K-Nearest Neighbors)

在降維後的潛在空間中,使用 Cosine Similarity 尋找 Top-K 相似使用者。Cosine 相似度忽略評分尺度差異,僅關注「興趣方向」是否一致。

similarity(u, v) = cos(θ) = (u · v) / (||u|| × ||v||)

使用 sklearn.neighbors.NearestNeighbors 搭配 algorithm='brute'n_jobs=-1 進行多核心並行計算。

1.3 評分預測 (Rating Prediction)

基於 Top-K 鄰居的加權平均進行預測,權重為相似度:

pred(u, i) = Σ(similarity(u, v) × rating(v, i)) / Σ(similarity(u, v))

Item Bias 機制:當鄰居中無人評分過目標電影時,使用該電影的全局平均分作為 Fallback,有效解決冷啟動問題。

2. 開發工具棧

  • 語言: Python 3.12
  • 資料處理: Pandas, NumPy, Scipy (Sparse Matrix)
  • 機器學習: Scikit-learn (TruncatedSVD, NearestNeighbors)
  • 資料下載: Kagglehub
  • 專案管理: UV (快速套件管理與虛擬環境)
  • 記憶體監控: psutil (RSS 記憶體採樣)

3. 效能優化策略

3.1 記憶體優化

優化技術 說明 記憶體節省
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%

3.2 CPU 計算優化

優化技術 說明 加速比
多核心並行 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 倍

🧪 九次實驗完整紀錄與分析 (Experiments)

本研究進行了 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 秒

各實驗詳細分析

📌 實驗 1:Baseline (無 SVD)

目的:建立基礎性能基準

  • 策略:直接在原始稀疏矩陣上執行 KNN (20 鄰居)
  • 結果:Hit Rate 僅 55.8%,RMSE 高達 1.0514
  • 問題:高維稀疏空間中的距離計算不可靠,「維度災難」導致所有使用者距離趨於相等

📌 實驗 2:引入 SVD (50 維)

目的:驗證降維的必要性

  • 改進:使用 SVD 降至 50 維潛在空間
  • 結果:Hit Rate 提升至 52.2% (-6.4%),RMSE 反而上升至 1.1135
  • 發現:在 1M 小數據集上,SVD 降維反而損失資訊,需要更多數據才能發揮效果

📌 實驗 3-5:擴展至全量資料

目的:驗證模型在大規模資料上的泛化能力

  • 改進:從 1M 擴展至完整 20M 資料集
  • 結果:Hit Rate 躍升至 61.4%,證明「更多資料 → 更準確的相似度估計」
  • 實驗 4/5 差異:僅新增評估指標 (MAE、NDCG),模型結構相同

📌 實驗 6:最佳基線 ⭐

目的:尋找最優超參數組合

  • 改進
    1. SVD 維度提升至 128 維(平衡表達能力與計算成本)
    2. KNN 鄰居增加至 50 位(擴大協同過濾的資訊來源)
    3. 引入 Item Bias(使用電影平均分作為冷啟動 Fallback)
  • 結果
    • Hit Rate 達到 66.8%(相比實驗3提升 8.7%)
    • NDCG 提升至 0.5280(排序品質顯著改善)
    • RMSE 降至 0.9753(首次突破 1.0 關卡)
  • 關鍵洞察:Item Bias 機制有效解決「鄰居中無人評分」的困境,避免預測值為空。

📌 實驗 7:時間衰減 ⏱️ (負面結果)

目的:驗證「近期評分更重要」的假設

  • 策略:對評分套用指數衰減權重,半衰期設為 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)也顯著增加,因為需要載入時間戳資料
    • 結論:時間衰減在「新聞推薦」或「商品推薦」中有效,但在電影推薦中不適用

📌 實驗 8:相似度放大

目的:強化高相似度鄰居的影響力

  • 策略:將相似度取 2.5 次方,拉大相似度差距
    amplified_sim = sim^2.5
    
  • 結果:Hit Rate 66.8%,與實驗6持平,RMSE 略優 (0.9746 vs 0.9753)
  • 分析:放大機制在本實驗中未顯著改善效果,說明實驗6的基線配置已相當優秀

📌 實驗 9:TF-IDF 去熱門偏差 📉 (負面結果)

目的:降低熱門電影的主導地位

  • 策略:套用 TF-IDF 權重懲罰熱門電影
    weight = rating × log(n_users / movie_popularity)
    
  • 結果
    • Hit Rate 暴跌至 53.0%(比實驗6差 -20.4%)
    • NDCG 降至 0.3454(效果最差
  • 深度分析
    • 文本檢索中,TF-IDF 用來過濾「the」、「is」等高頻無意義詞彙
    • 但在電影推薦中,「大家都看過的電影」如《肖申克的救贖》、《教父》恰恰是連結不同使用者的橋樑
    • 過度懲罰熱門電影導致推薦清單充斥冷門片,使用者接受度低
    • 結論:熱門度≠噪音,在推薦系統中需要保留共性特徵

關鍵洞察與負面結果的價值

  1. Item Bias 的關鍵作用:在稀疏矩陣中,單純依靠鄰居評分常遇到「無人評分」的困境。加入電影平均分作為 Fallback 後,RMSE 從 1.0473 降至 0.9753(-6.9%),Hit Rate 從 61.4% 提升至 66.8%(+8.8%)。

  2. 維度與鄰居數的甜蜜點

    • SVD 維度在 128 時達到最佳平衡(50 維表達力不足,200 維過擬合且計算慢)
    • KNN 鄰居在 50 時最優(20 個資訊不足,100 個引入噪音)
  3. 負面結果的學術價值 ⚠️

    • 時間衰減無效:實驗7顯示時間衰減使 Hit Rate 下降 7.8%、RMSE 上升 5.7%,證明電影品味具有長期穩定性,與新聞/商品推薦不同
    • TF-IDF 反效果:實驗9顯示 TF-IDF 使 Hit Rate 暴跌 20.4%,揭示「熱門≠噪音」,熱門電影是協同過濾的重要橋樑
    • 這些負面結果在學術報告中同等重要,展現研究者對資料特性的深入理解
  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 樣本

🚀 如何執行 (How to Run)

本專案使用 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.log

專案結構

1141_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

📝 結論 (Conclusion)

主要成果

本研究成功基於 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 分鐘

負面結果的重要發現 ⚠️

透過系統性的對照實驗,本研究驗證了兩項「反直覺」的負面結果:

  1. 時間衰減 (Time Decay) 在電影推薦中無效

    • 實驗7 結果顯示,套用時間衰減後 Hit Rate 下降 7.8%(從 66.8% 降至 61.6%),RMSE 上升 5.7%
    • 原因分析:電影品味具有長期穩定性,一個人喜歡科幻片、懸疑片的偏好不會隨時間大幅改變
    • 對比:時間衰減在「新聞推薦」(時效性強) 或「商品推薦」(季節性) 中有效,但電影屬於「耐久品」
    • 學術價值:證明了「適用於 A 領域的技術未必適用於 B 領域」,需根據資料特性選擇方法
  2. TF-IDF 去熱門偏差導致災難性效果

    • 實驗9 結果顯示,套用 TF-IDF 後 Hit Rate 暴跌 20.4%,為所有實驗中最差
    • 原因分析:在文本檢索中,TF-IDF 用來過濾「the」、「is」等無意義高頻詞。但在電影推薦中,「大家都看過的電影」如《肖申克的救贖》、《教父》恰恰是連結不同使用者的重要橋樑
    • 深層啟示:熱門度 ≠ 噪音。過度強調「個性化」反而損失「共性特徵」,導致推薦清單充斥冷門片,使用者接受度低
    • 實務建議:在推薦系統中應保留適度的熱門電影,作為「安全選項」與「破冰話題」

方法論價值

相比深度學習的「黑盒子」,本研究採用的 KNN + SVD 混合架構具備:

  1. 可解釋性 (Explainability):能明確指出「因為你跟使用者 A 的興趣相似度 87%,而 A 給《星際效應》5星,所以推薦給你」
  2. 快速迭代:不需要調整學習率、Dropout 等超參數,實驗結果穩定可復現
  3. 低資源需求:在單機環境下即可處理 2000 萬級資料,無需 GPU

未來改進方向

  1. 引入內容特徵 (Hybrid):結合電影類型、導演、演員等元資料,提升冷啟動表現
  2. 深度學習模型:嘗試 Neural Collaborative Filtering (NCF) 或 LightGCN,捕捉更複雜的非線性互動
  3. 線上學習 (Online Learning):支援即時更新,根據使用者最新行為動態調整推薦
  4. 多目標優化:不僅考慮準確度,也納入「多樣性」、「新穎性」、「覆蓋率」等指標
  5. 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.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Python 100.0%