DeepWalk隨機游走

算法思想

2021-10-09_17-04.png

參考資料

https://zhuanlan.zhihu.com/p/45167021

代碼實現(xiàn)與注解

思路

  • 理清successor,outdegree函數(shù)的輸入輸出
  • 查看補全函數(shù)的返回類型--分析可能的結(jié)果--我最初的猜測:這walks應(yīng)該是多個向量的集合,最后確實也是【[[],..]這樣的結(jié)構(gòu)多用于擴充,然后聯(lián)想需要學習向量,所以想到向量遞推的那種向量集合】
  • 生成隨機采樣索引序列集 -- 這個需要匹配采樣形狀,以及索引閾值--我是參考一個示例修改的,感悟是: 利用隨機數(shù)0~1,給rand傳入指定shape,再乘以一個相同shape的數(shù)據(jù),可以得到一個>=0, <=最大出度-1的值,這樣就可以用來索引采樣了
  • 理清上下文變量關(guān)系,進行zip打包遍歷到一起,然后進行聚合操作即可。

Code

%%writefile userdef_graph.py
from pgl.graph import Graph

import numpy as np


class UserDefGraph(Graph):
    def random_walk(self, nodes, walk_len):
        """
        輸入:nodes - 當前節(jié)點id list (batch_size,)
             walk_len - 最大路徑長度 int
        輸出:以當前節(jié)點為起點得到的路徑 list (batch_size, walk_len)

        用到的函數(shù)
        1. self.successor(nodes)
           描述:獲取當前節(jié)點的下一個相鄰節(jié)點id列表
           輸入:nodes - list (batch_size,)
           輸出:succ_nodes - list of list ((num_successors_i,) for i in range(batch_size))
        2. self.outdegree(nodes)
           描述:獲取當前節(jié)點的出度
           輸入:nodes - list (batch_size,)
           輸出:out_degrees - list (batch_size,)
        """
        # 首先獲得當前節(jié)點列表對應(yīng)的一個向量
        walks = [[node] for node in nodes]
        # 游走路徑中節(jié)點對應(yīng)id號
        walks_ids = np.arange(0, len(nodes))
        # 當前節(jié)點情況
        cur_nodes = np.array(nodes)
        # 根據(jù)游走長度進行遍歷--破出條件:1. range結(jié)束;2. outdegree==0【出度為零,沒有可繼續(xù)的節(jié)點】
        for l in range(walk_len):
            """選取有下一個節(jié)點的路徑繼續(xù)采樣,否則結(jié)束"""
            # 計算當前節(jié)點的出度--也就是對應(yīng)有哪些位置的鄰近節(jié)點
            outdegree = self.outdegree(cur_nodes)
            # 根據(jù)出度來確定掩碼--True, False--將出度為0的部分復(fù)制為False,反之True
            walk_mask = (outdegree != 0)
            # 判斷是否沒有可繼續(xù)的節(jié)點情況--出度為0
            if not np.any(walk_mask):
                break
            # 根據(jù)掩碼獲取可繼續(xù)前進的節(jié)點,作為后邊討論的當前可前行節(jié)點
            cur_nodes = cur_nodes[walk_mask]
            # 獲取掩碼下,原節(jié)點id,組成新的work_ids用于后邊討論,但本身還是作為一個節(jié)點的標記,對應(yīng)這是第幾個節(jié)點
            walks_ids = walks_ids[walk_mask]
            # 根據(jù)掩碼獲取相應(yīng)的不為0的出度--用于后邊計算前行的路徑
            outdegree = outdegree[walk_mask]
            # 返回可繼續(xù)的節(jié)點集合 successor 可獲取當前節(jié)點的下一個相鄰節(jié)點id列表,
            # 那么successor 計算出下一節(jié)點的集合后,我們需要從中隨機取出一個節(jié)點--所以我們要創(chuàng)建隨機采樣的index_list(索引序列集)
            succ_nodes = self.successor(cur_nodes)
            # 創(chuàng)建index_list=>為了才到合適的index信息,采用np.floor與np.random,rand()實現(xiàn):
            # eg: np.floor(np.random.rand(outdegree.shape[0]) * outdegree).astype('int64')
            # np.random.rand(outdegree.shape[0]): 根據(jù)出度集的形狀來取得相應(yīng)形狀的隨機數(shù)--這里體現(xiàn)游走的隨機性
            # np.random.rand(outdegree.shape[0]) * outdegree:利用生成的隨機數(shù)與出度集對應(yīng)元素相乘——這里得到一些列的隨機數(shù)
            # 隨機數(shù)范圍在0~最大出度值--保證路徑有效
            # np.floor(np.random.rand(outdegree.shape[0]) * outdegree)——實現(xiàn)向下取整,這樣就得到了相應(yīng)游走路徑中接下來那個點的索引
            sample_index = np.floor(np.random.rand(outdegree.shape[0]) * outdegree).astype('int64')
            """
            具體實例:
            np.floor(np.random.rand(20) * 3).astype('int64')
            result: array([0, 1, 2, 1, 0, 0, 0, 0, 1, 1, 1, 2, 0, 2, 2, 2, 2, 1, 2, 0])
            """
            # 知道了隨機采樣的序列集了,那么接下就是分配新的游走路徑了
            # 用于后邊存放—— 裝配有下一個節(jié)點的新路徑
            next_nodes = []
            # succ_nodes:相鄰節(jié)點id列表
            # sample_index:對應(yīng)出度生成的隨即索引集
            # walks_ids:游走路徑中節(jié)點對應(yīng)id號
            for s, ind, walk_id in zip(succ_nodes, sample_index, walks_ids):
                # 將節(jié)點列表、隨機采樣序列、游走路徑中節(jié)點對應(yīng)id號一一對應(yīng)進行填充
                # 為相應(yīng)節(jié)點添加可以繼續(xù)前行的節(jié)點,形成一條路徑
                walks[walk_id].append(s[ind])# walks=>[[], [], []]是這種形式的
                # 同時獲取接下來要重新討論游走時所需的新節(jié)點
                next_nodes.append(s[ind])
                """
                如:從1走到了2,從3走到了7: [[1], [3]]=>[[1, 2], [3, 7]]     
                next_nodes.append(s[ind])        
                # 接下來自然就該考慮把新的2, 7 作為下一次游走時討論出度的節(jié)點啦
                """
            cur_nodes = np.array(next_nodes)  # 將節(jié)點轉(zhuǎn)換為np類型,方便一些操作運算--同時保證前后數(shù)據(jù)類型
            # 并且list中,元素本質(zhì)是對象。如:L = [1, 2, 3],需要3個指針和三個整數(shù)對象,對于數(shù)值運算比較浪費內(nèi)存和CPU
            # Numpy提供了ndarray(N-dimensional array object)對象:存儲單一數(shù)據(jù)類型的多維數(shù)組。
        # 遍歷完游走長度的次數(shù),就可以返回得到的隨機游走路徑啦
        return walks

print(np.floor(np.random.rand(20) * 3).astype('int64'))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容