1. 程式人生 > >筆記︱基於網路節點的node2vec、論文、演算法python實現

筆記︱基於網路節點的node2vec、論文、演算法python實現

看到一個很有意思的演算法,而且騰訊朋友圈lookalike一文中也有提及到,於是蹭一波熱點,學習一下。論文是也發KDD2016
.
.

一、主要論文:node2vec: Scalable Feature Learning for Networks

本文的特徵抽取方式類似於聚類分析的非監督方法,本質上都是利用相鄰節點之間的聯絡。文中提到了網路中的節點一般有兩種相似度量:1.內容相似性,2.結構相似性。其中內容相似性主要是相鄰節點之間的相似性,而結構上相似的的點並不一定是相鄰的,可能隔得很遠,這也是文中為何要把BFS和DFS相結合來選擇鄰居節點的原因。

文章的主要想法就是,利用SkipGram的方法,來為Networks抽取Representation。那麼,自然,根據SkipGram的思路,最重要的就是定義這個Context,或者說是Neighborhood。​從文字的角度來說,這個Neighborhood當然就是當前Word周圍的字,這個定義非常自然。但是對於Graph或者Network來說就來得沒那麼容易了。

文章闡述了一般所採用Depth-First Search或者是Breadth-First Search來Sample一個Node的周邊Node的問題。簡單來說,BFS比較容易有一個Microscopic的View而DFS容易有一個Macro-view,兩者都有Representative的問題。

文章的核心思想是採用Random Walk來代替DFS或者BFS。文章定義了一種二階的Random Walk,擁有兩個引數,來控制多大的概率反覆經過一些Node和控制所謂的Inward和Outward。總之,整個Random Walk的目的就是在DFS和BFS之間採取某種平衡。

文章雖然提出的是關於Node Feature提取的演算法,但是Edge Feature也可以很容易從Node Feature匯出。

總體感覺是,硬要用SkipGram或者WordVec的想法在Networks上做,還顯得比較牽強。因為有這個Neighborhood的概念,在Graph上,反而不是那麼直觀得定義,因此所有類似的工作都顯得比較彆扭。當然,這篇文章也不失為一種不錯的Heuristic。​
這裡寫圖片描述

這裡寫圖片描述

.
.
.

二、python實現

案例:
To run node2vec on Zachary’s karate club network, execute the following command from the project home directory:

python src/main.py
--input graph/karate.edgelist --output emb/karate.emd

Options

You can check out the other options available to use with node2vec using:

python src/main.py --help

Input

The supported input format is an edgelist:

node1_id_int node2_id_int <weight_float, optional>

The graph is assumed to be undirected and unweighted by default. These options can be changed by setting the appropriate flags.

Output

The output file has n+1 lines for a graph with n vertices. The first line has the following format:

num_of_nodes dim_of_representation

The next n lines are as follows:

node_id dim1 dim2 ... dimd

where dim1, … , dimd is the d-dimensional representation learned by node2vec.
.
.
.

三、騰訊對node2vec的應用

這個橫軸是與廣告進行互動的好友個數,縱軸是使用者對廣告的關注率(包括檢視,點贊或者評論),我們發現這個關注率會隨著好友數的增加而上升。這個資料拐點差不多是3到5個好友。
這裡寫圖片描述

重點會挖掘這兩個價值,就是社交同質性和社交影響力。
實際上在一個社交網路的節點也是這樣的,我們經常會存在一些大的節點,他會有非常多的好友,有的人好友就達不到那麼多。所以說其實在社交網路裡面的一個節點的分佈也是冪律分佈。如何把Wodrd2Vec遷移到node2vec,這個時候就要產生一個節點的序列,它對應到了自然語言處理的一條句子,圖結構裡面的節點相當於NLP的一個單詞。

所以在圖網路上按照一個搜尋的方法生成節點序列,這個節點的序列可以對應到自然語言的一個句子,後面我們通過Wodrd2Vec的框架,將節點embedding為一個向量。所以對於做network embedding的時候,這個生成節點序列的搜尋策略非常重要。最簡單的一個方法,就是隨機遊走,隨機遊走一方面生成節點序列,另一方面也是對圖的一種取樣,降低了計算量。

這裡寫圖片描述

比如說我們的一個社交網路,我的同學會形成一個社團,設計這個P往回走,就更容易走到我這個群體。當P越大,它會越能體現同質性。Q越大的時候,它其實能夠體現這種結構的相似性,不同的節點有不同的作用。比如說F節點和E節點它是連線這兩個社團的橋接點。當Q大的時候,它體現的是網路結構的相似性。這時候我們怎麼選P和Q?這個可以根據實際任務進行半監督的學習。

這裡寫圖片描述

