图与推荐系统(一):Graph Embedding之DeepWalk (原理 + 代码实战)

2021年下半年大部分时间都在秋招or浪,停笔了几个月,正好前段时间玩了一个推荐系统比赛,wsdm cup的亚马逊跨境电商任务,其中用到了几个图模型,也拿到了冠军,寒假在家准备系统的梳理一遍graph在推荐当中的应用,包括算法和代码

why graph embedding?

图是数据的有意义且易于理解的表示形式,但是出于下面的原因需要对图进行嵌入表示。

  • 在graph直接进行机器学习具有一定的局限性,我们都知道图是由节点和边构成的,这些向量关系一般只能使用数学,统计或者特定的子集进行表示,但是嵌入之后的向量空间具有更加灵活和丰富的计算方式;
  • 图嵌入能够压缩数据, 我们一般用邻接矩阵描述图中节点之间的连接。连接矩阵的维度是|V| x |V|,其中|V|是图中节点的个数。矩阵中的每一列和每一行都代表一个节点。矩阵中的非零值表示两个节点已连接。将邻接矩阵用用大型图的特征空间几乎是不可能的。一个具有1M个节点和1Mx1M的邻接矩阵的图该怎么计算和表示呢?嵌入可以看做是一种压缩技术,能够起到降维的作用;
  • 向量计算比直接在图上操作更加的简单、快捷。

1.原理简述

在这里插入图片描述

DeepWalk 的思想类似 word2vec,使用图中节点与节点的共现关系来学习节点的向量表示。那么关键的问题就是如何来描述节点与节点的共现关系,DeepWalk 给出的方法是使用随机游走 (RandomWalk) 的方式在图中进行节点采样。RandomWalk 是一种可重复访问已访问节点的深度优先遍历算法。给定当前访问起始节点,从其邻居中随机采样节点作为下一个访问节点,重复此过程,直到访问序列长度满足预设条件。

DeepWalk的本质是在图结构上进行随机游走,生成Item序列,然后将这些Item序列作为训练样本输入Skip-Gram进行训练,得到Item的Embedding。

DeepWalk 算法主要包括两个步骤,第一步为随机游走采样节点序列,第二步为使用word2vec 学习表达向量。

①构建同构网络,从网络中的每个节点开始分别进行 Random Walk 采样,得到局部相关联的训练数据;
②对采样数据进行 SkipGram 训练,将离散的网络节点表示成向量化.

2.代码实现

一共就两步,采样序列+送给word2vec学出embedding。这里参考https://github.com/shenweichen/GraphEmbedding中,通过并行的方式加速路径采样,我们固定为每个进程分配指定数量的num_walks的方式,这样可以最大限度减少进程频繁创建与销毁的时间开销。

数据集是wiki数据集,包含 已经处理好的2,405 个网页和17,981条网页之间的链接关系,以及每个网页的所属类别。

导入包和图模型

import networkx as nx
from gensim.models import Word2Vec
import pandas as pd
import numpy as np
import itertools
import math
import random
from joblib import Parallel, delayed
from tqdm import trange

import warnings

warnings.filterwarnings('ignore')
#从边列表中读取图形
G = nx.read_edgelist('./data/wiki/Wiki_edgelist.txt',
                         create_using=nx.DiGraph(), nodetype=None, data=[('weight', int)])

并行的方式采样seq

假设walk N次,在每一次walk中,所有的node都采用随机游走的方式产生以各自node为起点的序列。通过Parallel和delay函数的配合,为每个线程分配好各自要跑的walk数,这样能快速的完成seq的采样。

def partition_num(num, workers):
    if num % workers == 0:
        return [num//workers]*workers
    else:
        return [num//workers]*workers + [num % workers]


class RandomWalker:
    def __init__(self, G):

        self.G = G
            
    def deepwalk_walk(self, walk_length, start_node):

        walk = [start_node]

        while len(walk) < walk_length:
            cur = walk[-1]   #当前序列的最后一个值
            cur_nbrs = list(self.G.neighbors(cur))  #获取所有的邻居节点
            if len(cur_nbrs) > 0:     
                walk.append(random.choice(cur_nbrs))   #随机选择一个邻居节点加入队列
            else:
                break
        return walk
 

    def simulate_walks(self, num_walks, walk_length, workers=1, verbose=0):

        G = self.G

        nodes = list(G.nodes())

        results = Parallel(n_jobs=workers, verbose=verbose, )(
            delayed(self._simulate_walks)(nodes, num, walk_length) for num in
            partition_num(num_walks, workers))

        walks = list(itertools.chain(*results))
        
        return walks

    def _simulate_walks(self, nodes, num_walks, walk_length,):
        walks = []
        for _ in range(num_walks):
            random.shuffle(nodes)
            for v in nodes:
                walks.append(self.deepwalk_walk(
                    walk_length=walk_length, start_node=v))
        
        return walks

设置参数,通过word2vec学embedding

num_walks = 80
walk_length = 10
workers = 4

#根据RandomWalker产生序列
rw = RandomWalker(G)
sentences = rw.simulate_walks(num_walks=num_walks, walk_length=walk_length, workers=workers, verbose=1)


model = Word2Vec(sentences = sentences,
              vector_size = 128,
              min_count=5,
              sg =1,
              hs=1,
              workers = workers,
              window=5, 
              epochs=3)


#获取embedding dict
embedding_dict = {}
for word in G.nodes():  
    embedding_dict[word] = model.wv[word]

查看两个embedding之间的余弦相似度

#计算两个embedding之间的余弦相似度
def cosine_similarity(x,y):
    num = x.dot(y.T)
    denom = np.linalg.norm(x) * np.linalg.norm(y)
    return num / denom

result = cosine_similarity(embedding_dict['1397'],embedding_dict['1470'])   
result
0.69411856

graph结构

nx.draw(G, with_labels=True, font_weight='bold')

在这里插入图片描述

【参考】

  1. 总结|为什么要进行图嵌入Graph embedding?
  2. 【Graph Embedding】DeepWalk:算法原理,实现和应用
  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值