推薦系統

china-pub發表於2013-06-08

 

推薦系統是近幾年比較火的一個話題,尤其是Netflix舉辦過一次電影推薦比賽之後,ACM有專門的Recommer System的會議。關於推薦系統的分類,從不同的角度有不同的分法,傳統的有兩種分法,一種叫基於內容(Content based)的推薦,顧名思義就是根據要推薦的專案(電影,書籍,音樂等等)本身的一些DNA進行推薦,比如電影的型別,是動作片還是愛情片還是動作愛情片?電影的導演是否有名,演員的陣容怎麼樣等等。還有一種叫協同過濾(Collaborative Filtering),協同過濾按照演算法又可以分成很多小類,User-based,Item-based,Slope-one,Model-based,下面就以一個實際例子來介紹不同的推薦演算法是怎麼實現的。

例子:假設我們獲取了一些使用者在對一些專案的評分,我們的目的是預測某個使用者對某個專案的評分。如下面的表格所示,我們拿預測User1對Item2的評分舉例。

 

  Item1 Item2 Item3 Item4
User1 4 5 5
User2 4 2 1  
User3 3   2 4
User4 4 4    
User5 2 1 3 5

基於內容(Content based)的推薦

Content-based是說我們在已經知道了Item DNA的情況下,基於這些DNA去做推薦。比如我們的Item是電影,那Item的DNA可能是電影的型別,我們拿喜劇片,愛情片和科幻片舉例。假如Item 2 是一部喜劇片,同時也可以是一部愛情片,我們用一個三維向量表示為:

$\large \mathbf{x}^2 = (1,0.99,0)^T$

如果同時我們也知道了使用者喜歡什麼樣的電影,到底是喜歡喜劇片多一點還是喜歡科幻片片多一點?那麼使用者的喜好也可以用一個三維向量來表示,假如使用者1只喜歡愛情片(喜好程度用0-5來表示),那麼使用者1的愛好用向量表示為:

$\large \mathbf{w}^1=(0,5,0)^T$

那麼,我們基於這兩個向量就可以預測使用者1會給Item 2 評多少分:

$\large r^{1,2} = {\mathbf{w}^1}^T \cdot \mathbf{x}^2 = 0*1 + 5*0.99 + 0 * 0 = 4.95 $

但實際上我們並不知道表徵喜好程度的向量,我們的目的是要學習出這個向量。

為此,我們想定義一些符號:

$\large n_u$:表示一共有多少使用者

$\large n_m$:表示一共有多少Item

$\large c(i,j)$:=1表示使用者 i 評價過 Item j

$\large r^{i,j}$: 表示使用者 i 對 Item j 的評分

$\large \mathbf{x}^j$:表徵 Item j 的特徵向量

$\large \mathbf{w}^i $: 表徵使用者的特徵向量(未知,需要學習)

$\large m^i $:使用者 i 評價過的 Item 數量

$\large n+1$:$\mathbf{x}$和 $\mathbf{w}$的維度

為了學習到使用者的特徵向量,我們需要定義一個學習策略,我們仍然採用先定義損失函式,然後對損失函式求極小的策略來學習使用者特徵。很自然的一個選擇就是採用平方損失函式。使用者 i 對 Item j 的評分損失為:

$\large (  {\mathbf{w}^i}^T \cdot \mathbf{x}^j - r^{i,j}  )^2$

對某個使用者 i 來說,損失為:

$\large \frac {1} {2m^i} \sum_{j : c(i,j)=1} (  {\mathbf{w}^i}^T \cdot \mathbf{x}^j - r^{i,j}  )^2  + \frac {\lambda}{2m^i} \sum_{k=1}^{n} (w_k^i)^2 $

對所有的使用者來說,損失為:

$\large L(\mathbf{w}) = \frac {1}{2} \sum_{i=1}^{n_u} \sum_{j : c(i,j)=1} ({\mathbf{w}^i}^T \cdot \mathbf{x}^j - r^{i,j})^2 + \frac {\lambda}{2}\sum_{i=1}^{n_u}\sum_{k=1}^{n}(w_k^i)^2 $

