推薦系統(2)—LFM(Latent Factor Model)模型


前面一篇隨筆介紹了基於協同過濾的推薦系統的基本思想及其python實現,本文是上一篇的續集。本文先介紹評價推薦系統的離線指標,稍后主要討論基於矩陣分解的LFM模型。

評價推薦系統的離線指標

1、F值得分

  推薦系統的目的是為客戶提供可能喜歡(購買)的產品,但從本質上來說是一個聚類的過程(對客戶聚類或者對商品聚類)。對於一個離線的推薦系統來說,為某個客戶推薦出的產品我們可以通過某種方式知道是否為該客戶喜歡的,也就是說我們可以從該客戶處得到標准值。正因為如此,我們就可以借鑒檢驗分類模型的F值得分來做檢驗一個推薦系統的效能。
  我們可以通過將單個用戶的准確率(或召回率)做累加,即可得到整個推薦系統的准確率(或召回率),如下:$$Precssion\left ( u \right )= \frac{\sum_{u\in U} R\left ( u \right )\bigcap T\left ( u \right )}{\sum _{u\in U}R\left ( u \right )}$$  

\[Recall\left ( u \right )= \frac{\sum_{u\in U} R\left ( u \right )\bigcap T\left ( u \right )}{\sum _{u\in U}T\left ( u \right )} \]

其中\(R(u)\)是為用戶u做出的推薦列表,而\(T(u)\)是用戶在測試集上的真正的行為列表,通過如下公式可以計算出整個推薦系統的效能:  

