推薦系統基礎概念
-
前言
作者根據開源項目 gorse 的每一步提交, 系統性學習推薦系統架構組成以及gorse中使用的推薦算法的實現。 通過參考算法文檔以及代碼實現,作者對gorse的學習過程以及進度 與 博客發布的時間線保持一致
-
數據集分割
-
原因
推薦系統的根本任務是學習一個函數 f:(U,I)→Rf: (\mathcal{U}, \mathcal{I}) \to \mathbb{R}f:(U,I)→R,該函數能夠預測用戶 U\mathcal{U}U 對物品 I\mathcal{I}I 的偏好(例如評分)
然而,我們的最終目標是最小化模型在未觀測到的數據上的誤差,即泛化誤差。一個模型如果在訓練集上表現優異,但在未見數據上表現糟糕,則稱之為過擬合 (Overfitting)。它過度學習了訓練數據中的特有模式乃至噪聲,而未能捕捉到底層的、具有普適性的偏好規律。
因此,數據集劃分的根本目的,就是從有限的訓練數據中,模擬出未見數據的場景,從而對模型的泛化能力進行可靠的估計
-
常見數據劃分優缺點
-
留出法
這是最簡單直接的方法。它從原始數據集中隨機抽取一部分(例如80%)作為訓練集,剩下的一部分(20%)作為測試集。
大致流程:
對數據集 D\mathcal{D}D 進行一次性的、互斥的劃分,形成訓練集 D?train\mathcal{D}*{train}D?train 和測試集 D?test\mathcal{D}*{test}D?test,滿足 D?train∩D?test=?\mathcal{D}*{train} \cap \mathcal{D}*{test} = \emptysetD?train∩D?test=? 且 D?train∪D?test=D\mathcal{D}*{train} \cup \mathcal{D}*{test} = \mathcal{D}D?train∪D?test=D。
在 D?train\mathcal{D}*{train}D?train 上訓練模型 MMM,之后在 D?test\mathcal{D}*{test}D?test 上評估 MMM 的性能,其結果作為對泛化誤差的估計。*
- 優點:現簡單,計算開銷小,尤其適合在數據量非常龐大的場景下進行快速實驗和驗證。
- 缺點:單次隨機劃分的結果帶有很強的偶然性。可能某一次劃分恰好把一些“困難”或“簡單”的樣本都分到了測試集中,從而導致評估結果出現偏差。
-
K折交叉驗證
為了克服留出法的偶然性,它將整個數據集分成 K 個大小相似、互不相交的子集(稱為“折”)。然后進行 K 次訓練和評估,每次都選擇其中 1 個折作為測試集,剩下的 K-1 個折合并作為訓練集。最后,將 K 次的評估結果取平均值,作為模型的最終性能指標。
大致流程
將數據集 D\mathcal{D}D 隨機劃分為 K 個大小近似相等的互斥子集(折,Folds): D1,D2,…,DK\mathcal{D}_1, \mathcal{D}_2, \dots, \mathcal{D}_KD1?,D2?,…,DK?
進行 K 輪迭代,對于第 k∈{1,…,K}k \in \{1, \dots, K\}k∈{1,…,K} 輪:
-
令測試集為 Dtest(k)=Dk\mathcal{D}_{test}^{(k)} = \mathcal{D}_kDtest(k)?=Dk?。
-
令訓練集為 Dtrain(k)=D?Dk\mathcal{D}_{train}^{(k)} = \mathcal{D} \setminus \mathcal{D}_kDtrain(k)?=D?Dk?。
-
在 Dtrain(k)\mathcal{D}_{train}^{(k)}Dtrain(k)? 上訓練模型 MkM_kMk?,并在 Dtest(k)\mathcal{D}_{test}^{(k)}Dtest(k)? 上計算其性能指標 ?k\epsilon_k?k?。
最終的性能估計為 K 輪指標的均值。同時,也可以計算指標的標準差,以衡量模型性能的穩定性。
- 優點:充分利用了所有數據,每個樣本都有一次機會成為測試數據,使得評估結果更加穩定、可靠,大大降低了單次劃分帶來的偶然誤差。
- 缺點:計算成本高: 計算開銷是留出法的 K 倍。常用的 K 值為 5 或 10。
參考代碼:
func (set *TrainSet) KFold(k int, seed int64) ([]TrainSet, []TrainSet) {trainFolds := make([]TrainSet, k)testFolds := make([]TrainSet, k)rand.New(rand.NewSource(seed))perm := rand.Perm(set.Length())foldSize := set.Length() / kbegin, end := 0, 0 // todo 數據集劃分for i := 0; i < k; i++ {end += foldSizeif i < set.Length()%k {end++}// Test settestIndex := perm[begin:end]testFolds[i].interactionUsers = selectInt(set.interactionUsers, testIndex)testFolds[i].interactionItems = selectInt(set.interactionItems, testIndex)testFolds[i].interactionRatings = selectFloat(set.interactionRatings, testIndex)// Train settrainIndex := concatenate(perm[0:begin], perm[end:set.Length()])trainFolds[i].interactionUsers = selectInt(set.interactionUsers, trainIndex)trainFolds[i].interactionItems = selectInt(set.interactionItems, trainIndex)trainFolds[i].interactionRatings = selectFloat(set.interactionRatings, trainIndex)begin = end}return trainFolds, testFolds }
-
-
留一法交叉驗證
這是K折交叉驗證的一種極端情況,即 K 的值等于數據集中樣本的總數 N。在推薦場景下,這通常意味著每次只留下一個用戶的某一次交互記錄作為測試,用該用戶的所有其他數據來訓練。
大致流程:
K-折交叉驗證的一個特例,其中 K=NK=NK=N,N 是數據集中樣本的總數。
- 優點:由于幾乎所有數據都參與了訓練,模型的評估結果偏差極小,最能反映模型在真實數據上的期望性能。
- 缺點:計算成本極其高昂。如果數據集稍大,執行一次完整的留一法驗證將會耗費難以想象的時間。因此,它只適用于數據集規模非常小的場景。
-
基于時間的劃分
基于時間的劃分方法嚴格按照時間戳來切分數據。例如,選取一個時間點,將此時間點之前的所有數據作為訓練集,之后的數據作為測試集。
大致流程
嚴格依據交互發生的時間戳進行劃分。
-
選取一個時間點 TsplitT_{split}Tsplit?。
-
所有時間戳 t<Tsplitt < T_{split}t<Tsplit? 的交互數據構成訓練集 Dtrain\mathcal{D}_{train}Dtrain?。
-
所有時間戳 t≥Tsplitt \ge T_{split}t≥Tsplit? 的交互數據構成測試集 Dtest\mathcal{D}_{test}Dtest?。
- 優點:最能模擬線上真實環境,可以有效評估模型對未來用戶行為的預測能力。這是檢驗模型是否能跟上用戶興趣變化趨勢的黃金標準。
- 適用場景:對于任何具有時序特征的推薦任務(例如電商、新聞、社交媒體),這都是首選的劃分方法。
-
-
-
總結
根據不同的推薦場景選擇合適的劃分方法
劃分方法 優點 缺點 主要適用場景 留出法 簡單、快速 結果偶然性大 數據量巨大時的快速實驗或初步驗證。 K折交叉驗證 結果穩定,數據利用率高 計算開銷相對較大 常規的模型選擇和評估,是學術界和工業界的標準實踐。 留一法 評估偏差小,結果最可靠 計算成本極高 數據集規模很小,且對評估精度要求極高的罕見情況。 時間劃分 最貼近真實應用場景 需要數據包含時間信息 用戶興趣會隨時間變化的場景,如新聞、電商推薦。
-
-
推薦模型性能驗證
模型驗證的核心目標是科學地度量模型的泛化能力,確保其在未知數據上的表現符合預期。
-
離線評估 (Offline Evaluation)
離線評估是在模型上線前,使用固定的歷史數據集進行的驗證。它是成本最低、迭代速度最快的評估方式。
所有離線評估都必須基于正確的數據集劃分,以模擬真實世界的數據不可見性。主要協議包括:
-
時序劃分 (Temporal Split): 業界標準。按時間切分,用過去的數據訓練,預測未來的數據。這是唯一能在線下可靠模擬線上環境的方法。
-
K-折交叉驗證 (K-Fold Cross-Validation): 學術界標準。適用于靜態、非時序數據集,通過多次劃分求平均來獲得魯棒的評估結果。
-
留出法 (Hold-out): 用于超大規模數據集的快速驗證,但結果穩定性較差。
核心評估指標 (Key Metrics)
根據推薦任務的不同,我們關注的指標也不同。
-
評分預測 (Rating Prediction) 任務
這類任務的目標是預測用戶對物品的具體評分。
-
平均絕對誤差 (Mean Absolute Error, MAE):
它衡量的是預測評分與真實評分之間差值的絕對值的平均值。MAE對所有誤差一視同仁。
MAE=1∣Dtest∣∑(u,i)∈Dtest∣rui?r^ui∣ \text{MAE} = \frac{1}{|\mathcal{D}_{test}|} \sum_{(u,i) \in \mathcal{D}_{test}} |r_{ui} - \hat{r}_{ui}| MAE=∣Dtest?∣1?(u,i)∈Dtest?∑?∣rui??r^ui?∣ -
均方根誤差 (Root Mean Square Error, RMSE):
與MAE相比,RMSE通過平方項放大了較大預測誤差的懲罰,對模型的離譜預測(比如真實評分為1分,預測為5分)更為敏感。
RMSE=1∣Dtest∣∑(u,i)∈Dtest(rui?r^ui)2 \text{RMSE} = \sqrt{\frac{1}{|\mathcal{D}_{test}|} \sum_{(u,i) \in \mathcal{D}_{test}} (r_{ui} - \hat{r}_{ui})^2} RMSE=∣Dtest?∣1?(u,i)∈Dtest?∑?(rui??r^ui?)2?
gorse中的相關實現代碼:
func RootMeanSquareError(prediction []float64, truth []float64) float64 {tmp := make([]float64, len(prediction))floats.SubTo(tmp, prediction, truth) // 誤差floats.Mul(tmp, tmp) // 平方return math.Sqrt(stat.Mean(tmp, nil)) // 平均值開根號 } func MeanAbsoluteError(prediction []float64, truth []float64) float64 {tmp := make([]float64, len(prediction)) floats.SubTo(tmp, prediction, truth) // 誤差abs(tmp) // 絕對值 return stat.Mean(tmp, nil) // 平均值 }
-
-
Top-N 排序推薦 (Ranking) 任務
這是現代推薦系統最核心的任務,即為用戶生成一個有序的推薦列表。
精確率 (Precision@K) / 召回率 (Recall@K):
- Precision@K: 在推薦的Top-K個物品中,用戶真正喜歡的物品所占的比例。它衡量推薦結果的準確性。
- Recall@K: 在用戶所有喜歡的物品中,被我們成功推薦到Top-K列表里的比例。它衡量推薦結果的全面性。
-
分類任務 (Classification) - 如點擊率(CTR)預估
這類任務的目標是預測用戶點擊某個物品的概率。
AUC (Area Under the ROC Curve):
AUC衡量的是模型將正樣本排在負樣本前面的能力。它不依賴于某個具體的點擊閾值,能綜合評估模型在所有閾值下的排序能力,是CTR預估模型最核心的離線評估指標之一。
-
-
在線評估(Online Evaluation)
當模型在離線評估中表現出色后,必須通過在線實驗來驗證其在真實環境中的效果。這是檢驗模型商業價值的最終標準。
-
A/B 測試 (A/B Testing):
- 機制: 將用戶隨機分成若干組,一組(控制組)使用現有模型A,另一組或多組(實驗組)使用新模型B、C等。在一段時間內,比較各組的核心業務指標。
- 評估指標: 不再是RMSE或NDCG,而是真實的商業KPI,例如:點擊率(CTR)、轉化率(CVR)、用戶停留時長、GMV(商品交易總額)等。
- 優點: 結果最可靠,具有統計學意義,能直接衡量商業價值。
- 缺點: 實驗周期長,成本高,可能對部分用戶造成負面體驗。
-
交叉測試 (Interleaving):
- 機制: 將兩個模型(A和B)的推薦結果混合在一起,展示給同一個用戶。通過追蹤用戶最終點擊了來自哪個模型的物品,來快速判斷哪個模型更優。
- 優點: 比A/B測試更敏感,能用更少的時間和流量獲得顯著的統計結果,非常適合快速迭代多個算法版本。
- 缺點: 實現相對復雜,主要用于判斷模型的相對好壞,難以直接評估對絕對業務指標的影響。
-
-
超越精確度的質量評估 (Qualitative Evaluation)
一個高精度的模型不一定是一個好的推薦模型。例如,模型可能總是推薦那些熱門的、用戶早已熟知的物品。因此,還需要關注以下質量指標:
- 覆蓋率 (Coverage): 模型能夠推薦出的物品占總物品庫的比例。高覆蓋率意味著模型具有更好的挖掘長尾物品的能力。
- 多樣性 (Diversity): 推薦列表中的物品是否種類豐富,而不是高度同質化。
- 新穎性 (Novelty): 模型推薦的物品是否是用戶之前不知道的、全新的物品。
- 驚喜度 (Serendipity): 模型能否推薦出那些用戶意想不到、但又確實令其滿意的物品。
-
總結
一個成熟的模型驗證流程應該是:通過離線評估快速篩選和迭代算法,輔以質量評估確保推薦廣度和深度,最終通過在線評估來決策模型是否上線。
評估范式 核心目的 主要方法/指標 優點 缺點 離線評估 快速驗證算法的理論性能 RMSE, MAE, Precision/Recall@K, NDCG@K, AUC 快速、低成本、可重復 無法完全模擬真實環境,與線上表現可能存在偏差(Gap) 在線評估 驗證模型的真實商業價值 A/B測試, 交叉測試 結果真實可靠,直接關聯業務KPI 慢、高成本、有風險 質量評估 衡量推薦的人性化和探索能力 覆蓋率, 多樣性, 新穎性 彌補純精度指標的盲點,提升用戶體驗 通常難以直接量化和優化
-