最小化上面的損失函式,採用梯度下降進行迭代:

$\large w_k^i := w_k^i  - \alpha \sum_{j : c(i,j)=1}  (  {\mathbf{w}^i}^T \cdot \mathbf{x}^j - r^{i,j}  ) x_k^j \qquad (for \qquad k=0) $

$\large w_k^i := w_k^i  - \alpha (\sum_{j : c(i,j)=1}  (  {\mathbf{w}^i}^T \cdot \mathbf{x}^j - r^{i,j}  ) x_k^j  + \lambda w_k^i) \qquad (for \qquad k \neq 0) $

 

協同過濾(Collaborative Filtering)

Item-based

如下圖所示,我們有三個使用者1,2,3和三個電影A,B,C。使用者1喜歡電影A和電影C,使用者2喜歡電影A,B,C,使用者3喜歡電影A。假設電影A和電影C很相似(這裡的相似性不是由A和C本身的DNA得到的,至於計算方面後面再說),那麼我們有理由預測使用者3會喜歡電影C,因為她喜歡A,而A和C很相似。

如果使用者1給電影A打了5分,而A和C又有90%的相似,那麼我們會預測說使用者3給電影C的評分是5*90%=4.5分。這就是所謂的Item-based。

推廣一下,回頭看看我們開頭的例子,我們的任務是要預測使用者1會給Item2評多少分,如果我們已經知道了Item2和Item1,Item2和Item3,Item2和Item4之間的相似性,那麼我們預測:

$\large p^{u1,i2} = \frac {r^{u1,i1}s^{i2,i1} + r^{u1,31}s^{i2,i3} + r^{u1,i4}s^{i2,i4}} {s^{i2,i1}+s^{i2,i3}+s^{i2,i4}} $

那麼問題來了,在不知道Item本身的資訊的情況下,如何計算兩個Item之間的相似性呢?如果我們把每個Item都用一個列向量來表示,其中向量裡的每一維都是不同的使用者對這個Item的評分,那麼計算兩個Item之間的相似性就轉化成我們熟悉的計算兩個向量之間的相似性了,可以採用餘弦距離(Cosine distance),皮爾遜相關性係數(Peason correlation coefficient),傑卡德相似係數(Jaccard similarity coefficient)等等。這裡我們拿皮爾遜相關性係數舉例:

$\large s^{i,j}=\frac {\sum_{u \in U} (r^{u,i} - \overline{r^i}) (r^{u,j} - \overline{r^j}) } {\sqrt{ \sum_{u \in U} (r^{u,i} - \overline{r^i})^2 }  \sqrt{ \sum_{u \in U} (r^{u,j} - \overline{r^j})^2 } } $

其中:

$s^{i,j} $ 表示Item i 和Item j之間的相似性

$U$表示同時評價過Item i和Item j的使用者集合

$\overline{r^i}$表示使用者集合$U$在Item i上的平均評分

$\overline{r^j}$表示使用者集合$U$在Item j上的平均評分

 

使用者 a 對 Item i 的評分預測公式為:

$\large p^{a,i} = \frac {\sum_{j \in I} r^{u,j}s^{i,j}}{\sum_{i \in I} |s^{i,j}|} $

其中:

$I$為使用者 a 評價過的Item集合

 

那麼預測User 1 對 Item 2 評分的具體計算步驟為:

1. 找出User 1 評價過的Item集合:Item 1, Item3, Item 4

2. 計算Item 2 和Item 1,Item 3, Item 4之間的相似度

拿計算Item 2 和 Item 1 相似性舉例:

2.1 找出同時評價過 Item 2 和 Item 1的使用者集合U:使用者2,使用者4和使用者5

2.2 使用者集合U在 Item 1 上的平均分3.33,在Item 2 上的平均分2.33,所以:

$\large s^{2,1} = \frac {0.67*-0.33 + 0.67*1.67+ -1.33*-1.33} {\sqrt {0.67^2 + 0.67^2 + (-1.33)^2} \sqrt {0.33^2 +1.67^2 + 1.33^2}} = 0.754 $

