【打卡-Coggle竞赛学习2023年2月】图节点嵌入

## Part4 图节点嵌入

### 背景介绍

图(Graphs)是一种对物体(objects)和他们之间的关系(relationships)建模的数据结构,物体以结点(nodes)表示,关系以边(edges)表示。图是复杂系统中常用的信息载体,可以表示现实中许多复杂关系,如社交网络、犯罪网络、交通网络等。

### 环境配置

实践环境建议以Python3.7+,且需要安装如下库:

  • numpy
  • pandas
  • networkx
  • igraph
  • gensim

### 学习打卡

任务名称难度
任务1:图属性与图构造低、1
任务2:图查询与遍历低、2
任务3:节点中心性与应用中、2
任务4:图节点嵌入算法(DeepWalk/node2vec)高、3
任务5:图节点嵌入算法:LINE/SDNE高、3
任务6:图节点嵌入算法:GraphGAN高、3
- 任务1:图属性与图构造
  • 步骤1:导入networkx
  • 步骤2:加载Wiki数据集,包含来自 19 个类别的 2405 个文档和它们之间的 17981个边。
  • 步骤3:使用networkx构造上述有向图
import pandas as pd
import numpy as np
import networkx as nx
import matplotlib.pyplot as plt

# 两列,分别为节点id,节点类别
group = pd.read_csv('http://mirror.coggle.club/dataset/graph-wiki/group.txt.zip', sep='\t', header=None)

# 两列,分别为出发节点id,目的节点id
graph = pd.read_csv('http://mirror.coggle.club/dataset/graph-wiki/graph.txt.zip', sep='\t', header=None)

g = nx.DiGraph()

# 只添加前100条边
g.add_edges_from(graph.values[:100])
nx.draw_spring(g)

# 添加所有数据
g = nx.DiGraph()
g.add_edges_from(graph.values[:])

在这里插入图片描述

- 任务2:图查询与遍历
  • 步骤1:使用networkx对Wiki数据集进行如下统计
    • 节点个数、边个数
    • 节点度平均
    • 存在指向自身节点的个数
  • 步骤2:对节点1397进行深度和广度遍历,设置搜索最大深度为5
  • 步骤3:判断节点1573与节点1397之间是否存在联通性
# 边个数 节点个数
g.number_of_edges(), g.number_of_nodes()

# 度均值
np.mean([x[1] for x in list(g.degree())])

# 对节点1397的深度5内进行深度和广度遍历
nx.dfs_tree(g, 1397, 5).nodes()
nx.bfs_tree(g, 1397, 5).nodes()

# 节点1573与节点1397之间的路径
list(nx.connectivity.node_disjoint_paths(g, 1573, 1397))

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

- 任务3:节点中心性与应用
  • 步骤1:筛选度最大的Top10个节点,并对节点深度1以内的节点进行可视化;
    在这里插入图片描述

  • 步骤2:使用PageRank筛选Top10个节点,并对节点深度1以内的节点进行可视化;
    在这里插入图片描述

  • 步骤3:文本关键词提取算法RAKE

    • 使用jieba对文本进行分词
      在这里插入图片描述

    • 单词作为节点,距离2以内的单词之间存在边

    • 计算单词打分 wordDegree (w)/ wordFrequency (w) wordDegree (�)/ wordFrequency (�)

    • 按照打分统计每个文章Top10关键词
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

  • 步骤4:文本关键词提取算法TextRank

    • 使用jieba对文本进行分词
    • 单词作为节点,距离2以内的单词之间存在边
    • 使用PageRank对单词进行打分
    • 按照打分统计每个文章Top10关键词
      在这里插入图片描述
      在这里插入图片描述

在这里插入图片描述

# 文章1
'''
一纸四季报,令芯片巨头英特尔一夜间股价重挫近6.5%,市值蒸发80亿美元,再度被AMD反超。

这份严重缩水的财报显示,英特尔在去年四季度营收大降32%至140亿美元,是2016年以来最低单季收入;净利润由三季度的10.2亿美元转为近7亿美元净亏损;毛利率更从2021年四季度的53.6%大幅下降至39.2%。

此番业绩“跳水”并非英特尔一家的一时失利,在全球PC出货量整体下滑的背景下,包括英特尔、AMD、英伟达、高通在内的芯片企业,均在过去一年里出现不同程度的收入与利润下滑,但英特尔的确是其中的重灾区。
'''

