矩陣分解#

矩陣分解(Matrix Factorization,MF)是協同過濾的進階方法。

它把「用戶 - 物品」評分矩陣分解成兩個低維的隱因子矩陣,藉此緩解資料稀疏性,並保留 CF 的核心思想。

MF 是後續所有 embedding-based 方法的源頭:第 7 章的雙塔模型本質就是 MF 的神經網路版本。學會 MF 等於拿到深度推薦模型的入場券。

基本原理#

分解目標#

m × n 的用戶 - 物品評分矩陣 R 分解為兩個低維矩陣:

R(m×n) ≈ P(m×k) × Q(k×n)^T
  • P:用戶隱因子矩陣,每位用戶對應一條 k 維向量
  • Q:物品隱因子矩陣,每件物品對應一條 k 維向量
  • k:隱因子數量(通常 10~200)

預測評分#

r̂(u,i) = p_u · q_i = Σ(p_uk × q_ik)

隱因子可理解為潛在的「主題」或「特徵」,例如電影的動作程度、愛情程度。但這些維度是模型自己學出來的,不一定能語意解釋。

概念澄清:推薦系統說的「SVD」其實不是線性代數教科書的 SVD(R = UΣV^T,要求矩陣完整)。Simon Funk 在 Netflix Prize 提出的 Funk SVD 是用 SGD 直接學 P、Q,只在已知元素上算誤差。後續所有「SVD/SVD++」變體都沿用這個套路,不要被名字誤導。

為什麼低秩分解有效(幾何直覺)#

評分矩陣看似活在 n 維(物品數)的高維空間,但真實的用戶偏好其實由少數幾個潛在維度主導——多數人的口味可以用「動作 vs 文藝」「主流 vs 小眾」這類少量軸線大致描述。

低秩分解就是降維:把高維、稀疏、充滿空白的評分矩陣,投影到 k 維的稠密隱因子空間。線性代數的 SVD 是用前 k 個奇異值做最佳低秩逼近;MF 則是「只在觀測到的格子上」做這件事,避免把空白硬擬合成 0 而帶偏向量。兩者產出的 user / item 向量都落在同一個可比較的空間,這正是後面所有「算內積找相似」的基礎。

隱因子數 k 怎麼選k 小(1050)訓練快、記憶體省,適合召回層的海量用戶物品;k 大(100200)能刻畫更細的偏好,適合排序層或品項較少的目錄。實務上交叉驗證,多數資料集在 k≈128 後損失就改善有限。

SVD 及其變體#

基礎 SVD(Funk SVD)#

損失函數:

L = Σ(r_ui - p_u · q_i)² + λ(||p_u||² + ||q_i||²)
  • 第一項:預測誤差(只在已知評分上累加)
  • 第二項:L2 正則化,防止過擬合

SVD++#

加入隱式回饋(用戶看過什麼,即使沒評分也是訊號):

r̂(u,i) = μ + b_u + b_i + q_i · (p_u + |N(u)|^(-1/2) Σ y_j)
  • μ:全域平均評分
  • b_ub_i:用戶 / 物品的偏差項(修正打分習慣)
  • N(u):用戶 u 有過行為的物品集合
  • y_j:物品 j 的隱式特徵向量

SVD++ 把「用戶看過什麼」與「用戶評過什麼」一併納入。Netflix Prize 冠軍方案的核心元件。

TimeSVD++#

把時間因素納入:用戶偏好隨時間漂移、物品熱度也會變化。

r̂(u,i,t) = μ + b_u(t) + b_i(t) + q_i · p_u(t)

優化演算法#

隨機梯度下降(SGD)#

for epoch in range(num_epochs):
    for u, i, r in training_data:
        error = r - predict(u, i)
        P[u] += lr * (error * Q[i] - reg * P[u])
        Q[i] += lr * (error * P[u] - reg * Q[i])

交替最小二乘(ALS)#

ALS 在 Spark MLlib 是內建演算法,業界處理大規模資料的主流選擇。

核心思想:交替固定一個矩陣,求另一個的解析解。

1. 初始化 Q 為隨機矩陣
2. 固定 Q,解析求解 P = R × Q × (Q^T × Q + λI)^(-1)
3. 固定 P,解析求解 Q
4. 重複 2-3 直到收斂

每一步都有解析解、計算穩定,且每位用戶 / 物品的更新互不依賴,天然可平行化,適合處理大規模稀疏矩陣。

SGD vs ALS#

維度SGDALS
收斂速度較慢較快(稀疏資料)
平行化困難容易
實作複雜度簡單中等
適用場景顯式評分隱式回饋

隱式回饋處理#

One-Class 問題#

實際推薦系統中,明確評分很少,更多的是隱式回饋(點擊、瀏覽、購買)。

回饋類型特點範例
顯式回饋用戶明確表達喜好評分、按讚
隱式回饋只有正樣本,缺少負樣本點擊、購買

Weighted-ALS#

針對隱式回饋的改進:把所有「沒互動」當成弱訊號的負樣本,但給予低權重。

L = Σ c_ui × (r_ui - p_u · q_i)² + λ(||P||² + ||Q||²)
  • r_ui = 1(有行為)或 0(無行為)
  • c_ui = 1 + α × 行為次數(信心度)

行為次數越多,信心度越高。Hu/Koren/Volinsky 原論文預設 α = 40。

負樣本採樣#