給大家看一下node2vec的結果,先給大家看這個演算法的輸出。這裡有一個簡單的圖,做embedding之後的結果,1和2的節點向量是一樣的,它會是重疊的一個向量,3、4、5、6也是一個重合的節點,它表達的是什麼呢?為什麼1和2完全重疊?其實1和2的網路環境是一模一樣的,這個embedding的結果表達是是節點的社交網路環境,也就是我們說的拓撲特徵。
對社交相似性的學習框架,大家可以看下面的圖。 我們建立一個迴歸的model。現在做的是SVR模型。輸入好友網路,溝通網路、文章的轉發閱讀網路等等,進行embedding得到特徵向量表達,通過SVR模型,學習到這些特徵和廣告相似度的函式關係。這個函式關係計算出好友相似度,可以對好友進行排序。

這裡寫圖片描述

我們看一下演算法的效果。我們評估演算法的效果,最直接的就是說我有多個演算法,廣告主需要100萬的使用者,我這幾個演算法都給出100萬用戶,然後看一下這100萬的使用者點選量是怎麼樣的,我們叫Lift值。其他的演算法跟它進行對比,看一下它的效果有沒有提升。那我們的演算法相比直接的二分類模型有2倍-3倍的lift。

這裡寫圖片描述

.

延伸一:網路與詞向量

來源於:網路與幾何的糾纏 | 張江
最近,深度學習成為了科學界的新寵。人們將大量的資料扔進了神經網路中,以期待它能夠自己學習到資料中蘊藏的模式。然而,目前的深度學習處理的資料大多僅僅侷限在影象和文字,但卻不包括網路。這是因為,網路的本質在於節點之間的連線資訊,而這種資訊很難被結構化為標準的資料。怎麼辦呢?

答案就在於空間。只要我們將網路嵌入到了一個幾何空間中,我們就可以將每個節點的座標視作該節點的特徵,從而放到神經網路中進行學習和訓練。那麼,針對一個一般性的網路,我們又如何計算每一個節點的空間座標呢?

答案就在於DeepWalk演算法。它首先在網路上釋放大量的隨機遊走粒子,這些粒子在給定的時間內就會走出一個節點構成的序列。我們不妨將節點視作單詞,於是它們生成的序列就構成了句子,我們便可以得到一種節點由序列構成的“語言”。接下來,我們就可以應用強大的Word2Vec演算法,計算出每個節點“單詞”的向量表示,也就是空間座標了。
這裡寫圖片描述
這種節點嵌入的演算法可以很好地反映節點之間的連線資訊,或者我們可以將DeepWalk演算法得到的節點座標視作對每個節點連線資訊的編碼。那些連線結構上相似的節點會在空間中彼此靠近。
這裡寫圖片描述
有了從結構到空間的這種轉換,我們便可以利用普通的聚類和分類演算法來對複雜網路進行處理。
.

延伸二:NE(Network Embedding)論文小覽

自從word2vec橫空出世,似乎一切東西都在被embedding,今天我們要關注的這個領域是Network Embedding,也就是基於一個Graph,將節點或者邊投影到低維向量空間中,再用於後續的機器學習或者資料探勘任務,對於複雜網路來說這是比較新的嘗試,而且取得了一些效果。

本文大概梳理了最近幾年流行的一些方法和論文,paper主要是來自thunlp/NRLPapers 這個List,並摻雜了一些其他論文。大概看了一遍,簡單總結一下,希望對大家有所幫助,如有不嚴謹的地方,還望指正。
拋開一些傳統的流形學習方法不談,下面大概以這個outline組織(區分並不嚴格):
此處輸入圖片的描述
這裡寫圖片描述

DeepWalk(Online Learning of Social Representations.)

DeepWalk是KDD 2014的一篇文章,彼時word2vec在文字上的成功應用掀起來一波向量化的浪潮,word2vec是根據詞的共現關係,將詞對映到低維向量,並保留了語料中豐富的資訊。DeepWalk演算法思路其實很簡單,對圖從一個節點開始使用random walk來生成類似文字的序列資料,然後將節點id作為一個個「詞」使用skip gram訓練得到「詞向量」。
思路雖然簡單,背後是有一定道理的,後面一些工作有證明這樣做其實等價於特殊矩陣分解(Matrix Factorization)。而DeepWalk本身也啟發了後續的一系列工作。

node2vec(Scalable Feature Learning for Networks)

node2vec在DW的基礎上,定義了一個bias random walk的策略生成序列,仍然用skip gram去訓練。
論文分析了BFS和DFS兩種遊走方式,保留的網路結構資訊是不一樣的。
DeepWalk中根據邊的權重進行隨機遊走,而node2vec加了一個權重調整引數α:t是上一個節點,v是最新節點,x是候選下一個節點。d(t,x)是t到候選節點的最小跳數。
通過不同的p和q引數設定,來達到保留不同資訊的目的。當p和q都是1.0的時候,它等價於DeepWalk。

