協同過濾的R語言實現及改進

騰訊雲加社群發表於2019-02-22
歡迎大家前往騰訊雲+社群,獲取更多騰訊海量技術實踐乾貨哦~

協同過濾演算法是推薦系統最常用的演算法之一,本文將介紹一種方法來使它可以在大型資料集上快速訓練。

協同過濾演算法(CF)是構建推薦系統時最常用的技術之一。它可以基於收集到的其他使用者的偏好資訊(協同)來自動地預測當前使用者的興趣點。協同過濾演算法主要分為兩種:基於記憶(memory-based)的協同過濾演算法和基於模型(model-based)的協同過濾演算法。一般來說,將兩者融合可以獲得預測準確度上的提升。

在本文中,我們將關注基於記憶的協同過濾演算法並詳細討論其推導和整合的細節。我們將展示我們最近在改進經典協同過濾演算法上的一些工作,使其可以在大規模資料集上實施並達到縮短訓練時間的效果。我們的演算法是用R語言實現的,但是它也可以被移植到其他語言上。

基於記憶的協同演算法又可以分為下面兩種:

  • 基於使用者的協同過濾:如果想要預測使用者U對物品I的評價,可以藉助其他和U相似的使用者的評價來進行預測。這麼做的原因是我們認為相同品味的使用者會對同一事物做出相似的評價。
  • 基於物品的協同過濾:如果想要預測使用者U對物品I的評價,可以藉助該使用者對和物品I相似的物品的評價進行預測。這麼做的原因是我們認為同一使用者對相似事物做出的評價應當是接近的。

下面讓我們從一個例子出發來觀察基於使用者的協同過濾是如何實現的。下面給出了計算評價ru,i的公式,ru,i 即使用者u對物品i的評分。我們把和使用者u相似的使用者(使用者之間的相似度資訊通過一個矩陣維護,sim為相似度計算函式)的評價彙總在一起,從公式可以看出,使用者間的相似度越大,其中一個使用者對另一個使用者評價的預測結果影響程度就越大。w為計算最終評分所需的歸一化權重因子。

為了驗證當前推薦系統的效能,我們需要在測試集上進行預測。為了更高的效率,計算會藉助矩陣乘法完成,而不是通過迴圈的方式完成。下面的圖片展示了矩陣計算的過程:

從左到右依次為 使用者對物品的評分矩陣 使用者相似度矩陣 預測結果矩陣

上圖展示了預測使用者U2對物品I3評分時的計算過程。為了計算預測結果,我們需要知道其他使用者對I3的評分(第一個矩陣中藍色高亮的一行)以及其他使用者與U2的相似度(第二個矩陣中藍色高亮的一列;注意這裡我通過設定相似度矩陣對角線的元素為零來避免資料洩露)。到此,我們可以寫出使用者U2對物品I3評分的計算公式:

計算結果將被儲存在第三個矩陣的藍色單元當中。不過這裡還沒有進行歸一化,為了得到最終的預測結果,我們還需要計算歸一化因子w,計算公式已經在上面給出。

基於記憶的協同過濾的主要優點與它的可擴充套件性和效能密不可分。舉例來說,如果這裡有500,000個使用者,那麼我們需要計算所有使用者對之間的相似度(最壞的情況需要計算1200億個值)。顯然這需要大量的記憶體和處理時間,下面我們將嘗試用R語言(當然你也可以使用別的程式語言 : ) )對協同過濾演算法進行一些改進從而解決這一問題。

我們將用R推薦系統中最常用的包之一——recommenderlab與我們的實現進行比較。這個比較是在4核i7,16G記憶體的小型電腦上完成的,使用的資料集是MovieLens 100k, MovieLens 1m, MovieLens 10m。後面,你會看到我們的整合具有兩大優勢:

  1. 它的速度有顯著的提升。
  2. 可以支援在龐大的資料集上構建推薦系統,當 recommenderlab 報出記憶體溢位的錯誤時,我們的實現仍然可以正常工作。

執行效率的提升

評分矩陣通常是一個龐大(有大量的使用者和物品)的稀疏(每個使用者往往只對少量的物品打分)矩陣。在R語言中,我們可以通過專門的資料結構來儲存稀疏矩陣,缺失值不會被重複儲存在記憶體當中。一般來說,有超過90%的值是缺失的,所以這種做法可以節省下大量的記憶體。我們的實現以及recommenderlab中都採用了矩陣的稀疏表示。

我們實現的基於使用者的協同過濾主要包含以下步驟(基於物品的協同過濾也是如此):

  1. 匯入評分矩陣
  2. 開發者決定是否對使用者評分進行標準化。這一步通常會提高準確率。這是因為標準化可以移除使用者評分的偏置,舉例來說就是有些使用者總是會打高分或者總是打低分。
  3. 計算使用者之間的相似度。
  4. 使用KNN演算法。(只保留k個最相似的使用者,即在使用者的評分預測計算中,相似度矩陣每列只儲存最高的k個值)k值需要開發者手動指定。
  5. 計算預測值並進行反歸一化得到最終的預測評分。

recommenderlab也使用了與上面相同的過程。但是我們在這些過程中引入了一些改進從而顯著地提升了演算法執行效率。其中主要的兩個優化如下:

  1. 對大型稀疏矩陣的相似性計算進行了優化。具體方法可以參考Recommender Systems: Matrix Operations for Fast Calculation of Similarities
  2. 相似度矩陣的k近鄰演算法不是通過迴圈完成的,我們採用了更優的實現。首先,我們對相似度矩陣進行了分組(列拆分),然後在每組當中通過函式找到最高的k個值。這個函式已經在R `data.table`包中被實現。依此,我們通過每組的資訊得到了相似度矩陣中每列最大的k個值。