# 文章2
'''
2021年,成都地区生产总值已经超过1.99万亿元,距离2万亿门槛仅咫尺之间。在去年遭受多轮疫情冲击及高温限电冲击的不利影响下,2022年,成都市实现地区生产总值20817.5亿元,按可比价格计算,比上年增长2.8%。

成都因此成为第7个跨过GDP2万亿门槛的城市。目前,GDP万亿城市俱乐部中形成了4万亿、3万亿、2万亿和万亿这四个梯队。上海和北京在2021年跨过了4万亿,深圳2021年跨过了3万亿,重庆、广州、苏州和成都则是2万亿梯队。

在排名前十的城市中,预计武汉将超过杭州。武汉市政府工作报告称,预计2022年武汉地区生产总值达到1.9万亿元左右。而杭州市统计局公布的数据显示,杭州2022年地区生产总值为18753亿元。受疫情影响,武汉在2020年GDP排名退居杭州之后。
'''


# 文章3
'''
据报道,美国证券交易委员会(SEC)与特斯拉首席执行官埃隆·马斯克之间又起波澜。SEC正对马斯克展开调查,主要审查内容是,马斯克是否参与了关于特斯拉自动驾驶软件的不恰当宣传。

据知情人士透露,该机构正在调查马斯克是否就驾驶辅助技术发表了不恰当的前瞻声明。

特斯拉在2014年首次发布了其自动驾驶辅助功能,公司声称该功能可以让汽车在车道内自动转向、加速和刹车。目前所有特斯拉车辆都内置了该软件。
'''
# 筛选度最大的Top10个节点,并对节点深度1以内的节点进行可视化;
g_degree = pd.DataFrame(g.degree()).sort_values(by=1)
g_degree = g_degree.iloc[-10:]

selected_nodes = []
for node in g_degree[0].values:
    selected_nodes += list(nx.dfs_tree(g, node, 1).nodes())

nx.draw_spring(g.subgraph(selected_nodes), node_size=3)
# 使用PageRank筛选Top10个节点,并对节点深度1以内的节点进行可视化
g_pagerank = pd.DataFrame.from_dict(nx.pagerank(g), orient='index')
g_pagerank = g_pagerank.sort_values(by=0)

g_pagerank = g_pagerank.iloc[-10:]
selected_nodes = []
for node in g_pagerank[0].index:
    selected_nodes += list(nx.dfs_tree(g, node, 1).nodes())

nx.draw_spring(g.subgraph(selected_nodes), node_size=3)

文本关键词提取算法RAKE

import jieba
from collections import Counter

g2 = nx.Graph()
words = jieba.lcut(content)
words = [x for x in words if len(x) > 1]
for i in range(len(words)-2):
    for j in range(i-2, i+2):
        if i == j:
            continue
        g2.add_edge(words[i], words[j])

g2_node_gree = dict(g2.degree())
word_counter = dict(Counter(words))

g2_node_gree = pd.DataFrame.from_dict(g2_node_gree, orient='index')
g2_node_gree.columns = ['degree']

g2_node_gree['freq'] = g2_node_gree.index.map(word_counter)
g2_node_gree['score'] = g2_node_gree['degree'] / g2_node_gree['freq']

g2_node_gree.sort_values(by='score').index[-10:]

# ['32%', '140', '2016', '以来', '最低', '单季', '收入', '利润', '缩水', '净利润']
# ['增长', '2.8%', '成都', '2020', '成为', '超过', 'GDP2', '目前', '可比价格', '因此']
# ['主要', '审查', '内容', '参与', '关于', '软件', '所有', '宣传', '人士', '恰当']

文本关键词提取算法TextRank

g2 = nx.Graph()

words = jieba.lcut(content)
words = [x for x in words if len(x) > 1]
for i in range(len(words)-2):
    for j in range(i-2, i+2):
        if i == j:
            continue
        g2.add_edge(words[i], words[j])