同理,計算出$s^{2,3}=-1, s^{2,4}=0.756$

3. 根據相似度和評分預測公式計算出預測分數

$\large p^{1,2} = \frac {4*0.754 + 5*(-1) + 5 *0.756} {0.754 + 1 + 0.756} = 0.716 $

 

在實際工程中,我們遇到的Item數量往往很大,如果線上去計算所有 Item 兩兩之間的相似度的話肯定不現實,那麼實際工程中應該怎麼處理呢? 這裡提供兩個方法:

第一種: 對所有Item進行預處理,一般是用雜湊的思想,將可能相似的Item集合Hash到一個桶裡,那麼線上計算的時候,只需要計算在某個桶裡的Item兩兩之間的相似性了,具體做法請google LSH,這裡不多說。

第二種: 用分散式計算離線把所有Item 之間的相似性都計算好,線上直接查詢就行。

還是以上面的例子來介紹怎麼用map-reduce的框架來計算item之間的相似性,整個計算過程採用兩個map-reduce過程。

 

 

 

User-based

 如下圖所示,我們有三個使用者1,2,3和四個電影A,B,C,D。使用者1喜歡電影A和電影C,使用者2喜歡電影B,使用者3喜歡電影A,電影C和電影D。如果使用者1和使用者3很相似(同樣,相似性也不是基於使用者本身的DNA來計算的,後來再介紹),那麼我們有理由預測使用者1會喜歡電影D,因為使用者1喜歡電影A和C,使用者3喜歡電影A,C和D,而使用者1和使用者3又比較相似。這就是所謂的User-based。

那麼我們用這種演算法怎麼預測使用者1對Item 2的評分呢?跟Item-based類似,我們先看看怎麼計算兩個使用者之間的相似性:

$\large s^{u,v}=\frac {\sum_{i \in I} (r^{u,i} - \overline{r^u}) (r^{v,i} - \overline{r^v}) } {\sqrt{ \sum_{i \in I} (r^{u,i} - \overline{r^u})^2 }  \sqrt{ \sum_{i \in I} (r^{v,i} - \overline{r^v})^2 } } $

其中:

$I$為使用者u,使用者v同時評價過的Item集合

$\overline{r^u}$為使用者 u 對 I 裡所有 Item 評分的平均值

$\overline{r^v}$為使用者 v 對 I 裡所有 Item 評分的平均值

 

User-based的評分的預測公式與Item-based的評分預測公式稍微有點不一樣:

$\large p^{a,i} = \overline{r^a} + \frac {\sum_{u \in U} (r^{u,i} - \overline{r^u}) s^{a,u}} {\sum_{u \in U} |s^{a,u}|} $

其中:

$U$為所有評價過Item i 的使用者集合

$\overline{r^a}$為使用者 a 對所有他評價過的Item的評分的平均值

$\overline{r^u}$為使用者 u 對所有他評價過的Item的評分的平均值(Item i 除外)

 

為什麼User-based和Item-based的評分預測公式會有區別呢?主要是為了消除使用者評分的bias,有的使用者就是喜歡評低分,而有的使用者習慣給高分。

那麼,預測使用者1在Item 2 上的評分的步驟為:

1. 找出評價過Item 2 的使用者集合:使用者2,使用者4和使用者5

2. 計算使用者1和使用者2,使用者4,使用者5之間的相似性

拿計算使用者1和使用者5的相似性為例:

2.1 找出使用者1和使用者5同時評價過的Item 集合I:Item 1,Item 3 和 Item 4

2.2 使用者1在 I 上的平均分為4.67,使用者5在I上的平均分為3.33,所以:

$\large s^{1,5} = \frac {-0.67*-1.33 + 0.33 *0.33 + 0.33 * 1.67}{\sqrt {(-0.67)^2 + 0.33^2 + 0.33^2} \sqrt {(-1.33)^2 + 0.33^2 + 1.67^2}} = 0.756$

同理計算$s^{1,2}=-1,s^{1,4}=0$

3. 根據相似性和評分預測公式計算預測分

