矩陣分解在推薦系統中的應用

矩陣分解是最近幾年比較火的算法,經過kddcup和netflix比賽的多人多次檢驗,矩陣分解可以帶來更好的結果,而且可以充分地考慮各種因素的影響,有非常好的擴展性,因爲要考慮多種因素的綜合作用,往往需要構造cost function來將矩陣分解問題轉化爲優化問題,根據要考慮的因素爲優化問題添加constraints,然後通過迭代的方法進行矩陣分解,原來評分矩陣中的missing vlaue可以通過分解後得到的矩陣求的。

本文將簡單介紹下最近學習到的矩陣分解方法。

(1)PureSvd

怎麼評價這種方法呢?開始覺得這種方法很神奇很數學,而且在實際使用的時候也非常好用。

但最近讀了Yehuda大神的paper之後,覺得這種方法比較猥瑣。

其實,矩陣分解的核心是將一個非常稀疏的評分矩陣分解爲兩個矩陣,一個表示user的特性,一個表示item的特性,將兩個矩陣中各取一行和一列向量做內積就可以得到對應評分。

那麼如何將一個矩陣分解爲兩個矩陣就是唯一的問題了。

說到這裏大家就可能想起了在線代和數值分析中學到的各種矩陣分解方法,QR,Jordan,三角分解,SVD。。。

這裏說說svd分解。

svd是將一個任意實矩陣分解爲三個矩陣U,S,V,其中,U,V是兩個正交矩陣,稱爲左右奇異矩陣,S是個對角陣,稱爲奇異值矩陣。

其實svd分解的問題可以化解爲特徵值分解的問題。

評分矩陣A(m*n)=U(m*k)*S(k*k)*V'(k*n)

令B(m*m)=A(m*n)*A'(n*m)

B矩陣就是一個方陣,可以利用各種簡單的方法將B進行特徵值分解:

Bv=av,

v是方陣B的特徵向量,a是特徵向量v對應的特徵值。

所以奇異值s=sqrt(a),

左奇異向量u=A*v/s

同樣的方法可以求得右奇異向量。

這樣我們就得到了svd分解後的三個矩陣。(你可以自己寫個c程序計算,當然也可以用matlab算算得到)

分解後的三個矩陣都有着各自的意義,

U:每一行表示一個user的特徵。

V:每一列表示一個item的特徵。

S:表示對應的user和item的相關性。

所以可以考慮用U和V將S吸收進來,形成兩個矩陣分別表示user的矩陣和item的矩陣。

得到這個以後後面的事情就好辦了。

爲什麼說這個方法猥瑣呢?

因爲我覺得,這種方法有着矩陣分解算法的表,卻可以非常簡單地完成矩陣的分解,然後填充稀疏的評分矩陣。

但它考慮的因素太少了,不過對於簡單的推薦系統,這種方法還是非常有意義的,容易實現,而且結果也不會太差。

(2)Latent Factor Model

這是真正的矩陣分解算法,經過實踐檢驗,具有非常高的準確性和易擴展性。

正如上面提到的,實現推薦系統結果的目標是將那個稀疏的評分矩陣分解成兩個矩陣,一個表示user的feature,一個表示item的feature,然後做內積得到預測。

當然要實現滿足一定約束條件的矩陣分解,可不像上面的PureSVD那樣容易,需要構造一個優化問題,用一些複雜的算法求解優化問題。而這些優化問題往往是NP問題,只有局部最優解。

首先構造一個優化目標函數,

考慮到最後的評價指標是預測分值和實際分值之間的誤差的平方(RMSE),所以構造的目標函數也是誤差的平方的函數。

爲什麼這樣的算法可以得到更優的結果呢?因爲算法可以很容易地擴展很多的feature進來,更加出色地考慮了多種影響推薦效果的實實在在的因素。

  • Biases
因爲有的用戶總是會打出比別人高的分,或者說有的用戶他的評價尺度比較寬鬆;同樣有的item總是被打高分。這是一個普遍存在的問題,所以在構造目標函數的時候需要增加幾項:所有評分的平均值miu,user的偏見分數bu,item的偏見分數bi。
比如:求用戶x對電影y的打分,
所有評分電影的評分的平均分是miu=3.5,
電影y比所有評分電影平均分高bi=0.5
但是用戶x是個比較嚴格的用戶,評分總是相對偏低,所以bu=-0.3
所以用戶x對電影y的打分爲3.7
  • Implicit feedback
