1.使用第三方库networkx进行有向图与无向图的可视化

万物皆可嵌入一文中,我们介绍了从物品(item)生成序列,然后做word2vec的原理,并且提到了一些相关的算法——Deep WalkLINEnode2vec,除了这三个,还有两个这样的图嵌入(Graph Embedding)方法——SDNEStruc2Vec。

接下来我们会用五篇文章的篇幅来更新这五种Graph Embedding方法的具体原理以及实现过程,因为这些方法都是基于图论的,所以这一节我们先介绍图论的一个实现工具,也是对概率图模型可视化的一个补充。

python 概率密度PDF python概率图模型_python 概率密度PDF

networkx

networkx是一个python三方库,专门用来做网络结构图的工具包。可以直接通过pip进行安装,我们要用的正是这个库。这一节直接介绍它的一些基础操作。其他的可以通过官网学习,链接小编放在文章的最后。

  • 导入相关的包
import networkx as nx
import matplotlib.pyplot as plt
  • 创建图、节点、边
g = nx.Graph()
g.clear() #将图上元素清空

#节点的名字可以是任意数据类型的
g.add_node(1)
g.add_node("a")
g.add_node("spam")

g.add_nodes_from([2,3]) #创建两个节点2,3
H = nx.path_graph(10) #从0开始的连续数字的节点
g.add_nodes_from(H) #将0~9加入了节点


g.add_edge(1,2)
e = (2,3)
g.add_edge(*e) #直接g.add_edge(e)数据类型不对,*是将元组中的元素取出

#加一组边
g.add_edges_from([(1,2),(1,3)])
g.add_edges_from([("a","spam") , ("a",2)]) 

#加一系列连续的边
n = 10
H = nx.path_graph(n)
g.add_edges_from(H.edges()) #添加了0~1,1~2 ... n-2~n-1这样的n-1条连续的边
  • 属性设置
#设置点属性
g.add_node('benz', money=10000, fuel="1.5L")

#查看相关属性
g.nodes()['benz'] # {'fuel': '1.5L', 'money': 10000}
g.nodes()['benz']['money'] # 10000
g.nodes(data=True) # data默认false就是不输出属性信息,修改为true,会将节点名字和属性信息一起输出

#设置边属性
n = 10
H = nx.path_graph(n)
g.add_nodes_from(H)
g.add_edges_from(H.edges())
g[1][2]['color'] = 'blue'

g.add_edge(1, 2, weight=4.7)
g.add_edges_from([(3,4),(4,5)], color='red')
g.add_edges_from([(1,2,{'color':'blue'}), (2,3,{'weight':8})])
g[1][2]['weight'] = 4.7
  • 查看与删除
g.number_of_nodes() #查看点的数量
g.number_of_edges() #查看边的数量
g.nodes() #返回所有点的信息(list)
g.edges() #返回所有边的信息(list中每个元素是一个tuple)
g.neighbors(1) #所有与1这个点相连的点的信息以列表的形式返回
g[1] #查看所有与1相连的边的属性,格式输出:{0: {}, 2: {}} 表示1和0相连的边没有设置任何属性(也就是{}没有信息),同理1和2相连的边也没有任何属性

#删除节点
# g.remove_node(node_name)
# g.remove_nodes_from(nodes_list)
#删除边
# g.remove_edge(edge)
# g.remove_edges_from(edges_list)

对于图嵌入序列生成,需要查找节点的邻居以及其相关的属性,所以以下三个应该是常用的方法:

g[1] #查看所有与1相连的边的属性


g.nodes(data=True)#将节点名字和属性信息一起输出


g.neighbors(1)    #所有与1这个点相连的点的信息以列表的形式返回

最后再介绍从pandas快速变成图模型的方法:

nx.from_pandas_edgelist(df,source,target,edge_attr,create_using)

df就是传进去的DataFrame数据集,source表示第一个节点的字段名,target表示第二个节点的字段名,edge_attr表示把那些字段作为边的属性,可以接收一个list,create_using表示使用有向图还是无向图,还是其他图。

举一个例子吧,对于下面DataFrame数据集:

python 概率密度PDF python概率图模型_css_02

生成一个有向图,节点从node1指向node2,weight和cost作为边属性:

G = nx.from_pandas_edgelist(df, 'node1', 'node2', edge_attr=["weight", "cost"],create_using=nx.DiGraph())

可视化观察一下:

python 概率密度PDF python概率图模型_数据挖掘_03

python 概率密度PDF python概率图模型_数据可视化_04

有向图与无向图的可视化

我们来看看有向图和无向图的可视化,举四个例子:

  • 简单朴素的可视化(有向图+无向图)
import networkx as nx
import matplotlib.pyplot as plt

G = nx.Graph()
G.add_edge(1, 2)
G.add_edge(1, 3)
G.add_edge(1, 5)
G.add_edge(2, 3)
G.add_edge(3, 4)
G.add_edge(4, 5)

