推薦系統的目的是爲客戶提供可能喜歡(購買)的產品,但從本質上來講是一個聚類的過程(對客戶聚類或者對商品聚類)。對於一個離線的推薦系統來講,爲某個客戶推薦出的產品咱們能夠經過某種方式知道是否爲該客戶喜歡的,也就是說咱們能夠從該客戶處獲得標準值。正由於如此,咱們就能夠借鑑檢驗分類模型的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 )}\] css
\[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得分就能夠評價推薦系統的效能,尤爲在多個推薦系統之間作比較時就能評判出推薦系統的優劣python
覆蓋率是指推薦系統對全部的用戶推薦的全部產品列表中,出現的產品與數據庫中在銷售的全部產品的佔比(不考慮每一個商品被推薦的次數)。在一個在線購物網站,咱們但願推薦系統推薦的商品列表儘量多地包含數據庫中的在售商品,若是一個推薦系統的全部推薦商品列表都未出現某種商品,那麼這種商品的銷量將會愈來愈少,這是在線購物網站不肯意看到的。所以,咱們但願提升覆蓋率,覆蓋率的計算公式以下:\[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 )\]數據庫
多樣性指一個推薦系統根據用戶購買行爲爲用戶推薦的商品的種類狀況,若是一個用戶購買了某種商品(青島啤酒),推薦系統總是爲該用戶推薦其餘廠商的啤酒,那麼咱們說這個推薦系統推薦的產品不具備多樣性(不是一個好的推薦系統),一個好的推薦系統可能會想到爲用戶推薦購買產品相近且不一樣類別的產品,如能夠推薦一個開瓶器等。
與多樣性相對應的另一個指標是驚喜度,驚喜度來自於和客戶喜歡的物品不類似,可是客戶卻以爲滿意(會購買)的推薦,好比上面說的爲買啤酒的客戶推薦一個尿布等。
上面幾個指標是做爲推薦系統效能的離線指標,通常指標值都達到最好時該推薦系統效果最好,可是通常狀況下不可能都達到最好,所以在評價多個推薦系統效能時得綜合考慮這幾個指標,選擇較好的部署。dom
假設已經有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分解。spa