用戶在使用web應用的時候,會產生大量的行爲,充分挖掘這部分的價值,將會很好地提升推薦的效果。
利用用戶的隱式反饋,相當於充分的利用了評分矩陣中的missing value的價值,用戶在頁面的停留時間,檢索,瀏覽,點擊等等各種行爲都可以建模,內含到目標函數中。
這裏,可以將簡單地用一個Boolean來描述一種行爲有還是沒有。
不過在使用的時候,需要進行歸一化處理。
  • User-associated attributes
基於用戶的社會化屬性進行推薦也是一種很基本的推薦,當然也可以考慮到目標函數中。
  • Temporal dynamics
用戶的興趣包括長期和短期,動態地考慮一段時間內用戶的興趣是很有必要的。
上面的幾個因素中隨着時間變化的有,user的bias項bu=bu(t),item的bias項bi=bi(t),以及user的factor向量pu=pu(t),這裏可以忽略item的factor向量的變化,因爲item是比較穩定的。
  • Confidence level
因爲在處理上述的因素的時候,很多都是比較主觀的,所以需要給每個因素添加一個置信權重,以平衡整個結果。

通過構造出這個目標函數,然後添加相應的約束條件,接下來的問題就是求解這個優化問題。
通常比較好的方法是Stochastic gradient desent。

PS:這種方法是現在學術界的主流方法,大家可以參閱Yehuda的神作(http://research.yahoo.com/Yehuda_Koren)以及上海交大在今年kddcup獲獎方法的paper以及他們的開源系統(http://apex.sjtu.edu.cn/apex_wiki/svdfeature

(3)NMF(非負矩陣分解)

很多人用這種方法是因爲他們覺得只有一個非負的值對於實際的例子纔會有意義。

考慮到svd或者latent factor model會得到負的值,所以這種方法的物理意義比較明確。

同樣的道理,NMF也是將評分矩陣的轉置矩陣分解成兩個矩陣。

不同的是這兩個矩陣有着和上面的矩陣不同的物理意義。

其中一個是基矩陣W,另一個是投影矩陣H,即R'(n*m)=W(n*r)*H(r*m)

W:每一列包含一個基向量,這組基向量構成一個r維的空間。

H:每一列則近似爲原始數據對應的列向量在該r維空間的投影。

做這個分解的方法也是構造一個目標函數和一些約束條件,然後用梯度下降的算法來計算得到一個局部最優解。

這種方法的思路大概是這樣的:

  • 將評分矩陣轉置然後分解成兩個矩陣W和H。
  • 根據基矩陣W,可以計算得到目標用戶評分向量a對基矩陣W的投影向量h。
  • 計算投影向量h與投影矩陣H各行之間的歐式距離,將其中距離最小的前k個用戶組成目標用戶a的最近鄰集合。
  • 然後用皮爾遜相關法將最近鄰集合中的數據進行加權計算,然後排序進行推薦。
可以看出來,這種方法的思路和上面的兩種還是很不相同的,主要還是在計算目標用戶的最近鄰集合,主要思想還是knn,只是在中間用了矩陣分解的方法降維降低了計算的時間複雜度。

矩陣分解在學習的時候感覺既沒用又麻煩,尤其是線代裏面做矩陣的分解計算,無聊的很。
現在看來,矩陣分解非常有意義。
 
 
 
 
 
 
續:

最近研究了下Yehuda大神的paper,學習了下矩陣分解方法在推薦系統中如何用。

本文中提到的矩陣分解是一般的分解,即R=M*N的形式。

1、矩陣分解方法的來源

CF裏的矩陣分解思想是來自於IR領域的Latent Semantic Analysis(LSA)。google黑板報的《數學之美》中很清楚地講了SVD分解在IR中的應用。(http://www.google.com.hk/ggblog/googlechinablog/2006/12/blog-post_8935.html

2、矩陣分解的優劣

優點是:

  • 比較容易編程實現
  • 比較低的時間和空間複雜度
  • 預測的精度比較高
  • 非常好的擴展性
缺點是:推薦的結果不具有很好的可解釋性。因爲把ratings matrix分解成user-factor matrix和item-factor matrix,這裏的factor很難用實際意義的概念來解釋。不過,矩陣分解的過程相當於一個軟聚類的過程,得到的每一個factor相當於每一個聚類後的分組,只是我們沒有一個通用的方法來爲這些分組命名。
但是在實際的應用中,我們可以提取這些分組中最突出的特點來給這些factor命名。比如,拿新聞資訊類的推薦系統來說,做好分解之後,每個factor都可以看成是一類資訊,可以從這些資訊中提取一些特徵來給這個factor命名。

3、矩陣分解的模型(Latent Factor Model)
矩陣分解的思路是把評分矩陣通過分解,用一個低秩的矩陣來逼近原來的評分矩陣,逼近的目標就是讓預測的矩陣和原來的矩陣之間的誤差平方最小。(矩陣分解一般不用數學上直接分解的辦法,儘管分解出來的精度很高,但是效率實在太低!矩陣分解往往會轉化爲一個優化問題,通過迭代求局部最優解。)
但是有個問題是,原來的評分矩陣的稀疏度太大,分解很容易產生overfitting(過度擬合,意思就是爲了遷就一些錯誤的偏僻的值導致整個模型錯誤)的問題。所以現在的方法是在目標函數中增加一項regularization(正則化),來避免overfitting問題。
所以一般的矩陣分解的目標函數(或者稱爲loss function)是:

前一項是預測後的矩陣和現有的評分矩陣的誤差,這裏計算只針對評分矩陣中已經評分的項。
後一項就是正則化項,用來解決過度擬合的問題。
這個優化問題求解的就是分解之後的user-factor,item-factor矩陣的factor向量。(qi是item的factor向量,pu是user的factor向量)
求解這個優化問題常用兩種方法,一種是alternative least squares(交叉最小二乘法),另一種是stochastic gradient descent(隨機梯度下降法)。
前一種方法會涉及到矩陣的求逆問題,所以計算起來會比較麻煩。
後一種方法,只需要求梯度,就可以迭代計算了,因此會簡單很多。
迭代方程如下:


其中,gamma是學習速率,lamda是正則化係數,是兩個可選的參數,而且對於最後的結果非常重要。
這裏,gamma的大小不僅會影響到訓練時間,還會影響到結果的收斂性。gamma太大的話會導致結果發散,一般都會把gamma取得很小,不同的數據集取得值不同,但大概是0.001這個量級。這樣的話訓練的時間會長一些,但結果會比較好。
lamda的值一般也比較小,大概取0.01這個量級就好了。
迭代開始前,需要對user和item的特徵向量賦初值,這個初值很重要,會嚴重地影響到計算速度。一般的做法是在所有已評分的平均分附近產生一些隨機數作爲初值。
迭代結束的條件一般是loss function開始增加了,或者loss function的值小於了某一個閾值。
當我們拿到計算出來的user,item的factor向量後,最後預測結果時有兩種選擇,一種是保留計算出來的小數rating,一種是將這些小數rating四捨五入並裁減到[1,5]這個區間內。
對於實際的推薦系統來說,結果是小數還是整數,沒有所謂,因爲我們並不會把預測的分數給用戶看,而只是返回一個推薦列表。
但對於線下訓練參數或者做論文的童鞋來說,不同的處理方法得到的RMSE或者MAE的值可不相同。
我用這個的算法對movielens 100k的小數據做了測試,用很短的時間就可以計算好,不過那些參數的選擇需要不斷地用RMSE 來計算得出。在其他的信息都沒有利用的情況下,也可以得到0.90這個量級的RMSE。

4、增加一些擴展項
上面的模型中只簡單的用了已知的評分數據,很多的信息都沒有考慮進來。
(1)增加biases信息
因爲有的user總是趨向於打一個很高的分,而有的user比較嚴格,總是打一個很低的分,有的item總是被打一個很高的分,而有的item總是被低估。所以我們需要給模型增加biases項,loss function如下:

迭代方程變成了:
同樣的方法,只是多了對bu和bi的賦初值。
同樣,我用movielens的100k數據計算,得到的RMSE值也在0.90這個量級,但整體要比沒有考慮biases結果好。
(2)增加implicit feedback信息
評分是一個顯性的反饋方式,然而在很多時候顯性的反饋很少很少,而user的很多行爲都可以反映出他們對item的態度,所以利用implicit feedback是非常必要的。給模型增加implicit feedback項,預測模型如下:

迭代方程如下:

implicit feedback信息對於商城來說,可能是購買,瀏覽等等行爲,對於Netflix這樣的網站來說,可能是瀏覽,租賃等等。

(3)考慮temporal信息
因爲用戶的興趣或者對某一個item的態度是和時間有關的,比如說,可能我今年不太喜歡西服這個東西,因爲我用不着,所以我不會購買,但可能若干年後我不得不穿西服的時候,我一定會去買,也就是說我給推薦系統留下我喜歡西服這個東西的印象。(即使我真的不喜歡西服。)
動態地考慮user的興趣或者需求是非常必要的。

矩陣分解是當下非常流行的算法,可以考慮將這種算法和傳統的KNN結合在一起來做推薦,相信效果會很不錯。
發佈了34 篇原創文章 · 獲贊 18 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章