\[F_{\beta }= \frac{\left ( 1+\beta \right )^{2}Recall\cdot Precision}{\beta ^{2}\cdot Recall+Precision}$$  F得分取值范圍為[0,1]之間,即權衡了准確率又兼顧了召回率,有了F得分就可以評價推薦系統的效能,尤其在多個推薦系統之間做比較時就能評判出推薦系統的優劣 ### 2、覆蓋率   覆蓋率是指推薦系統對所有的用戶推薦的所有產品列表中,出現的產品與數據庫中在銷售的所有產品的占比(不考慮每個商品被推薦的次數)。在一個在線購物網站,我們希望推薦系統推薦的商品列表盡可能多地包含數據庫中的在售商品,如果一個推薦系統的所有推薦商品列表都未出現某種商品,那么這種商品的銷量將會越來越少,這是在線購物網站不願意看到的。因此,我們希望提高覆蓋率,覆蓋率的計算公式如下:$$Coverage=\frac{\left |\cup _{u\in U} R\left ( u \right ) \right |}{\left | I \right |}$$其中I表示在售商品的總數     在考慮每個商品推薦次數的情況下,我們可以通過計算每個商品出現的頻率,用信息論中的熵或者基尼系數來度量一個推薦系統的覆蓋率:$$H=-\sum _{i=1}^{n}p_{i}\ln p_{i}$$或 $$Gini=\sum _{i=1}^{n}p_{i}\left ( 1-p_{i} \right )\]

3、多樣性與驚喜度

  多樣性指一個推薦系統根據用戶購買行為為用戶推薦的商品的種類情況,如果一個用戶購買了某種商品(青島啤酒),推薦系統老是為該用戶推薦其他廠商的啤酒,那么我們說這個推薦系統推薦的產品不具有多樣性(不是一個好的推薦系統),一個好的推薦系統可能會想到為用戶推薦購買產品相近且不同類別的產品,如可以推薦一個開瓶器等。  
 與多樣性相對應的另外一個指標是驚喜度,驚喜度來自於和客戶喜歡的物品不相似,但是客戶卻覺得滿意(會購買)的推薦,比如上面說的為買啤酒的客戶推薦一個尿布等。  
上面幾個指標是作為推薦系統效能的離線指標,一般指標值都達到最好時該推薦系統效果最好,但是一般情況下不可能都達到最好,因此在評價多個推薦系統效能時得綜合考慮這幾個指標,選擇較好的部署。

基於隱變量的推薦(Latent Factor Model)

  假設已經有n個人對m個商品進行評價,其評價矩陣\(A_{mxn}\)反應了每個人對每個商品的喜好程度(行為商品,列為用戶)。一般來說,一個人對商品或者某種事物的直觀感受會受到該商品或事物屬性值的影響,比如一個單身狗最近打算找一個對象,在眾多的女生中她選中了女生D,而他本人喜歡女生的類型具有漂亮的臉蛋、火辣的身材,白皙的皮膚等,這些特點就是他對美眉特征的一種偏好,而每個女生在臉蛋、身材、皮膚等特征上都有一定值,對於一個理性的單身狗來說,他選擇的D美眉一定是一個在他欣賞的屬性中具有較高值的女生,而在商品推薦中也是如此。雖然我們從矩陣A中只看到了每個用戶對每個商品的評價,但是我們可以認為這個評價值是用戶對商品的屬性值的偏愛程度與每個商品在這些屬性上的表現綜合結果,這里的屬性就是我們所說的隱變量。基於這樣的思想,我們可以將矩陣A分解成為“商品—商品屬性”的評價矩陣\(U_{mxk}\)與“商品屬性—客戶喜好”矩陣\(V_{kxn}\)的乘積,及:$$A_{m\times n}=U_{m\times k} V_{K\times n}$$  
這里的k可以看做是分解的商品的隱屬性個數,舉個栗子,假設有Ben、Tom、John、Fred對6種商品的評價情況如下,評分越高代表對該商品越喜歡(0表示未評價)

Ben Tom John Fred
product1 5 5 0 5
product2 5 0 3 4
product3 3 4 0 3
product4 0 0 5 3
product5 5 4 4 5
product6 5 4 5 5
     轉化為矩陣A為:$$A=\begin{bmatrix} 5 &5 &0 &5 \\ 5 &0 &3 &4 \\ 3 &4 &0 &3 \\ 0 &0 &5 &3 \\ 5 &4 &4 &5 \\ 5 &4 &5 &5 \end{bmatrix}$$

現在,我們的目的是要將矩陣A分解成為兩個矩陣的乘積。在整個過程中有三個問題需要考慮。第一,采用什么樣的分解方法,怎樣使得分解后的矩陣乘積盡量逼進矩陣A;第二,用幾個因變量來分解A矩陣合適,即分解后的矩陣U的列是多少合適;第三,對於一個客戶,怎么通過矩陣分解后的矩陣為他提供推薦。  
  下面先來說說第一個問題,要使得矩陣A能分解成U與V的乘積,也就是說對於A矩陣中的所有元素,要與矩陣U與矩陣V的乘積對應元素差距盡可能小,這種想法我們可以借鑒一下做回歸分析時求回歸系數的訓練方法,及構造一個損失函數,對損失函數采用梯度下降的方式求得分解矩陣元素值。對於K個因變量構造一個損失函數:$$J\left ( U,V;A \right )=\sum {i=1}^{m}\sum {j=1}^{n}\left ( a{ij}-\sum {r=1}^{k}u{ir}\cdot v{rj} \right )^{2}+\lambda \left ( \sum _{i=1}^{m} \sum {r=1}^{k}u{ir}^{2}+\sum _{j=1}^{n}\sum {r=1}^{k}v{r=1}^{2}\right )$$損失函數的右邊部分是L2正則化項(對應於redge回歸的正則化),可以降低解決過擬合問題導致分解后的矩陣元素太大,對損失函數求梯度:  

\[\left\{\begin{matrix} \frac{\partial J\left ( U,V;A \right )}{\partial u_{ir}}=-2\left ( a_{ij}-\sum _{r=1}^{k}u_{ir}v_{rj}\right )\cdot v_{rj}+2\lambda u_{ir}\\ \frac{\partial J\left ( U,V;A \right )}{\partial v_{rj}}=-2\left ( a_{ij}-\sum _{r=1}^{k}u_{ir}v_{rj}\right )\cdot u_{ir}+2\lambda v_{rj} \end{matrix}\right.,1\leq r\leqslant k\]

  有了梯度,我們就可以先隨機給定“商品—商品屬性”矩陣U和“商品屬性—客戶喜好”矩陣V一些初始值,然后對損失函數通過SGD方式得到,代碼如下:

import numpy as np
import math

def lfm(a,k):
    '''
    參數a:表示需要分解的評價矩陣
    參數k:分解的屬性(隱變量)個數
    '''
    assert type(a) == np.ndarray
    m, n = a.shape
    alpha = 0.01
    lambda_ = 0.01
    u = np.random.rand(m,k)
    v = np.random.randn(k,n)
    for t in range(1000):
        for i in range(m):
            for j in range(n):
                if math.fabs(a[i][j]) > 1e-4:
                    err = a[i][j] - np.dot(u[i],v[:,j])
                    for r in range(k):
                        gu = err * v[r][j] - lambda_ * u[i][r]
                        gv = err * u[i][r] - lambda_ * v[r][j]
                        u[i][r] += alpha * gu
                        v[r][j] += alpha * gv
    return u,v    
#對前面提到的評價矩陣A作分解,先選擇三個隱變量(k=3)
A = np.array([[5,5,0,5],[5,0,3,4],[3,4,0,3],[0,0,5,3],[5,4,4,5],[5,4,5,5]])
b,c = lfm(A,3)

#查看“商品—商品屬性”矩陣b和“商品屬性—客戶喜好”矩陣c
b,c
(array([[-0.2972852 ,  2.01461188,  1.0310134 ],
        [-0.41028699,  0.88314041,  1.70740435],
        [-0.69015017,  1.4846616 ,  0.22246443],
        [ 1.58422492,  1.15064457,  0.98881608],
        [-0.13167643,  1.63106585,  1.39457599],
        [ 0.36301204,  1.78414273,  1.44277207]]),
 array([[-0.81521492, -0.8423817 ,  1.25938865, -0.23881637],
        [ 1.32574586,  2.24986472,  1.49232807,  1.71803   ],
        [ 2.00802709,  0.18698412,  1.27586124,  1.42864871]]))
#查看b與c乘積
np.dot(b,c)
array([[ 4.98351751,  4.97581494,  3.94749428,  5.00511619],
       [ 4.933806  ,  2.65182221,  2.97963547,  4.054526  ],
       [ 2.97761928,  3.96325495,  1.63026864,  3.03333586],
       [ 2.21954795,  1.43916544,  4.97388618,  3.01117386],
       [ 5.07006975,  4.0413629 ,  4.047539  ,  4.82602576],
       [ 4.9665124 ,  3.97806056,  4.96047648,  5.03973199]])

  我們看到分解后的兩個矩陣乘積可以大致還原矩陣A,而且還原后的矩陣對原來用戶沒有評價的商品已經有了評價值,我們或許可以相信,該值即為用戶對該種商品的評價值的預測值(Tom對產品2的評價可能為2.7,John對產品1的評價可能為5.9),這就回答了上面提到的第三個問題。
  上面的第一個問題與第三個問題已經解決,而且真的按照我們的思路將矩陣A分解成了兩個矩陣的乘積。我們再看看第二個問題,我們分解出幾個商品屬性(隱變量)合適呢?這個問題我確實沒有在文獻上的看到有較完整的說明,或許可以從實驗的角度多取幾個K值來人為地檢測其效果,比如本例,如果知道這幾個人的喜好,然后取不同的K值來檢驗結果。
  LFM僅矩陣分解中的一種方式,下一篇我們再討論另一種特別有名氣的分解—SVD分解。



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM