目錄
- 數據的圖示
- 不同類型的基於圖的特征
- 節點屬性
- 局部結構特征
- 節點嵌入
- DeepWalk簡介
- 在Python中實施DeepWalk以查找相似的Wikipedia頁面
數據的圖示
當你想到“網絡”時,會想到什么?通常是諸如社交網絡,互聯網,已連接的IoT設備,鐵路網絡或電信網絡之類的事物。在圖論中,這些網絡稱為圖。
網絡是互連節點的集合。節點表示實體,它們之間的連接是某種關系。
例如,我們可以用圖的形式表示一組社交媒體帳戶:
節點是用戶的數字檔案,連接表示他們之間的關系,例如誰跟隨誰或誰與誰是朋友。
圖的用例不僅限於社交媒體!我們還可以使用圖和網絡表示其他類型的數據(並且在本文中我們將介紹一個獨特的行業用例)。
為什么我們將數據表示為圖?
為什么不僅僅使用典型的數據可視化技術來可視化數據?為什么要更復雜並學習新概念?下面我們會給出答案。
圖數據集和數據庫可幫助我們應對在處理結構化數據時面臨的若干挑戰。這就是為什么當今的主要科技公司,例如Google,Uber,Amazon和Facebook使用某種形式的圖的原因。
讓我們以一個例子來理解為什么圖是數據的重要表示形式。看下圖:
這是一小部分Facebook用戶(a, B, C, D, E, F, G)的數據集。圖像的左半邊包含這個數據的表格形式。每一行代表一個用戶和他/她的一個朋友。
右半部分包含代表同一組用戶的圖。該圖的邊緣告訴我們,連接的節點是Facebook上的朋友。現在,讓我們解決一個簡單的查詢:
“找到用戶A的朋友和用戶A朋友的朋友。”
查看表格數據和上面的圖。哪種數據形式更適合回答此類查詢?
使用圖來解決該問題要容易得多,因為我們只需要遍歷從節點A長度為2的路徑(ABC和ADF),即可找到朋友和朋友的朋友。
因此,圖可以輕松捕獲節點之間的關系,這在常規數據結構中是一項艱巨的任務。現在,讓我們看看使用圖可以解決什么樣的問題。
基於圖的特征的不同類型
為了解決上述問題,我們無法將圖直接提供給機器學習模型。我們必須首先從中創建特征,然后模型將使用這些特征。
此過程類似於我們在自然語言處理(NLP)或計算機視覺中所做的過程。我們首先從文本或圖像中提取數字特征,然后將這些特征作為輸入提供給機器學習模型:
從圖中提取的特征可以大致分為三類:
- 節點屬性:我們知道圖中的節點代表實體,並且這些實體具有自己的特征屬性。我們可以將這些屬性用作每個節點的特征。例如,在航空公司航線網絡中,節點將代表機場。這些節點將具有飛機容量,航站樓數量,着陸區等特征。
2.局部結構特點:節點的度(相鄰節點的數量),相鄰節點的平均度,一個節點與其他節點形成的三角形數,等等。 - 節點嵌入:上面討論的特征僅包含與節點有關的信息。它們不捕獲有關節點上下文的信息。在上下文中,我指的是周圍的節點。節點嵌入通過用固定長度向量表示每個節點,在一定程度上解決了這個問題。這些向量能夠捕獲有關周圍節點的信息(上下文信息)
用於學習節點嵌入的兩個重要的現代算法是DeepWalk和Node2Vec。在本文中,我們將介紹並實現DeepWalk算法。
DeepWalk簡介
要了解DeepWalk,重要的是要正確理解詞嵌入及其在NLP中的使用方式。我建議在下面的文章中仔細閱讀Word2Vec的解釋:
https://www.analyticsvidhya.com/blog/2019/07/how-to-build-recommendation-system-word2vec-python/?utm_source=blog&utm_medium=graph-feature-extraction-deepwalk
為了將事物置於上下文中,詞嵌入是文本的向量表示形式,它們捕獲上下文信息。讓我們看看下面的句子:
- 我乘巴士孟買
- 我乘火車去孟買
粗體字(公共汽車和火車)的向量將非常相似,因為它們出現在相同的上下文中,即粗體文本之前和之后的詞。該信息對於許多NLP任務非常有用,例如文本分類,命名實體識別,語言建模,機器翻譯等等。
我們還可以在每個節點的圖中捕獲此類上下文信息。但是,為了學習NLP空間中的詞嵌入,我們將句子提供給Skip-gram模型(淺層神經網絡)。句子是按一定順序排列的單詞序列。
因此,要獲得節點嵌入,我們首先需要安排圖中的節點序列。我們如何從圖中獲得這些序列?有一項針對該任務的技術稱為隨機游走。
什么是隨機游走?
隨機游走是一種從圖中提取序列的技術。我們可以使用這些序列來訓練一個skip-gram模型來學習節點嵌入。
讓我說明一下隨機游走的工作原理。讓我們考慮下面的無向圖:
我們將在該圖上應用隨機游走並從中提取節點序列。我們將從節點1開始,並覆蓋任意方向的兩條邊:
從節點1,我們可以轉到任何連接的節點(節點3或節點4)。我們隨機選擇了節點4。現在再次從節點4開始,我們不得不隨機選擇前進的方向。我們將轉到節點5。現在我們有3個節點的序列:[節點1 –節點4 –節點5]。
讓我們生成另一個序列,但是這次是從另一個節點生成的:
讓我們選擇節點15作為原始節點。從節點5和6,我們將隨機選擇節點6。然后從節點11和2,我們選擇節點2。新序列為[節點15 –節點6 –節點2]。
我們將對圖中的每個節點重復此過程。這就是隨機游走技術的工作原理。
在生成節點序列之后,我們必須將它們提供給一個skip-gram模型以獲得節點嵌入。整個過程被稱為Deepwalk。
在下一節中,我們將在Wikipedia文章網絡上從頭開始實施DeepWalk。
在Python中實施DeepWalk以查找相似的Wikipedia頁面
這將是本文中最令人興奮的部分,尤其是如果你喜歡代碼。因此,請啟動這些Jupyter notebook!
我們將使用Wikipedia文章圖,並使用DeepWalk從中提取節點嵌入。然后,我們將使用這些嵌入來查找相似的Wikipedia頁面。
我們不會觸及這些文章中的任何文本。我們的目標是純粹基於圖的結構來計算頁面之間的相似度。
但是,等等。我們如何以及在何處獲得Wikipedia圖數據集?Seealsology這個出色的工具將為我們提供幫助。這有助於我們從任何Wikipedia頁面創建圖。你甚至可以提供多個Wikipedia頁面作為輸入。這是該工具的屏幕截圖:
如果一個頁面鏈接到另一個頁面,就會有一個圖表示兩個頁面之間的聯系。
看看在Seealsology中該圖的形成方式。值得一看:https://s3-ap-south-1.amazonaws.com/av-blog-media/wp-content/uploads/2019/11/graph_buildup.mp4?_=1
圖中的節點非常接近,並不一定意味着它們在語義上相似。因此,需要在向量空間中表示這些節點,我們可以在其中識別相似的節點。
當然,我們可以使用其他方法來完成此任務。例如,我們可以解析這些節點(Wikipedia頁面)中的所有文本,並在詞嵌入的幫助下用向量表示每個頁面。然后,我們可以計算這些向量之間的相似度以找到相似的頁面。但是,這種基於NLP的方法存在一些缺點:
- 如果有數百萬個節點,那么我們需要大量的計算能力來解析文本並從所有這些節點或頁面中學習詞嵌入
- 這種方法不會捕獲這些頁面之間連接的信息。例如,一對直接連接的頁面可能比一對間接連接的頁面具有更強的關系
這些缺點可以通過圖和節點嵌入輕松解決。因此,一旦你的圖准備就緒,就可以從Seealsology下載TSV文件。在此文件中,每一行都是一對節點。我們將使用此數據來重構圖,並在其上應用DeepWalk算法以獲得節點嵌入。
讓我們開始吧!你可以為此使用Jupyter Notebook或Colab。
導入所需的Python庫
import networkx as nx
import pandas as pd
import numpy as np
import random
from tqdm import tqdm
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
%matplotlib inline
加載數據集
你可以從這里下載.tsv文件:
https://s3-ap-south-1.amazonaws.com/av-blog-media/wp-content/uploads/2019/11/space_data.zip
df = pd.read_csv("space_data.tsv", sep = "\t")
df.head()
Output:
源和目標都包含Wikipedia實體。對於所有行,目標實體在源實體的Wikipedia頁面有其超鏈接。
構造圖
G = nx.from_pandas_edgelist(df, "source", "target", edge_attr=True, create_using=nx.Graph())
讓我們檢查圖中的節點數:
len(G)
Output: 2088
我們將處理2,088個Wikipedia頁面。
隨機游走
在這里,我定義了一個函數,將節點和被遍歷的路徑的長度作為輸入。它將從指定的輸入節點以隨機的方式穿過連接節點。最后,它將返回遍歷節點的順序:
def get_randomwalk(node, path_length):
random_walk = [node]
for i in range(path_length-1):
temp = list(G.neighbors(node))
temp = list(set(temp) - set(random_walk))
if len(temp) == 0:
break
random_node = random.choice(temp)
random_walk.append(random_node)
node = random_node
return random_walk
讓我們來試試節點“space exploration”這個函數:
get_randomwalk('space exploration', 10)
輸出:
在這里,我已指定要遍歷的長度為10。你可以更改此數字並進行操作。接下來,我們將捕獲數據集中所有節點的隨機游走序列:
# 從圖獲取所有節點的列表
all_nodes = list(G.nodes())
random_walks = []
for n in tqdm(all_nodes):
for i in range(5):
random_walks.append(get_randomwalk(n,10))
# 序列個數
len(random_walks)
輸出: 10,440
因此,將遍歷長度設置為10,我們得到了10,440個節點的隨機游動序列。我們可以將這些序列用作skip-gram模型的輸入,並提取該模型學習到的權重。
from gensim.models import Word2Vec
import warnings
warnings.filterwarnings('ignore')
DeepWalk
接下來,我們將使用隨機游走訓練skip-gram模型:
# 訓練skip-gram (word2vec)模型
model = Word2Vec(window = 4, sg = 1, hs = 0,
negative = 10, # 負采樣
alpha=0.03, min_alpha=0.0007,
seed = 14)
model.build_vocab(random_walks, progress_per=2)
model.train(random_walks, total_examples = model.corpus_count, epochs=20, report_delay=1)
現在,圖中的每個節點都由固定長度(100)的向量表示。讓我們找出與“space tourism”最相似的頁面:
model.similar_by_word('space tourism')
輸出:
很有趣!所有這些頁面都是與民用太空旅行相關的主題。可以為其他實體提取類似的節點。
現在,我想看看我們的節點嵌入如何捕獲不同節點之間的相似性。我已經從圖中挑選了一些節點,並將它們繪制在二維空間中:
terms = ['lunar escape systems','soviet moonshot', 'soyuz 7k-l1',
'moon landing','space food', 'food systems on space exploration missions',
'meal, ready-to-eat','space law', 'metalaw', 'moon treaty',
'legal aspects of computing','astronaut training', 'reduced-gravity aircraft',
'space adaptation syndrome', 'micro-g environment']
下面我定義了一個函數,該函數將在二維空間中繪制所選節點的向量:
def plot_nodes(word_list):
X = model[word_list]
# 減少維度為2
pca = PCA(n_components=2)
result = pca.fit_transform(X)
plt.figure(figsize=(12,9))
# 創建一個散點圖的投影
plt.scatter(result[:, 0], result[:, 1])
for i, word in enumerate(word_list):
plt.annotate(word, xy=(result[i, 0], result[i, 1]))
plt.show()
讓我們繪制選定的節點:
plot_nodes(terms)
輸出:
看起來不錯!如你所見,相似的Wikipedia實體被分組在一起。例如,“soviet moonshot”,“soyuz 7k-l1”,“moon landing”和“lunar escape systems”都嘗試登陸月球。
這就是為什么DeepWalk嵌入如此有用的原因。我們可以使用這些嵌入來解決與圖相關的多個問題,例如鏈接預測,節點分類,問題解答系統等等。
請執行下面的代碼。它會產生隨機游走序列和獲取類似的節點使用DeepWalk一個輸入節點。
# importing required libraries
import pandas as pd
import networkx as nx
import numpy as np
import random
from tqdm import tqdm
from sklearn.decomposition import PCA
import pprint
from gensim.models import Word2Vec
import warnings
warnings.filterwarnings('ignore')
# read the dataset
df = pd.read_csv("space_data.tsv", sep = "\t")
print(df.head())
G = nx.from_pandas_edgelist(df, "source", "target", edge_attr=True, create_using=nx.Graph())
G = nx.from_pandas_edgelist(df, "source", "target", edge_attr=True, create_using=nx.Graph())
print('The number of nodes in pur graph: ',len(G))
def get_randomwalk(node, path_length):
random_walk = [node]
for i in range(path_length-1):
temp = list(G.neighbors(node))
temp = list(set(temp) - set(random_walk))
if len(temp) == 0:
break
random_node = random.choice(temp)
random_walk.append(random_node)
node = random_node
return random_walk
print('\n\nRandom sequence of nodes generated from Random Walk\n\n')
while True:
first_node = input("Enter name of first node (for example 'space exploration') : ")
if len(first_node) > 0:
break
pprint.pprint(get_randomwalk(first_node, 10))
# 從圖中獲取所有節點的列表
all_nodes = list(G.nodes())
random_walks = []
for n in tqdm(all_nodes):
for i in range(5):
random_walks.append(get_randomwalk(n,10))
# 序列長度
len(random_walks)
# 訓練skip-gram (word2vec)模型
model = Word2Vec(window = 4, sg = 1, hs = 0,
negative = 10, # 負采樣
alpha=0.03, min_alpha=0.0007,
seed = 14)
model.build_vocab(random_walks, progress_per=2)
model.train(random_walks, total_examples = model.corpus_count, epochs=20, report_delay=1)
print('\n\n Get similar nodes\n\n')
while True:
any_node = input("Enter name of any node (for example 'space toursim') : ")
if len(any_node) > 0:
break
pprint.pprint(model.similar_by_word(any_node))
結尾
我真的很喜歡在本文中探索DeepWalk中的圖形數據,我迫不及待地想嘗試其他圖形算法。在接下來的幾周里,繼續關注這個系列吧!
我鼓勵你實施此代碼,試用它,並建立自己的圖模型。這是學習任何概念的最佳方法。完整的代碼在這里:https://github.com/prateekjoshi565/DeepWalk。
歡迎關注磐創博客資源匯總站:
http://docs.panchuang.net/
歡迎關注PyTorch官方中文教程站:
http://pytorch.panchuang.net/