驗證

我們通過以下步驟來講我們的實現與recommenderlab進行比較:

  • 10折交叉驗證。每次訓練使用90%的資料來建立模型、計算相似度,10%的資料用來測試。任一使用者和物品都被劃分到了訓練集或者測試集當中。
  • 中心歸一化(Center Normalization),使用者評分的平均值將從他的實際評分中扣除。
  • 餘弦距離來計算相似度。
  • k:選取的近鄰樣本數為100,300以及樣本總值。
  • rmse:演算法的誤差(root-mean-square error,均方根誤差)
  • 執行時間 (exec time) :演算法的執行時間,以秒為單位。

在100k MovieLens 資料集上的比較

該資料集包括943個使用者和1682個電影(物品),100,000個評分。

基於使用者的協同過濾

基於物品的協同過濾

在1M MovieLens 資料集上的比較

該資料集包括6040個使用者和3706個電影(物品),100,000個評分。

基於使用者的協同過濾

基於物品的協同過濾

可以看到我們的實現在執行速度上更快,精準度也更高(達到了更低的rmse)。其中我們最關注的方面——速度得到了顯著的提升。

然而,速度只是經典實現中問題的一個方面。我們在上面提到過,協同過濾的另一個問題是空間佔用,即當矩陣過於龐大時我們會面臨記憶體不足的問題。在下一節中,我們將提出一個可行的方案來使傳統的協同過濾演算法可以被應用在龐大的資料集上。

在龐大的資料集上構建推薦演算法

在下面的測試中,我們使用MovieLens 10m的資料集。但是正如上面提到的,我們測試的機器只有16GB的記憶體並且使用了十折的交叉驗證。`recommenderlab`的實現在建立使用者相似度矩陣的過程中就因為記憶體不足而退出了。

在我們的實現當中,我們通過對矩陣進行切分解決了這一問題。即我們不是一次性計算所有的預測值,而是一塊一塊完成的。下面給出基於使用者的協同過濾的實現過程(基於物品的協同過濾同理):

  1. 取出使用者評分矩陣的前N行。在下圖圖示中,我們提取了I1:I4部分的切片。
  2. 取出M個使用者並計算他們與其他使用者的相似度。在下圖圖示中,我們提取了U1:U2部分的切片。
  3. 根據公式計算第一步得到的矩陣和第二步得到的矩陣的乘積。結果為MxN的矩陣,矩陣的元素為歸一化之前的預測結果。在圖示中,計算結果為使用者U1:U2對物品I1:I4的評分。
  4. 重複以上三步計算不同的MxN單元只到結果矩陣被填滿。

在10M MovieLens 資料集上的結果

該資料集包括69,878個使用者和10,677個電影(物品),10,000,054個評分。我們通過以下步驟來檢驗我們的演算法:

  • 10折交叉驗證
  • 中心歸一化(Center Normalization)。
  • 餘弦距離來計算相似度。
  • k:選取的近鄰樣本數為100,1000。
  • Chunk size:在演算法當中每次取出的塊的行列大小。具體的取值取決於你的硬體條件。

比較的結果可以從下面的表格找到,包含:

  • rmse:演算法的誤差(root-mean-square error)
  • 執行時間:演算法的執行時間,以分鐘為單位。
  • num predictions:協同過濾能夠預測的結果數。通常來說,協同過濾不是一定能夠得到預測結果的(比方說與之相似的使用者也都還沒有給該商品打分)

基於物品的協同過濾

基於使用者的協同過濾

正如上圖展示的結果所示,我們實現的演算法完滿地完成了任務。現在我們可以在16Gb記憶體配置的機器上構建推薦系統了。基於使用者和基於物品的協同過濾分別耗費了10分鐘和200分鐘的時間,基於使用者的協同過濾花費了更多的時間是因為資料集中有了更多的使用者,這要求我們計算更多的相似度。

通過現在的實現,當我們需要為一個或者多個使用者提供實時的推薦時,相似度的計算以及結果的預測將迅速很多,因為我們可以只選取少部分使用者進行操作。在MovieLens 10m的資料集上,基於使用者的協同過濾只需要一秒就可以對一個使用者或者多個使用者生成預測,但是基於物品的協同過濾則需要30s左右,這是因為我們需要更多的時間來計算相似度矩陣。這裡還可以通過將相似度矩陣儲存為模型,不再進行即時的訓練從而達到線上預測效果的加速。這個演算法實現的一個顯著優點就是可擴充套件性,由於我們將原資料集切分為了不同塊進行計算,所以可以進一步實現並行化。我們接下來的工作之一就是在分散式框架上實現並測試這一方法。

總結

在本文中,我們提出了一種新的方法來改進基於記憶的傳統協同過濾實現。本文的程式碼可以從Github上獲取。

問答
如何從源安裝R語言包?
相關閱讀
用R解析Mahout使用者推薦協同過濾演算法(UserCF)
近鄰推薦之基於使用者的協同過濾
協同過濾原理及Python實現

此文已由作者授權騰訊雲+社群釋出,原文連結:https://cloud.tencent.com/developer/article/1133912?fromSource=waitui

相關文章