# explicitly set positions
pos = {1: (0, 0), 2: (-1, 0.3), 3: (2, 0.17), 4: (4, 0.255), 5: (5, 0.03)} #设置每个节点的坐标
# pos = nx.spring_layout(G, seed=3) #自动获取坐标,通过seed来设置随机数

options = {
    "font_size": 36,
    "node_size": 2000,
    "node_color": "white",
    "edgecolors": "black",
    "linewidths": 4, # 节点圆圈的粗细
    "width": 5, #边的粗细
}
nx.draw_networkx(G, pos, **options)

# Set margins for the axes so that nodes aren't clipped
ax = plt.gca()
ax.margins(0.20)
plt.axis("off")
plt.show()

可视化结果如下:

python 概率密度PDF python概率图模型_python 概率密度PDF_05

G = nx.DiGraph([(0, 3), (1, 3), (2, 4), (3, 5), (3, 6), (4, 6), (5, 6)])

# group nodes by column
left_nodes = [0, 1, 2]
middle_nodes = [3, 4]
right_nodes = [5, 6]

# set the position according to column (x-coord)
pos = {n: (0, i) for i, n in enumerate(left_nodes)}
pos.update({n: (1, i + 0.5) for i, n in enumerate(middle_nodes)})
pos.update({n: (2, i + 0.5) for i, n in enumerate(right_nodes)})

nx.draw_networkx(G, pos, **options)

# Set margins for the axes so that nodes aren't clipped
ax = plt.gca()
ax.margins(0.20)
plt.axis("off")
plt.show()

结果如下:

python 概率密度PDF python概率图模型_python_06

  • 增加权重和颜色
import matplotlib.pyplot as plt
import networkx as nx

G = nx.Graph()

G.add_edge("a", "b", weight=0.6)
G.add_edge("a", "c", weight=0.2)
G.add_edge("c", "d", weight=0.1)
G.add_edge("c", "e", weight=0.7)
G.add_edge("c", "f", weight=0.9)
G.add_edge("a", "d", weight=0.3)

elarge = [(u, v) for (u, v, d) in G.edges(data=True) if d["weight"] > 0.5]
esmall = [(u, v) for (u, v, d) in G.edges(data=True) if d["weight"] <= 0.5]

pos = nx.spring_layout(G, seed=7) # positions for all nodes - seed for reproducibility

# nodes
nx.draw_networkx_nodes(G, pos, node_size=700)

# edges
nx.draw_networkx_edges(G, pos, edgelist=elarge, width=6)
nx.draw_networkx_edges(
    G, pos, edgelist=esmall, width=6, alpha=0.5, edge_color="b", style="dashed"
)

# labels
nx.draw_networkx_labels(G, pos, font_size=20, font_family="sans-serif")

di = {(u,v):d['weight'] for (u,v,d) in G.edges(data=True)}
nx.draw_networkx_edge_labels(G, pos,edge_labels=di)

ax = plt.gca()
ax.margins(0.08)
plt.axis("off")
plt.tight_layout()
plt.show()

python 概率密度PDF python概率图模型_数据可视化_07

import matplotlib.pyplot as plt
import networkx as nx

G = nx.DiGraph()

G.add_edge("a", "b", weight=0.6)
G.add_edge("a", "c", weight=0.2)
G.add_edge("c", "d", weight=0.1)
G.add_edge("c", "e", weight=0.7)
G.add_edge("c", "f", weight=0.9)
G.add_edge("a", "d", weight=0.3)

elarge = [(u, v) for (u, v, d) in G.edges(data=True) if d["weight"] > 0.5]
esmall = [(u, v) for (u, v, d) in G.edges(data=True) if d["weight"] <= 0.5]

pos = nx.spring_layout(G, seed=9) # positions for all nodes - seed for reproducibility

# nodes
nx.draw_networkx_nodes(G, pos, node_size=700)

# edges
nx.draw_networkx_edges(G, pos, edgelist=elarge, width=3)
nx.draw_networkx_edges(
    G, pos, edgelist=esmall, width=2, alpha=0.1, edge_color="b", style="dashed"
)

# labels
nx.draw_networkx_labels(G, pos, font_size=20, font_family="sans-serif")

di = {(u,v):d['weight'] for (u,v,d) in G.edges(data=True)}
nx.draw_networkx_edge_labels(G, pos,edge_labels=di)

ax = plt.gca()
ax.margins(0.08)
plt.axis("off")
plt.tight_layout()
plt.show()

python 概率密度PDF python概率图模型_css_08

networkx官网传送门:

https://networkx.org/nx-guides/index.html

https://networkx.org/documentation/stable/index.html

https://networkx.org/documentation/latest/auto_examples/basic/plot_properties.html