協同過濾#
協同過濾(Collaborative Filtering,CF)是推薦系統最經典的方法。
它的核心思想是利用群體智慧:相似的用戶喜歡相似的物品,相似的物品被相似的用戶喜歡。
為什麼今天還要學 CF?因為它是後面所有方法的概念基礎:矩陣分解 是 CF 的降維版本、向量召回則是 Item-CF 的向量化版本。理解 CF 才能看懂後續演進的動機。
基本概念#
用戶 - 物品矩陣#
物品1 物品2 物品3 物品4
用戶A 5 3 ? 1
用戶B 4 ? ? 1
用戶C 1 1 ? 5
用戶D ? 1 5 4CF 的核心任務是填充矩陣中的空白,預測用戶對未評分物品的評分(或互動機率)。
兩種主要方法#
| 方法 | 核心思想 | 比對的對象 |
|---|---|---|
| User-Based CF | 相似的用戶喜歡相似的物品 | 用戶相似度 |
| Item-Based CF | 用戶喜歡與歷史物品相似的物品 | 物品相似度 |
User-Based 協同過濾#
演算法流程#
1. 計算用戶之間的相似度
2. 找到目標用戶的 K 個最相似用戶
3. 用這 K 個用戶的評分加權預測目標用戶的評分
4. 推薦預測評分最高的物品預測公式#
r̂(u,i) = r̄_u + Σ[sim(u,v) × (r(v,i) - r̄_v)] / Σ|sim(u,v)|r̄_u:用戶 u 的平均評分(去除個人打分偏差)sim(u,v):用戶 u 和 v 的相似度r(v,i):用戶 v 對物品 i 的評分
優缺點#
| 優點 | 缺點 |
|---|---|
| 可以發現用戶潛在興趣 | 用戶量大時計算複雜 |
| 推薦結果可解釋 | 用戶冷啟動問題 |
| 實作簡單 | 相似度矩陣需頻繁更新 |
Item-Based 協同過濾#
演算法流程#
1. 計算物品之間的相似度
2. 對用戶歷史評分過的每個物品
3. 找到該物品的 TopK 相似物品
4. 以歷史評分加權預測用戶對新物品的評分預測公式#
r̂(u,i) = Σ[sim(i,j) × r(u,j)] / Σ|sim(i,j)|sim(i,j):物品 i 和 j 的相似度r(u,j):用戶 u 對物品 j 的評分
與 User-Based 的比較#
| 維度 | User-Based | Item-Based |
|---|---|---|
| 比對對象 | 用戶相似度矩陣 | 物品相似度矩陣 |
| 適用場景 | 用戶少、物品多 | 用戶多、物品少 |
| 更新頻率 | 需頻繁更新 | 相對穩定 |
| 工業應用 | 較少 | 廣泛(Amazon、Netflix) |
| 冷啟動 | 物品冷啟動較好 | 用戶冷啟動較好 |
| 可解釋性 | 「跟你像的人也喜歡」 | 「因為你看過 X」 |
工業實踐:Item-Based CF 更常用,原因有三:
- 物品數量通常比用戶少,相似度矩陣較小
- 物品之間的相似度比用戶口味更穩定,可以離線計算
- 解釋性更好:「因為你看過 X,所以推薦 Y」直觀
相似度計算方法#
餘弦相似度#
cos(u,v) = (u·v) / (|u| × |v|)
= Σ(r_ui × r_vi) / √(Σr_ui²) × √(Σr_vi²)只看「方向」不看「強度」,最常用。
皮爾遜相關係數#
pearson(u,v) = Σ[(r_ui - r̄_u)(r_vi - r̄_v)] /
√[Σ(r_ui - r̄_u)²] × √[Σ(r_vi - r̄_v)²]皮爾遜相關係數先扣掉每位用戶的平均評分,可消除「有人習慣打高分、有人習慣打低分」的偏差。在顯式評分場景(如電影評分)特別有用。
Jaccard 相似度#
jaccard(u,v) = |I_u ∩ I_v| / |I_u ∪ I_v|只看是否互動過,不看評分強度。適合純隱式回饋(點擊、瀏覽)。
三者怎麼選?#
| 資料型態 | 建議方法 |
|---|---|
| 隱式回饋(0/1) | Jaccard、餘弦 |
| 顯式評分(1~5) | 皮爾遜 |
| 高維稀疏向量 | 餘弦 |
三者的取捨其實是「保留什麼、丟掉什麼」:
- 餘弦忽略強度(magnitude),對「打分習慣」不敏感,但對互動次數多的長尾用戶有偏。
- 皮爾遜先各自扣掉平均,移除個人打分基準(有人天生打高 1 分),最適合顯式評分。
- Jaccard只看「有沒有互動過」,丟掉強度資訊——停留 10 秒和 10 分鐘都算一次。
共通鐵則:相似度只在共同互動過的物品上算才有意義;重疊太少時(例如只有 1 個共同物品)餘弦可能算出 1.0,看似完美其實極不可靠。
相似度計算的優化#
問題:熱門物品偏差#
熱門物品與任何物品的共同用戶都很多,容易導致相似度被「灌水」。
解決方案:IUF(Inverse User Frequency)#
借用 TF-IDF 的思想,把活躍用戶的貢獻降權:
sim(i,j) = Σ[1/log(1 + |N_u|)] / √(|N_i| × |N_j|)N_u:用戶 u 評分過的物品數- 活躍用戶(什麼都看)對相似度的貢獻被打折扣
歸一化處理#
避免某些物品的相似度普遍偏高,在每個物品的相似度向量內做正規化:
sim_norm(i,j) = sim(i,j) / max(sim(i,·))鄰居選取與可靠度#
算完相似度後,要決定「拿幾個鄰居來預測」以及「哪些鄰居可信」。
鄰居數 K 怎麼選#
| K 太小 | K 太大 |
|---|---|
| 鄰居少、雜訊大 | 混進不相似的鄰居、預測被稀釋 |
- 實務常見 K 落在 20~50,且需依資料集與場景調參,沒有萬用常數。
- 也可改用相似度門檻取代固定 K:只納入
sim > 門檻(如 0.5)的鄰居,讓每個用戶自適應鄰居數。 - 鄰居過少的冷門用戶,退回熱門物品或全域平均作為保底。
加權聚合與最小共現#
預測公式裡的 sim(u,v) 就是權重——越相似的鄰居,評分占比越高,分母 Σ|sim| 把權重歸一化。為了避免「樣本太少的高相似度」誤導:
- 設最小共現門檻:只在共同物品數 ≥ 某值(如 5)時才採信該相似度。
- 對小樣本做收縮(shrinkage):往全域平均靠攏,樣本越少收縮越強。
Item-Based 在這點天生較穩:物品之間的共同評分用戶通常比「兩個用戶的共同物品」多,所以 item-item 相似度比 user-user 更可靠,這也是工業界偏好 Item-Based 的隱藏原因之一。
實踐中的挑戰#
1. 稀疏性問題#
用戶 - 物品矩陣通常 99.9% 以上為空,導致直接算相似度時樣本太少、不可靠。
緩解方案:
- 降維:矩陣分解,把稀疏矩陣壓成稠密的 latent factor(第 4 章)
- 聚類:先把用戶或物品分群,群內再算
- 預設投票:用平均值或先驗填補空格
2. 可擴展性問題#
| 規模 | 計算複雜度 |
|---|---|
| m 用戶 | O(m²) 用戶相似度 |
| n 物品 | O(n²) 物品相似度 |
緩解方案:
- 離線預計算 + 線上查表
- 分散式計算(Spark MLlib)
- 近似最近鄰搜尋(ANN,例如 Faiss、HNSW)
3. 冷啟動問題#
| 類型 | 表現 | 緩解方案 |
|---|---|---|
| 新用戶 | 無歷史行為 | 引導選擇興趣、使用人口統計學特徵 |
| 新物品 | 無人評分 | 基於內容的推薦、編輯推薦 |
工程實作要點#
相似度矩陣存儲#
存儲方案
# 使用稀疏矩陣存儲
from scipy.sparse import csr_matrix
# 只存儲非零元素
similarity = csr_matrix((data, (row, col)), shape=(n_items, n_items))
# 線上查詢時,常用 Redis 存 TopK 相似物品
# key: item_id, value: [(similar_item_id, score), ...]增量更新#
1. 新增用戶行為時,只更新相關物品的相似度
2. 定期全量重算,保證準確性
3. 用雙 Buffer 切換,避免線上服務中斷離線 / 線上分離#
| 階段 | 任務 | 頻率 |
|---|---|---|
| 離線 | 計算相似度矩陣 | 每天 / 每小時 |
| 線上 | 查相似物品、加權打分 | 即時 |
CF 作為召回階段#
工業系統很少把 CF 當成最終排序,而是當成召回(候選生成):快速、近似、覆蓋廣。
百萬物品 ─ Item-CF + ANN ─▶ 數千候選 ─ 排序模型 ─▶ Top-N- CF 負責「在 50ms 內從百萬物品撈出數千個相關候選」,重點是召回率。
- 真正的精排在後面,用更豐富的特徵(用戶屬性、上下文)與深度模型重排(第 6 章)。
- 這也解釋了為何 Item-Based + ANN 比 User-Based 更實用:物品 embedding 可離線預算,使用者只需即時查詢,正好接上雙塔架構(第 7 章)。
評估指標#
預測準確度(顯式評分)#
RMSE = √[Σ(r̂_ui - r_ui)² / n]
MAE = Σ|r̂_ui - r_ui| / n排序指標(推薦清單品質)#
| 指標 | 計算方式 |
|---|---|
| Precision@K | 推薦清單中相關物品的比例 |
| Recall@K | 相關物品被推薦的比例 |
| NDCG@K | 考慮位置的排序品質 |
工業界更看排序指標,因為使用者只看 Top 幾筆,預測絕對值是否準不太重要,相對排序對才重要。
總結#
| 要點 | 說明 |
|---|---|
| 核心思想 | 利用群體智慧,相似用戶 / 物品有相似偏好 |
| User-Based | 找相似用戶,適合用戶少物品多的場景 |
| Item-Based | 找相似物品,工業界更常用 |
| 相似度 | 餘弦、皮爾遜、Jaccard,依資料型態選擇 |
| 挑戰 | 稀疏性、可擴展性、冷啟動 |
| 工程實踐 | 離線算相似度,線上查表召回 |
| 演進方向 | ➡️ 矩陣分解(降維)➡️ 向量召回(embedding) |
下一章:矩陣分解