g2_node_gree = pd.DataFrame.from_dict(nx.pagerank(g2), orient='index')
g2_node_gree.columns = ['degree']
g2_node_gree = g2_node_gree.sort_values(by='degree')

# ['39.2%', '四季', '一纸', 'AMD', '下滑', '四季度', '收入', '芯片', '亿美元', '英特尔']
# ['万亿元', '成都', '地区', '2021', '城市', '杭州', '武汉', '2022', '生产总值', '万亿']
# ['功能', '是否', '辅助', '调查', '恰当', 'SEC', '驾驶', '自动', '马斯克', '特斯拉']

img

- 任务4:图节点嵌入算法:
DeepWalk

/

node2vec
  • 步骤1:使用DeepWalk对Wiki数据集节点嵌入,维度为50维
    在这里插入图片描述

  • 步骤2:每个group中20%的节点作为验证集,剩余的作为训练集
    在这里插入图片描述

  • 步骤3:使用节点嵌入向量 + 逻辑回归进行训练,并记录验证集准确率
    在这里插入图片描述

  • 步骤4:使用node2vec重复上述操作
    在这里插入图片描述

  • 步骤5:使用t-SNE将节点的DeepWalk/node2vec特征降维,绘制散点图,节点颜色使用group进行区分
    deepwalk
    在这里插入图片描述
    node2vec
    在这里插入图片描述

2014 DeepWalk: Online Learning of Social Representations, PDF

DeepWalk的思想类似word2vec,使用图中节点与节点的共现关系来学习节点的向量表示。那么关键的问题就是如何来描述节点与节点的共现关系,DeepWalk给出的方法是使用随机游走(RandomWalk)的方式在图中进行节点采样。

RandomWalk是一种可重复访问已访问节点的深度优先遍历算法。给定当前访问起始节点,从其邻居中随机采样节点作为下一个访问节点,重复此过程,直到访问序列长度满足预设条件。

import random
def deepwalk(G, walk_length):
    nodes = G.nodes()
    history_walks = []

    # 对于每个节点
    for node in nodes:

        # 从当前节点开始
        random_walk_length = [node]

        # 开始游走
        for i in range(walk_length-1):

            # 找到节点邻居
            neighbors = list(G.neighbors(node))

            # 排除已经游走的邻居
            neighbors = list(set(neighbors) - set(random_walk_length))    
            if len(neighbors) == 0:
                break

            # 随机挑选邻居
            random_neighbor = random.choice(neighbors)            
            random_walk_length.append(random_neighbor)

            # 从下一个邻居继续游走
            node = random_neighbor

        # 此节点的游走路径
        history_walks.append(random_walk_length)

    return history_walks
g = nx.DiGraph()
# 构件图
g.add_edges_from(graph.values[:])
# 游走
history_walks = deepwalk(g, 100)

from gensim.models import Word2Vec
# 训练word2vec
w2v = Word2Vec(history_walks, vector_size=50, window=5)
# 节点类别,因为word2vec有单独节点次序
node_group = group.iloc[list(w2v.wv.key_to_index.keys())][1].values
from sklearn.manifold import TSNE

tsne = TSNE(n_components=2)
tsne_data = tsne.fit_transform(w2v.wv.vectors)

import matplotlib.cm as cm
x = np.arange(20)
ys = [i+x+(i*x)**2 for i in range(20)]
colors = cm.rainbow(np.linspace(0, 1, len(ys)))

plt.scatter(
    tsne_data[:, 0], 
    tsne_data[:, 1],
    color=colors[node_group]
)

img

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

# 划分数据集
x_tr, x_val, y_tr, y_val = train_test_split(
    w2v.wv.vectors, node_group, test_size=0.2, stratify=node_group
)

# 模型训练与验证,准确率0.535
model = LogisticRegression()
model.fit(x_tr, y_tr)
model.score(x_val, y_val)

2016 node2vec: Scalable Feature Learning for Networks, PDF

node2vec是一种综合考虑DFS邻域和BFS邻域的graph embedding方法。简单来说,可以看作是deepwalk的一种扩展,是结合了DFS和BFS随机游走的deepwalk。node2vec依然采用随机游走的方式获取顶点的近邻序列,不同的是node2vec采用的是一种有偏的随机游走。

node2vec的游走策略(已经由节点t�游走到节点v�,下一步如何抉择),根据下面公式,计算出每个每个邻近节点的“值”,然后折算成概率,最后别名采样算法最终游走到的目标节点(p�越小,embedding越倾向于表达同质性;q�越小,embedding越倾向于表达结构性)。

假设上一步在顶点t�,当前在顶点v�,接下来需要计算走到顶点x�的“权重”。dtx=0,1,2���=0,1,2分别表示下一步走回t�,走到x1�1,走到x2�2或x3�3的权重。(对应距离上一步位置t与下一步位置x的距离分别是0,1,2)

img

def next_step(graph, previous, current, p, q):
    neighbors = list(graph.neighbors(current))

    weights = []
    # Adjust the weights of the edges to the neighbors with respect to p and q.
    for neighbor in neighbors:
        if neighbor == previous:
            # Control the probability to return to the previous node.
            weights.append(1 / p)
        elif graph.has_edge(neighbor, previous):
            # The probability of visiting a local node.
            weights.append(1)
        else:
            # Control the probability to move forward.
            weights.append(1 / q)

    # Compute the probabilities of visiting each neighbor.
    weight_sum = sum(weights)
    probabilities = [weight / weight_sum for weight in weights]

    if len(neighbors) == 0:
        return None

    # Probabilistically select a neighbor to visit.    
    next = np.random.choice(neighbors, size=1, p=probabilities)[0]
    return next


def random_walk(graph, num_walks, num_steps, p, q):
    walks = []
    nodes = list(graph.nodes())
    # Perform multiple iterations of the random walk.
    for walk_iteration in range(num_walks):
        random.shuffle(nodes)

        for node in tqdm(nodes):
            # Start the walk with a random node from the graph.
            walk = [node]
            # Randomly walk for num_steps.
            while len(walk) < num_steps:
                current = walk[-1]
                previous = walk[-2] if len(walk) > 1 else None
                # Compute the next node to visit.
                next = next_step(graph, previous, current, p, q)
                if next:
                    walk.append(next)
                else:
                    break
            # Add the walk to the generated sequence.
            walks.append(walk)

    return walks

# Random walk return parameter.
p = 1

# Random walk in-out parameter.
q = 4

# Number of iterations of random walks.
num_walks = 5

# Number of steps of each random walk.
num_steps = 100

# 游走结果
walks = random_walk(g, num_walks, num_steps, p, q)

# 可视化、模型训练与验证,准确率0.555

img

- 任务5:图节点嵌入算法:
LINE

/

SDNE
  • 步骤1:使用LINE对Wiki数据集节点嵌入,维度为50维
  • 参考https://zhuanlan.zhihu.com/p/56478167和https://github.com/shenweichen/GraphEmbedding
  • 注意使用这个库,需要把数据集中的/t改为空格
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

  • 步骤2:每个group中20%的节点作为验证集,剩余的作为训练集

  • 在这里插入图片描述

  • 步骤3:使用节点嵌入向量 + 逻辑回归进行训练,并记录验证集准确率

  • 在这里插入图片描述

  • 步骤4:使用SDNE重复上述操作
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 步骤5:使用t-SNE将节点的LINE/SDNE特征降维,绘制散点图,节点颜色使用group进行区分

  • Line:
    在这里插入图片描述

  • SDNE
    在这里插入图片描述

2015 LINE: Large-scale Information Network Embedding, PDF

LINE保留了对一阶相似性和二阶相似性的敏感度。LINE考虑了二阶关系,即两个点也许不直接相连,但是如果它们的一阶公共好友比较多那么它们也被认为是比较相似的。

The first-order proximity in a network is the local pairwise proximity between two vertices. If no edge is observed between u and v, their first-order proximity is 0.

The second order proximity between a pair of vertices (u, v) in a network is the similarity between their neighborhood network structures. If no vertex is linked from/to both u and v, the second-order proximity between u and v is 0.

LINE需要定义了节点嵌入矩阵,然后去通过节点嵌入向量的内积得到相似度,并将相似度与一阶相似性和二阶相似性之间计算的KL散度,本质是让嵌入矩阵去模拟原始节点的相似性。