$\large p^{1,2} = 4.67 + \frac {(2-2.5)*(-1) + (4-4)*0 + (1-3.33)*0.756}{1+0+0.756} = 3.95 $

 

Slope-one

Slope-one基於一種簡單的假設,假設任意兩個Item i 和 j 之間的評分存在某種線性關係,即知道了Item j 的評分,我們可以用線性公式來預測 Item i 的評分, $p^{u,i}= a r^{u,j}+b^{u,i,j}$,更進一步的假設斜率 $a=1$,這就是演算法為什麼叫Slope-one的原因。為了求得b,我們先定義一個平方損失函式:

$\large L(b^{i,j}) = \sum_{u \in U}(r^{u,i} - p^{u,i})^2 = \sum_{u \in U}(r^{u,i} - r^{u,j} - b)^2 $

其中:

$U$是同時評價過Item i 和 Item j 的使用者集合。

最小化上面的損失函式得到:

$ \large b^{i,j} = \frac {\sum_{u \in U}(r^{u,i} - r^{u,j})} {\sum_{u \in U} 1} $

預測使用者a對Item i 的評分預測公式為:

$\large p^{a,i} = \frac {\sum_{j \in I}(r^{a,j} + b^{i,j})} {\sum_{j \in I} 1} $

那麼用Slope-one預測使用者1在Item 2 上的評分步驟為:

1. 找到同時評價過Item 1 和Item 2的使用者: 使用者2,使用者4和使用者5

2. 計算Item 2 和 Item 1 的平均分差

$\large b^{2,1} = \frac {(2-4) + (4-4) +(1-2)} {3} = -1$

3. 仿照步驟1和步驟2計算

$\large b^{2,3} =-0.5, b^{2,4}=-4 $

4. 按照預測公式計算預測分

$\large p^{1,2} = \frac {(4-1) + (5-0.5) + (5-4)} {3} = 2.83 $

 

Weighted Slope-one

後來又演變出一種叫Weighted Slope-one的演算法,它的思想和Slope-one一樣,只是最後的評分預測公式加入了權重。

$\large p^{a,i} = \frac {\sum_{j \in I}(r^{a,j} + b^{i,j})c^{i,j}} {\sum_{j \in I} c^{i,j}} $

我們在上面計算 $b^{2,1}$的時候,是根據三個使用者的共同評分計算出來的,而在計算$b^{2,3}$的時候,是根據兩個使用者的共同評分計算出來的,計算$b^{2,4}$的時候只根據了一個使用者的評分。所以他們的權重分別是$c^{2,1}=3, c^{2,3}=2, c^{2,4}=1$,所以:

$\large p^{1,2} = \frac {(4-1)*3 + (5-0.5)*2 + (5-4)*1} {3+2+1} = 3.17 $

 

 Item-based,User-based,Slope-one都各有優缺點。Item-based跟當前使用者的行為相關,比如在瀏覽一部動作片的時候,推薦的結果可能就是另一部動作片,但在瀏覽一部愛情片的時候,推薦的結果可能就是一部愛情片。User-based考慮的相同愛好的使用者群的興趣,推薦這個使用者群喜歡過的某個Item,與當前使用者的行為關係不大,比如在瀏覽一部動作片或者愛情片的時候,推薦出來的結果可能都一樣。Slope-one主要是計算起來比較方便,也可以增量計算,實現很簡單。

思考一下:新聞推薦用User-based還是Item-based好?

另外,推薦的可解釋性也是現在推薦系統非常強調的,比如你在瀏覽Amazon的時候,它的推薦都會給出“Why Recommended”的理由。Item-based和Content-based類似,能給出很好的解釋,推薦的東西跟你現在瀏覽的東西相關,因為你在看Java程式設計思想,所以給你推薦Java相關的書籍。User-based的解釋是說跟你趣味相投的某某也喜歡這個電影,但是你可能並不認識這個某某,所以很難讓人信服。Slope-one就更沒法給出合理的解釋了。

 

