推薦系統實踐 0x09 基於圖的模型

用戶行為數據的二分圖表示

用戶的購買行為很容易可以用二分圖(二部圖)來表示。並且利用圖的演算法進行推薦。基於鄰域的模型也可以成為基於圖的模型,因為基於鄰域的模型都是基於圖的模型的簡單情況。我們可以用二元組\((u,i)\)來表示用戶\(u\)對物品\(i\)有過購買行為,這樣的話數據集可以用一個二分圖來表示。我這裡嘗試畫一個二分圖(有點丑,不要介意哈):

graph LR
A(A) –>a[a]
A(A) –>b[b]
A(A) –>d[d]
B(B) –>b[b]
B(B) –>c[c]

左邊是用戶節點,右邊是物品節點。連線代表用戶對物品有過購買行為。

基於圖的推薦演算法

我們把個性化推薦演算法放在二分圖當中,給用戶推薦物品就轉變成了度量用戶節點和商品節點的相關性,相關性越高的物品在推薦列表當中的權重就越大。一般來說頂點相關性取決於三個方面:

  • 兩個頂點之間的路徑數;
  • 兩個頂點之間路徑的長度;
  • 兩個頂點之間的路徑經過的頂點。

相關性高的一對頂點一般具有如下特徵:

  • 兩個頂點之間有很多路徑相連;
  • 連接兩個頂點之間的路徑長度都比較短;
  • 連接兩個頂點之間的路徑不會經過出度比較大的頂點。

基於上面3個主要因素,研究人員設計了很多計算圖中頂點之間相關性的方法。下一節將介紹一種基於隨機遊走的PersonalRank演算法。

PersonalRank

假設要給用戶\(u\)進行個性化推薦,可以從用戶\(u\)對應的節點\(v_u\)開始在用戶物品二分圖上進行隨機遊走。遊走到任何一個節點時,首先按照概率\(\alpha\)決定是繼續遊走,還是停止這次遊走並從\(v_u\)節點開始重新遊走。如果決定繼續遊走,那麼就從當前節點指向的節點中按照均勻分布隨機選擇一個節點作為遊走下次經過的節點。這樣,經過很多次隨機遊走後,每個物品節點被訪問到的概率會收斂到一個數。最終的推薦列表中物品的權重就是物品節點的訪問概率。

\[\begin{equation}
\mathrm{PR}(V)=\left\{
\begin{aligned}
\alpha \sum_{v’ \in \mathrm{in}(v)}\frac{\mathrm{PR}(v’)}{|\mathrm{out}(v’)|}\quad (v \ne v_u)\\
(1-\alpha)+\alpha\sum_{v’ \in \mathrm{in}(v)}\frac{\mathrm{PR}(v’)}{|\mathrm{out}(v’)|}\quad (v=v_u)
\end{aligned}
\right.
\end{equation}
\]

用程式碼來表示:

def PersonalRank(G, alpha, root):
    rank = dict()
    rank = {x:0 for x in G.keys()}
    rank[root] = 1
    for k in range(20):
        tmp = {x:0 for x in G.keys()}
        for i, ri in G.items():
            for j, wij in ri.items():
                if j not in tmp:
                    tmp[j] = 0
                tmp[j] += 0.6 * rank[i] / (1.0 * len(ri))
                if j == root:
                    tmp[j] += 1 - alpha
        rank = tmp
    return rank

雖然PersonalRank演算法可以通過隨機遊走進行比較好的理論解釋,但該演算法在時間複雜度上有明顯的缺點。因為在為每個用戶進行推薦時,都需要在整個用戶物品二分圖上進行迭代,直到整個圖上的每個頂點的PR值收斂。這一過程的時間複雜度非常高,不僅無法在線提供實時推薦,甚至離線生成推薦結果也很耗時。為了解決PersonalRank每次都需要在全圖迭代並因此造成時間複雜度很高的問題,這裡給出 兩種解決方案。第一種很容易想到,就是減少迭代次數,在收斂之前就停止。這樣會影響最終的 精度,但一般來說影響不會特別大。另一種方法就是從矩陣論出發,重新設計演算法。

我們將PR演算法設計成矩陣的形式,令\(M\)為二分圖的轉移概率矩陣,即

\[M(v,v’)=\frac{1}{\mathrm{out}(v)}
\]

那麼迭代公式修改為:

\[r = (1-\alpha)r_0 + \alpha M^T r
\]

我們解一下這個方程

\[r = (1-\alpha)(1-\alpha M^T)^{-1}r_0
\]

這裡的\((1-\alpha M^T)\)是稀疏矩陣,對其快速求逆即可。

後記

最近這兩天出去過節了,斷更了幾天,我又開始繼續更新這個系列了。這個系列後續可能就比較快的更新完,再說一個好消息,更新完這個系列之後,王喆編著的《深度學習推薦系統》以及相關的實踐課程影片我也買了,將繼續更新《深度學習推薦系統》以及實踐影片課的讀書筆記,大家可以關注一下,敬請期待。