[社交网络]networkx库包(介绍+使用)

2,105 阅读6分钟

总结

在一张庞大的网络中, 有很多的节点,
节点与节点之间,可能有边,也可能没有边。

节点,有属性。属性和属性值之间的关系,就像dict字典一样。
边,也有属性

度中心性
中介中心性

1/什么是networkx

有一个关于图论和网络建模的工具叫 NetworkX,
它是用 Python 语言开发的扩展包,内置了常用的图与网络分析算法,可以方便我们进行网络数据分析

2/社交网络图的增删改查

初始化(构建)一张社交网络图

   # 图的形式有很多种,比如有向图,无向图,多重有向图,多重无向图
   
   多重指的是节点之间存在多条边, 每条边的含义不同. 
   
   比如有的边代表关注, 有的边代表发过信息, 有的边代表转过账等. 
   
   当然我们也可以把多条边,通过某种方式最后构建成一条边, 这个需要看具体的业务场景. 
 
   import networkx as nx  
   
   # 初始化社交网络图,图中没有节点和边关系
   G = nx.Graph() # 无向图,节点之间的边没有方向,且2个节点之间只有一条边
   G = nx.DiGraph() # 有向图,节点之间的边有方向,且2个节点之间只有一条边
   G = nx.MultiGraph() # 多重无向图,边没有方向,两节点之间可以有多条边,不同的边代表不同的意思
   G = nx.MultiDigraph() # 多重有向图,边有方向,两节点之间可以有多条边,不同的边代表不同的意思

添加节点

   # 一次添加1个节点
   G.add_node("node_name")   # add_node(),而不是add_nodes(),说明这是一次添加一个节点
   
   # 批量添加节点
   G.add_nodes_from( ['b','c','d','e'] )  # add_nodes_from(),而不是add_node_from()
   
   # 加环,add_cycle()函数意味着同时添加了节点和边关系
   G.add_cycle(['f','g','h','j'])   

   # 添加节点的同时,还可以添加节点的属性,
   # 一个节点可以有一个或者任意多个属性
   # 节点的属性名称和属性值之间的关系,类似字典dict。属性名称不能重复。
   G.add_node(1,weight=2)    # 增加节点1,节点1权重属性值为2
   G.nodes[1]["age"] = 30    # 给节点1增加age属性
   G.add_node(2,weight=3)    # 增加节点2,同时给节点2添加权重属性为3
   
   G.nodes[0]["foo"] = "bar" # 添加节点0的同时,也添加了foo属性
   list(G.nodes(data=True))  # 查看节点值及其属性,data=True是返回属性
   # 输出结果:
   [(0, {'foo': 'bar'}), (1, {'weight':2, 'time': '5pm'}), (2, {'weight':3})]

添加边

# 每次添加一条边
G.add_edge(2,3)  # 添加一条边2-3(这里其实是一举两得,把节点和边都添加进去了)
G.add_edge(3,2)  # 如果G是无向图,边3-2与边2-3则是同一条边,只会保留一条边(保留后添加的)

# 一次性添加多条边
# 一次性添加多条边,用add_edges_from()函数,添加边,同时就会把节点添加进去
G.add_edges_from( [(1,2),(1,3),(2,4),(2,5),(3,6),(4,8),(5,8),(3,7)] )   

# 因为是无向图,所以如果边已经存在,则后添加的边会覆盖之前添加的边
# add_edge()和add_edges_from()函数只是添加了边,并没有添加边的属性。

添加边的属性,一条边可以有任意多个属性

给这三条边设置属性score,边的属性单独放在一个字典中dict
G.add_edges_from( [(‘小红’, ‘小黄’, {‘score’:70}),
                   (‘小红’, ‘小青’, {‘score’:80}),
                   (‘小黄’, ‘小青’, {‘score’:90})
                  ] )

image.png

单独给一条边添加属性:
G[node][node]['属性名'] = '属性值'
    