Model-based

 推薦問題其實也可以歸結為機器學習裡面的一個領域,很自然的機器學習裡常用的一些模型都可以應用到推薦系統裡,比如貝葉斯模型,迴歸模型或者非常流行的矩陣分解,都可以用來解決推薦問題,這種自己建模或者用常用的模型去解決推薦問題的辦法就叫Model-based。這裡我主要說兩種Model-based,一種是矩陣分解,其實可以算真正意義上的協同過濾,另一種就是著名的SVD++。

矩陣分解

前面在講到 Content-based 推薦的時候說到,如果我們知道了 Item 的特徵向量, 就可以計算出使用者的特徵向量。一模一樣的道理,如果我們知道了使用者的特徵向量,就可以求出 Item 的特徵向量,那麼我們的損失函式為:

$\large L(\mathbf{x}) = \frac {1}{2} \sum_{j=1}^{n_m} \sum_{j : c(i,j)=1} ({\mathbf{w}^i}^T \cdot \mathbf{x}^j - r^{i,j})^2 + \frac {\lambda}{2}\sum_{j=1}^{n_m}\sum_{k=1}^{n}(x_k^j)^2 $

如果我們既不知道 Item 的特徵向量,又不知道使用者的特徵向量呢?這時候我們就可以考慮先隨便給一些 Random 的 Item 特徵向量和使用者的特徵向量,不斷迭代上面所說的“由Item特徵向量計算使用者特徵向量,由使用者特徵向量計算Item特徵向量”的過程。最後我們還是一樣用 ${\mathbf{w}^i}^T \cdot \mathbf{x}^j $ 來預測使用者 i 對 Item j 的評分,最後我們的整個評分預測矩陣會變為:

 $\large \left[ \begin{matrix}  {\mathbf{w}^1}^T \cdot \mathbf{x}^1 & {\mathbf{w}^1}^T \cdot \mathbf{x}^2 & \ldots & {\mathbf{w}^1}^T \cdot \mathbf{x}^{n_m}\\ {\mathbf{w}^2}^T \cdot \mathbf{x}^1 & {\mathbf{w}^2}^T \cdot \mathbf{x}^2 & \ldots & {\mathbf{w}^2}^T \cdot \mathbf{x}^{n_m} \\ \vdots & \vdots & & \vdots \\ {\mathbf{w}^{n_u}}^T \cdot \mathbf{x}^1 & {\mathbf{w}^{n_u}}^T \cdot \mathbf{x}^2 & \ldots & {\mathbf{w}^{n_u}}^T \cdot \mathbf{x}^{n_m} \end{matrix} \right]$

最後我們的損失函式就會變成:

$\large L(\mathbf{x}, \mathbf(w)) = \frac {1}{2} \sum_{(i,j) : c(i,j)=1} ({\mathbf{w}^i}^T \cdot \mathbf{x}^j - r^{i,j})^2 + \frac {\lambda}{2}\sum_{j=1}^{n_m}\sum_{k=1}^{n}(x_k^j)^2 + \frac {\lambda}{2}\sum_{i=1}^{n_u}\sum_{k=1}^{n}(w_k^i)^2 $

同樣我們採用梯度下降來解這個問題:

1. 將 $\mathbf(x), \mathbf(w)$ 初始化為一些Random的值

2. 梯度下降迭代

$\large x_k^j := x_k^j - \alpha (\sum_{i:c(i,j)=1} ({\mathbf{w}^i}^T \cdot \mathbf{x}^j - r^{i,j}) \mathbf{w}^i + \lambda x_k^j ) $

$\large w_k^i := w_k^i - \alpha (\sum_{j:c(i,j)=1} ({\mathbf{w}^i}^T \cdot \mathbf{x}^j - r^{i,j}) \mathbf{x}^j+ \lambda w_k^i) $

再回頭看看那個評分預測矩陣,是不是把原始矩陣分解成了兩個矩陣的乘積,是不是一個矩陣分解的問題?我們在矩陣分解之前一般會做一些的Normalization的工作,比如會把每個分數都減去該 Item 的平均分值。最後再預測分數的時候把該平均值加回來即可。我們有了所有 Item 的特徵向量之後,也可以很輕鬆的計算出任意兩個 Item 之間的相似度了。

 

SVD++

// TODO

 

 

相關文章