由於沒有明確負樣本,需要構造:

方法說明效果
隨機採樣均勻隨機選無行為物品一般
熱門採樣按物品熱度採樣較好
曝光未點擊從曝光但未點擊中採樣最好

熱門採樣的邏輯:熱門物品用戶更可能知道其存在,如果還沒互動,更可能是真正的負樣本。

BPR:面向排序的矩陣分解#

動機#

傳統 MF 優化「評分絕對值的準確度」,但推薦的最終目標是排序正確。BPR(Bayesian Personalized Ranking)直接優化排序。

BPR 優化目標#

max Σ log σ(r̂_uij) - λ||Θ||²
  • r̂_uij = r̂_ui - r̂_uj
  • (u, i, j):用戶 u 對物品 i 有正回饋,對物品 j 無回饋
  • σ:sigmoid 函數

BPR 直接優化「正樣本排在負樣本前面」的機率,與最終排序目標一致。

Weighted-ALS vs BPR#

維度Weighted-ALSBPR
任務型態回歸(0/1 + 信心度)排序(pairwise)
評估指標RMSE(不太相關)AUC(與優化目標一致)
訓練輸入(u, i, r)(u, i, j) 三元組
業界使用召回層召回層、排序層

BPR 訓練流程#

for epoch in range(num_epochs):
    for u, i, j in sample_triplets():
        x_uij = predict(u, i) - predict(u, j)
        gradient = sigmoid(-x_uij)
        update_parameters(u, i, j, gradient)

評估指標:AUC#

AUC = Σ I(r̂_ui > r̂_uj) / (|positive| × |negative|)

AUC 衡量「正樣本排在負樣本前面」的機率,是隱式回饋場景的主要排序指標。

向量檢索(ANN)#

這是現代召回層的核心:MF 訓練完得到 user / item 向量後,線上召回就退化成「給一條 user 向量,從千萬條 item 向量裡找 TopK 最近鄰」。靠 ANN(Approximate Nearest Neighbor)做毫秒級回應。

主流工具#

工具特點適用場景
FaissMeta 開源,CPU/GPU 均支援通用、大規模
HNSW圖索引,召回率與速度兼顧工業界主流
AnnoySpotify 開源,輕量、樹索引中小規模
ScaNNGoogle 開源,極致速度超大規模
Faiss 範例
import faiss

# 建立索引
d = 128  # 向量維度
index = faiss.IndexFlatL2(d)  # 暴力 L2 距離(小規模可用)
index.add(item_vectors)

# 查詢最相似的 k 個物品
k = 10
D, I = index.search(user_vector, k)

正式環境通常會用 IndexHNSWFlatIndexIVFPQ 換取速度。

聚類加速#

另一種思路:先對物品向量聚類,再分階段檢索。

1. 對物品向量做 K-means 聚類
2. 算用戶向量與每個聚類中心的相似度
3. 選相似度最高的若干群
4. 在選中的群內找具體物品

優點:可順便控制推薦多樣性(從不同群各取一些)。

工程實踐#

模型訓練工具#

工具語言特點
Spark ALSScala分散式,適合超大規模
ImplicitPython專注隱式回饋,CPU 高效
LightFMPython支援混合特徵(user/item side info)

模型更新策略#

策略頻率優點缺點
全量更新每天準確計算量大
增量更新每小時即時可能累積誤差
混合策略-平衡實作複雜

增量更新為何會累積誤差:只用新互動更新時,舊向量會逐漸偏離原本的全域最佳低秩逼近,誤差一輪輪疊加。定期全量重訓相當於把所有向量重新錨定回全域最佳;常見折衷是「每週全量 + 每日增量」,兼顧新鮮度與穩定度。

MF 的冷啟動對策#

MF 靠互動歷史學向量,新用戶 / 新物品沒有歷史就學不到向量:

情況對策
新用戶用人口統計、註冊情境初始化向量;或先走內容式推薦過渡
新物品用標題、類別、標籤等元資料當代理向量;或用內容相似度引導
通用訓練一個「從側資訊預測 MF 向量」的模型,補上缺失的 embedding

這正是雙塔模型(第 7 章)的優勢:它直接以特徵為輸入,新用戶 / 新物品只要有特徵就能算出向量,天然緩解冷啟動。

從 MF 到雙塔#

本章開頭說「MF 是深度推薦模型的入場券」,銜接點在這裡:

維度矩陣分解雙塔模型
向量怎麼來直接分解互動矩陣學 ID embedding用戶 / 物品特徵各過一座神經網路編碼器
能用的訊號只有互動互動 + 任意側資訊(屬性、上下文、文本)
損失函數RMSE / BPR交叉熵、對比學習(in-batch negatives)

兩者最終都把用戶與物品映到同一個向量空間、用內積算相似度——所以 MF 學會的「向量召回」直覺,可以原封不動搬到雙塔。

總結#

要點說明
核心思想把用戶和物品映射到低維隱因子空間
Funk SVD用 SGD 學 P、Q,只在已知元素上算誤差
SVD++加入隱式回饋與偏差項
ALS交替優化,天然平行化,適合大規模
Weighted-ALS處理隱式回饋的回歸版本
BPR排序學習版本,直接優化 AUC
向量檢索訓練完用 ANN(Faiss / HNSW)做線上召回
演進方向➡️ 雙塔模型(MF 的神經網路版本)

下一章:Bandit 演算法