這裡寫圖片描述

MMDW(Max-Margin DeepWalk Discriminative Learning of Network Representation)

DW本身是無監督的,如果能夠引入label資料,生成的向量對於分類任務會有更好的作用。
之前提到過有證明DW實際上是對於一個特殊矩陣M的分解,
這篇文章將DeepWalk和Max-Margin(SVM)結合起來,從損失函式看是這兩部分組成:
1.訓練的時候是分開優化,固定X,Y優化W和ξ,其實就是multi class 的 SVM。
2.固定W和ξ優化X,Y的時候稍微特殊一點,算了一個biased Gradient,因為損失函式裡有x和w的組合。
這樣在訓練中同時優化discrimination和representation兩部分,達到一個好的效果。

這裡寫圖片描述

TADW(Network Representation Learning with Rich Text Information.)

文章裡有DeepWark等同於M的矩陣分解的簡單證明,而在實際中,一些節點上旺旺會有文字資訊,所以在矩陣分解這個框架中,將文字直接以一個子矩陣的方式加入,會使學到的向量包含更豐富的資訊。
文字矩陣是對TFIDF矩陣的SVD降維結果。
此處輸入圖片的描述
.

延伸三:基於word2vec和doc2vec使用者表示方法

(1)使用者表示方法

本文采用了五種使用者表示方法,分別是One-Hot表示、基於使用者文字的分散式表示、基於使用者關係網路的分散式表示、半監督的網路分散式表示和聯合表示。
本節使用word2vec和doc2vec兩個工具通過使用者的文字資料分別學習使用者的分散式表示,並採用邏輯迴歸分類器對使用者的不同屬性進行分類。

利用基於word2vec(生成的向量長度為100,視窗大小為5,模型為CBOW模型,演算法為Hierarchical Softmax模型)生成的使用者分散式表示實驗結果見表 2。
這裡寫圖片描述
利用基於doc2vec(生成的向量長度為100,視窗大小為5,模型為CBOW模型,演算法為Hierarchical Softmax模型錯誤。)生成的使用者分散式表示實驗結果見表3。
這裡寫圖片描述
從實驗結果的對比可以看出,單純詞向量累加的形式所獲取到的使用者分散式表示並不能有效地提高實驗的效果,相反,各個引數都有所下降。與之相比,採用doc2vec工具直接得到的使用者分散式的表現表示雖然較之詞袋模型仍然有所下降,但是卻要高於word2vec累加的表現。

(2)使用者的關係網路

我們使用Deepwalk和LINE兩個工具通過使用者的關係網路資料分別學習使用者的分散式表示,並採用邏輯迴歸分類器對使用者的不同屬性進行分類。

延伸四:Flownetwork:流網路的開源Python包

南京大學的王成軍老師和芝加哥大學的吳令飛博士開發了一個開源工具包Flownetwork,將常用的計算都整合到了一起。初學者可以直接呼叫該包完成各種有關開放流網路的計算。
這裡寫圖片描述

然後進行注意力網路的分析:

首先我們可以用help語句來檢視一下這個流網路的結構:

help(fn.constructFlowNetwork)
Help on function constructFlowNetwork in module flownetwork.flownetwork:
constructFlowNetwork(C)
   C is an array of two dimentions, e.g.,
   C = np.array([[user1, item1],
      [user1, item2],
      [user2, item1],
      [user2, item3]])
   Return a balanced flow networ

在瞭解了這個網路的架構之後,我們就可以自己建立一個流網路:

demo = fn.attention_data
gd = fn.constructFlowNetwork(demo)

為了更好的瞭解這個流網路的結構,我們可以利用matplotlib畫出這個demo的流網路:

# drawing a demo network
fig = plt.figure(figsize=(12, 8),facecolor='white')
pos={0: np.array([ 0.2 ,  0.8]),
 2: np.array([ 0.2,  0.2]),
 1: np.array([ 0.4,  0.6]),
 6: np.array([ 0.4,  0.4]),
 4: np.array([ 0.7,  0.8]),
 5: np.array([ 0.7,  0.5]),
 3: np.array([ 0.7,  0.2 ]),
 'sink': np.array([ 1,  0.5]),
'source': np.array([ 0,  0.5])}
width=[float(d['weight']*1.2) for (u,v,d) in gd.edges(data=True)]

edge_labels=dict([((u,v,),d['weight']) for u,v,d in gd.edges(data=True)])nx.draw_networkx_edge_labels(gd,pos,edge_labels=edge_labels,
font_size = 15, alpha = .5)

nx.draw(gd, pos, node_size = 3000, node_color = 'orange',
 alpha = 0.2, width = width, edge_color='orange',style='solid')
nx.draw_networkx_labels(gd,pos,font_size=18)

plt.show()

然後我們就畫出了這個demo的流網路圖:

這裡寫圖片描述