LINE参考资料:

  • https://aistudio.baidu.com/aistudio/projectdetail/655814
  • https://github.com/thunlp/OpenNE/blob/pytorch/src/openne/models/line.py

first-order similariy between vertex vi�� and vj�� as follows:

p1(vi,vj)=11+exp(−u→Ti⋅u→j)�1(��,��)=11+exp⁡(−�→��⋅�→�)

2016 SDNE: Structural Deep Network Embedding, PDF

SDNE使用一个自动编码器结构来同时优化1阶和2阶相似度(LINE是分别优化的),学习得到的向量表示能够保留局部和全局结构,并且对稀疏网络具有鲁棒性。

- 任务6:图节点嵌入算法:
GraphGAN
  • 步骤1:使用GraphGAN对Wiki数据集节点嵌入,维度为50维

  • 参考:git clone https://github.com/hwwang55/GraphGAN.git
    在这里插入图片描述
    在这里插入图片描述
    先生成embedding,然后写入字典txt
    在这里插入图片描述
    使用GraphGAN训练相对来说时间就会比较久了,但是我们只是要个embedding训练结果。
    最后会生成对应的文件:
    在这里插入图片描述
    在这里插入图片描述
    经过较长的训练,5个epoch后我们得到了对应的emb文件。

  • 步骤2:每个group中20%的节点作为验证集,剩余的作为训练集
    在这里插入图片描述

  • 步骤3:使用节点嵌入向量 + 逻辑回归进行训练,并记录验证集准确率
    在这里插入图片描述

  • 步骤4:使用t-SNE将节点的GraphGAN特征降维,绘制散点图,节点颜色使用group进行区分

  • gen
    在这里插入图片描述

  • dis

在这里插入图片描述

2017 GraphGAN: Graph Representation Learning with Generative Adversarial Nets, PDF

GraphGAN是一种结合了生成模型和判别模型的框架。其中生成器拟合Ptrue,判别器尝试去判别两个点之间是否有边。

### 推荐资料

  • https://github.com/shenweichen/GraphEmbedding
  • https://github.com/daicoolb/Awesome-Graph-Embedding
  • https://github.com/thunlp/TADW/
  • https://blog.csdn.net/Dark_Scope/article/details/74279582
  • https://stellargraph.readthedocs.io/en/stable/demos/node-classification/index.html
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要找出某个日期的正确上下班打卡时间,你可以使用`datetime`模块进行日期时间的比较和筛选。下面是一个示例代码: ```python import datetime # 打卡数据 data = [ {'日期': '2023-06-10', '开始时间': '2023-06-10 16:27:00', '结束时间': '2023-06-10 17:39:00'}, {'日期': '2023-06-11', '开始时间': '2023-06-11 01:57:00', '结束时间': '2023-06-11 02:02:00'}, {'日期': '2023-06-11', '开始时间': '2023-06-11 15:57:00', '结束时间': '2023-06-12 01:51:00'}, {'日期': '2023-07-01', '开始时间': '2023-07-01 08:09:00', '结束时间': '2023-07-01 17:25:00'}, {'日期': '2023-07-01', '开始时间': '2023-07-01 17:32:00', '结束时间': '2023-07-01 17:41:00'} ] target_date = datetime.date(2023, 6, 11) # 指定目标日期 # 遍历打卡数据,找到目标日期的打卡记录 for record in data: record_date = datetime.datetime.strptime(record['日期'], '%Y-%m-%d').date() if record_date == target_date: start_time = datetime.datetime.strptime(record['开始时间'], '%Y-%m-%d %H:%M:%S') end_time = datetime.datetime.strptime(record['结束时间'], '%Y-%m-%d %H:%M:%S') print('开始时间:', start_time) print('结束时间:', end_time) ``` 在上面的示例代码中,我们首先指定目标日期为`2023-06-11`,然后遍历打卡数据,找到与目标日期匹配的记录。然后将开始时间和结束时间转换为`datetime`对象,并打印出来。 你可以根据实际需要修改目标日期和打卡数据,以适应你的情况。 希望对你有所帮助!如果还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

irrationality

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值