查看边的所有属性
for (u,v,w) in g.edges(data=True): # data=True是返回属性,若是False则只返回节点
  u 是节点
  v 是节点
  w 是连接uv两个节点的边上的所有属性,是一个字典结构。
    

添加带有权重的边

批量添加带权重的边(以下三种形式都可以实现):
G.add_weighted_edges_from([ (‘小红’, ‘小黄’, 7.0), 
                            (‘小红’, ‘小青’, 10),
                            (‘小黄’, ‘小青’, 3)] ) 
#元组中的第三个参数默认为weight属性值

G.add_edges_from([(‘小红’, ‘小黄’, {‘weight’:7.0}),
                  (‘小红’, ‘小青’, {‘weight’:10}),
                  (‘小黄’, ‘小青’, {‘weight’:3})] )

image.png

获取节点和边,以及节点和边的数量

G.nodes()
G.edges()            
G.number_of_nodes()   
G.number_of_edges()  

清空网络图

把网络图中的节点和边关系全部删除,网络图还是存在的,是一张空的网络图
G.clear() 

修改节点的属性,修改边的属性

修改节点的属性:
   G.nodes[0]["foo"] = "bar" 

修改边的属性:
   G.edges[‘小红’,‘小黄’][‘weight’] =10

获得边的属性

如果想读取权重,可以使用get_edge_data方法,它接受两个参数u和v,即边的起止点。
例如:
G.get_edge_data(0,1)   
输出{'weight': 3.0},这是一个字典结构

删除节点,删除边

删除节点
G.remove_node(node)  
G.remove_nodes_from(['b','c','d','e']) 
    
删除边(注意:真是把边删除了,节点还是存在的)
G.remove_edge(node1,node2)  # 一次删除一条边
G.remove_edges_from([])  # 批量删除多条边

保存社交网络图

nx.write_gml(G,"path_where_graph_should_be_saved.gml")   
# 以.gml作为后缀,

读取图

G = nx.read_gml("path_to_graph_graph.gml") 

有向图和无向图之间是可以相互转化的

G1 = G.to_undirected()  # 有向图-->无向图
G1 = G.to_directed()    # 无向图-->有向图

在社交网络图中,给图添加属性

 上图中的例子:
 首先创建一个了含有3个节点的社交网络图
 然后计算图中各个节点的中介中心性,得到的是一个字典格式
 然后通过set_node_attrbutes()函数给社交网络图添加属性
 set_node_attrbutes(g,attr_name,attr_value)"
 该函数有3个参数:
    社交网络g,属性名称,属性值

G.subgraph(nodes) 获得子图

# 从一张总的社交网络图中,指定节点,获得一张子图。
g = nx.path_graph(50) # 创建一张含有50个节点的图
nodes = ['A', 'C', 'B']
subgraph = g.subgraph(nodes)

图于图之间的合并

有2种方式
<1>G3=nx.disjoint_union(G1,G2)
  下图中,虽然把2张社交网络图放在了一站图中,但是公共节点(0,1,2)并没有合并在一起,
  所以这个函数不好

image.png

<2>g3 = nx.compose(g1,g2)
  下图中,公共节点已经合并了

image.png

nx.path_graph()

G=nx.path_graph(8)
该函数的作用是创建一个含有8个节点的社交网络图,形状类似于单链表的形式
下图只看左边即可

image.png

nx.has_path(G,source,target)

# 判断2节点是否连通
import networkx as nx
nx.has_path(G,source,target)

nx.complete_graph()

g=nx.complete_graph(3)
该函数是创建两两相连的社交网络图
下图只看中间即可

image.png

通过nx.bfs_successors(g,source=node,depth_limit=depth)

bfs_successors()函数是得到指定节点的所有层次的相邻节点
通过一定的函数改造,可以得到指定节点的指定层次的相邻节点。    

image.png image.png

获取结点i的邻居节点

G.neighbors(i)