networkx学习与使用——(3)路与圈

该博客参考《网络、群体与市场》学习networkx使用。先介绍实例构图,将网络抽象成图。接着讲解路,包括最短路径的多种用法及简单路相关函数。还介绍了圈的定义及相关函数,如求图中所有圈的基、find_cycle()函数等,最后给出完整代码资源和参考官网。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

路与圈

前几个星期写论文去了,耽搁了更新。给自己一个小目标,每周坚持一更!
为了保证实用性和逻辑性,接下来的更新内容会参考这本书的内容来学习networkx的使用。

大卫·伊斯利, 乔恩·克莱因伯格. 网络、群体与市场[M]. 清华大学出版社, 2011.

这本书在华文慕课上也有北大老师讲的非常nice的配套学习视频:人群与网络

实例构图

众所周知,互联网是从美国的ARPA计算机网络发展来的,1970年12月时的arpanet长这个样子:
arpanet1970
利用networkx画出我们需要的graph:

import networkx as nx               #载入networkx包
import matplotlib.pyplot as plt     #用于画图
G = nx.Graph()                     #无向图
edges = [('UCSB','SRI'),('UCSB','UCLA'),
        ('SRI','UCLA'),('SRI','STAN'),('SRI','UTAH'),
        ('UCLA','STAN'),('UCLA','RAND'),
        ('UTAH','SDC'),('UTAH','MIT'),
        ('RAND','SDC'),('RAND','BBN'),
        ('MIT','BBN'),('MIT','LINC'),
        ('BBN','HARV'),
        ('LINC','CASE'),
        ('HARV','CARN'),
        ('CASE','CARN')]
G.add_edges_from(edges)

接下来是画图:

labels={}
for node in G.nodes():
    labels[node]=node

pos=nx.spring_layout(G)                     # 生成节点位置信息 
plt.rcParams['figure.figsize']= (6, 4)      # 设置画布大小
nx.draw_networkx_nodes(G,pos)               # 画节点
nx.draw_networkx_edges(G,pos)               # 画边
nx.draw_networkx_labels(G,pos,labels)       # 画标签 

plt.axis('off')                             # 去掉坐标刻度  

# 保存并显示图片
# plt.savefig("ARPA.png")
plt.show()

ARPA1970
于是,我们成功的将一个简单的网络抽象成图,为接下来的分析做好了准备。

在用户手册的目录中,我们找到算法(Algorithms)下的最短路(shortest_path)和简单路(simple_path)。

最短路径

这里奉上最短路径相关的函数,从用户手册中直接截图出来的:
最短路径相关函数
寻找两点间的最短路径

print(nx.shortest_path(G, 'UCSB', 'SDC'))
out:
['UCSB', 'SRI', 'UTAH', 'SDC']

当然两点之间可能不止一条最短路径,所以我们可以输出所有最短路径:

print(list(nx.all_shortest_paths(G, 'UCSB', 'SDC')))
out:
[['UCSB', 'SRI', 'UTAH', 'SDC'], 
['UCSB', 'UCLA', 'RAND', 'SDC']]

最短路径的长度有四种用法,只输入图,输入图和源节点,输入图和目标节点和全都输入。
仅输入图会返回各个节点到其他节点的最短距离的字典:

print(list(nx.shortest_path_length(G)))
out:
[('UCSB', {'UCSB': 0, 'SRI': 1, 'UCLA': 1, 'STAN': 2, 'UTAH': 2, 'RAND': 2, 'SDC': 3, 'MIT': 3, 'BBN': 3, 'LINC': 4, 'HARV': 4, 'CASE': 5, 'CARN': 5}), 
('SRI', {'SRI': 0, 'UCSB': 1, 'UCLA': 1, 'STAN': 1, 'UTAH': 1, 'RAND': 2, 'SDC': 2, 'MIT': 2, 'BBN': 3, 'LINC': 3, 'HARV': 4, 'CASE': 4, 'CARN': 5}), 
('UCLA', {'UCLA': 0, 'UCSB': 1, 'SRI': 1, 'STAN': 1, 'RAND': 1, 'UTAH': 2, 'SDC': 2, 'BBN': 2, 'MIT': 3, 'HARV': 3, 'LINC': 4, 'CARN': 4, 'CASE': 5}), 
('STAN', {'STAN': 0, 'SRI': 1, 'UCLA': 1, 'UCSB': 2, 'UTAH': 2, 'RAND': 2, 'SDC': 3, 'MIT': 3, 'BBN': 3, 'LINC': 4, 'HARV': 4, 'CASE': 5, 'CARN': 5}), 
('UTAH', {'UTAH': 0, 'SRI': 1, 'SDC': 1, 'MIT': 1, 'UCSB': 2, 'UCLA': 2, 'STAN': 2, 'RAND': 2, 'BBN': 2, 'LINC': 2, 'HARV': 3, 'CASE': 3, 'CARN': 4}), 
('RAND', {'RAND': 0, 'UCLA': 1, 'SDC': 1, 'BBN': 1, 'UCSB': 2, 'SRI': 2, 'STAN': 2, 'UTAH': 2, 'MIT': 2, 'HARV': 2, 'LINC': 3, 'CARN': 3, 'CASE': 4}), 
('SDC', {'SDC': 0, 'UTAH': 1, 'RAND': 1, 'SRI': 2, 'MIT': 2, 'UCLA': 2, 'BBN': 2, 'UCSB': 3, 'STAN': 3, 'LINC': 3, 'HARV': 3, 'CASE': 4, 'CARN': 4}), 
('MIT', {'MIT': 0, 'UTAH': 1, 'BBN': 1, 'LINC': 1, 'SRI': 2, 'SDC': 2, 'RAND': 2, 'HARV': 2, 'CASE': 2, 'UCSB': 3, 'UCLA': 3, 'STAN': 3, 'CARN': 3}), 
('BBN', {'BBN': 0, 'RAND': 1, 'MIT': 1, 'HARV': 1, 'UCLA': 2, 'SDC': 2, 'UTAH': 2, 'LINC': 2, 'CARN': 2, 'UCSB': 3, 'SRI': 3, 'STAN': 3, 'CASE': 3}), 
('LINC', {'LINC': 0, 'MIT': 1, 'CASE': 1, 'UTAH': 2, 'BBN': 2, 'CARN': 2, 'SRI': 3, 'SDC': 3, 'RAND': 3, 'HARV': 3, 'UCSB': 4, 'UCLA': 4, 'STAN': 4}), 
('HARV', {'HARV': 0, 'BBN': 1, 'CARN': 1, 'RAND': 2, 'MIT': 2, 'CASE': 2, 'UCLA': 3, 'SDC': 3, 'UTAH': 3, 'LINC': 3, 'UCSB': 4, 'SRI': 4, 'STAN': 4}), 
('CASE', {'CASE': 0, 'LINC': 1, 'CARN': 1, 'MIT': 2, 'HARV': 2, 'UTAH': 3, 'BBN': 3, 'SRI': 4, 'SDC': 4, 'RAND': 4, 'UCSB': 5, 'UCLA': 5, 'STAN': 5}), 
('CARN', {'CARN': 0, 'HARV': 1, 'CASE': 1, 'BBN': 2, 'LINC': 2, 'RAND': 3, 'MIT': 3, 'UCLA': 4, 'SDC': 4, 'UTAH': 4, 'UCSB': 5, 'SRI': 5, 'STAN': 5})]

仅输入图和源节点会返回源节点到其他节点的最短距离字典:

print(nx.shortest_path_length(G, source = 'UCSB'))
out:
{'UCSB': 0, 'SRI': 1, 'UCLA': 1, 'STAN': 2, 'UTAH': 2, 'RAND': 2, 'SDC': 3, 'MIT': 3, 'BBN': 3, 'LINC': 4, 'HARV': 4, 'CASE': 5, 'CARN': 5}

仅输入图和目标节点会返回其他节点到目标节点的最短距离字典:

print(nx.shortest_path_length(G, target= 'UCSB'))
out:
{'UCSB': 0, 'SRI': 1, 'UCLA': 1, 'STAN': 2, 'UTAH': 2, 'RAND': 2, 'SDC': 3, 'MIT': 3, 'BBN': 3, 'LINC': 4, 'HARV': 4, 'CASE': 5, 'CARN': 5}

这里结果和上面一样是因为这里计算的是无向图。

全都输入,等价于len(shortest_path()):

print(nx.shortest_path_length(G, source='UCSB', target = 'SDC'))
out:
3

平均最短路径,事实上就是将上面的所有节点对之间的最短距离求平均数:

print(nx.average_shortest_path_length(G))
out:
2.5641025641025643

求两点间是否有路可达

print(nx.has_path(G, 'UCSB', 'SDC'))
out:
True

简单路

所谓简单路,就是不走重复点的路。
networkx中简单路仅有两个函数,求图中两点间的所有简单路径最短简单路径

print(list(nx.all_simple_paths(G, 'UCSB', 'SDC')))
out:
[['UCSB', 'SRI', 'UCLA', 'RAND', 'SDC'], 
['UCSB', 'SRI', 'UCLA', 'RAND', 'BBN', 'MIT', 'UTAH', 'SDC'], 
['UCSB', 'SRI', 'UCLA', 'RAND', 'BBN', 'HARV', 'CARN', 'CASE', 'LINC', 'MIT', 'UTAH', 'SDC'], 
['UCSB', 'SRI', 'STAN', 'UCLA', 'RAND', 'SDC'], 
['UCSB', 'SRI', 'STAN', 'UCLA', 'RAND', 'BBN', 'MIT', 'UTAH', 'SDC'], ['UCSB', 'SRI', 'STAN', 'UCLA', 'RAND', 'BBN', 'HARV', 'CARN', 'CASE', 'LINC', 'MIT', 'UTAH', 'SDC'], 
['UCSB', 'SRI', 'UTAH', 'SDC'], 
['UCSB', 'SRI', 'UTAH', 'MIT', 'BBN', 'RAND', 'SDC'], 
['UCSB', 'SRI', 'UTAH', 'MIT', 'LINC', 'CASE', 'CARN', 'HARV', 'BBN', 'RAND', 'SDC'], 
['UCSB', 'UCLA', 'SRI', 'UTAH', 'SDC'],
 ['UCSB', 'UCLA', 'SRI', 'UTAH', 'MIT', 'BBN', 'RAND', 'SDC'], 
 ['UCSB', 'UCLA', 'SRI', 'UTAH', 'MIT', 'LINC', 'CASE', 'CARN', 'HARV', 'BBN', 'RAND', 'SDC'], 
 ['UCSB', 'UCLA', 'STAN', 'SRI', 'UTAH', 'SDC'], 
 ['UCSB', 'UCLA', 'STAN', 'SRI', 'UTAH', 'MIT', 'BBN', 'RAND', 'SDC'], ['UCSB', 'UCLA', 'STAN', 'SRI', 'UTAH', 'MIT', 'LINC', 'CASE', 'CARN', 'HARV', 'BBN', 'RAND', 'SDC'], 
 ['UCSB', 'UCLA', 'RAND', 'SDC'], 
 ['UCSB', 'UCLA', 'RAND', 'BBN', 'MIT', 'UTAH', 'SDC'], 
 ['UCSB', 'UCLA', 'RAND', 'BBN', 'HARV', 'CARN', 'CASE', 'LINC', 'MIT', 'UTAH', 'SDC']]

最短简单路径的返回其实和所有简单路径的内容一样,但是得到的答案根据路径的长度,由短到长进行排序。

print(list(nx.shortest_simple_paths(G, 'UCSB', 'SDC')))
out:
[['UCSB', 'SRI', 'UTAH', 'SDC'], 
['UCSB', 'UCLA', 'RAND', 'SDC'],
['UCSB', 'SRI', 'UCLA', 'RAND', 'SDC'], 
['UCSB', 'UCLA', 'SRI', 'UTAH', 'SDC'],
['UCSB', 'SRI', 'STAN', 'UCLA', 'RAND', 'SDC'], 
['UCSB', 'UCLA', 'STAN', 'SRI', 'UTAH', 'SDC'], 
['UCSB', 'SRI', 'UTAH', 'MIT', 'BBN', 'RAND', 'SDC'],
['UCSB', 'UCLA', 'RAND', 'BBN', 'MIT', 'UTAH', 'SDC'],
['UCSB', 'SRI', 'UCLA', 'RAND', 'BBN', 'MIT', 'UTAH', 'SDC'],
['UCSB', 'UCLA', 'SRI', 'UTAH', 'MIT', 'BBN', 'RAND', 'SDC'],
['UCSB', 'SRI', 'STAN', 'UCLA', 'RAND', 'BBN', 'MIT', 'UTAH', 'SDC'],
['UCSB', 'UCLA', 'STAN', 'SRI', 'UTAH', 'MIT', 'BBN', 'RAND', 'SDC'],
['UCSB', 'SRI', 'UTAH', 'MIT', 'LINC', 'CASE', 'CARN', 'HARV', 'BBN', 'RAND', 'SDC'],
['UCSB', 'UCLA', 'RAND', 'BBN', 'HARV', 'CARN', 'CASE', 'LINC', 'MIT', 'UTAH', 'SDC'],
['UCSB', 'SRI', 'UCLA', 'RAND', 'BBN', 'HARV', 'CARN', 'CASE', 'LINC', 'MIT', 'UTAH', 'SDC'],
['UCSB', 'UCLA', 'SRI', 'UTAH', 'MIT', 'LINC', 'CASE', 'CARN', 'HARV', 'BBN', 'RAND', 'SDC'],
['UCSB', 'SRI', 'STAN', 'UCLA', 'RAND', 'BBN', 'HARV', 'CARN', 'CASE', 'LINC', 'MIT', 'UTAH', 'SDC'],
['UCSB', 'UCLA', 'STAN', 'SRI', 'UTAH', 'MIT', 'LINC', 'CASE', 'CARN', 'HARV', 'BBN', 'RAND', 'SDC']]

圈(环)

圈的简单定义为,长度大于三且起点与终点相同的路。
networkx中与圈相关的函数:
圈函数
首先是求图中所有圈的基:
先看networkx中关于圈的基给出的解释:A basis for cycles of a network is a minimal collection of cycles such that any cycle in the network can be written as a sum of cycles in the basis. Here summation of cycles is defined as “exclusive or” of the edges. Cycle bases are useful, e.g. when deriving equations for electric circuits using Kirchhoff’s Laws.
网络圈的基是圈的最小集合,这样网络中的任何圈都可以写成基中圈的和。这里圈的总和被定义为边的“异或”。圈基是有用的,例如,当使用基尔霍夫定律推导电路方程时。

nx.cycle_basis(G)
out:
[['BBN', 'HARV', 'CARN', 'CASE', 'LINC', 'MIT'],
 ['UTAH', 'SDC', 'RAND', 'BBN', 'MIT'],
 ['SRI', 'STAN', 'UCLA'],
 ['UCSB', 'SRI', 'UCLA'],
 ['UTAH', 'SRI', 'UCLA', 'RAND', 'BBN', 'MIT']]

第二个函数是针对有向图的,这里就不做展示了。

find_cycle()函数根据给定的源节点返回按照深度优先遍历找到的第一个圈,如果是有向图还能通过选择orientation参数来控制深度遍历的方向。

nx.find_cycle(G,'UCSB')
out:
[('UCSB', 'SRI'), ('SRI', 'UCLA'), ('UCLA', 'UCSB')]

完整代码资源

networkx学习(3)

参考

networkx官网地址:https://networkx.org/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我的手机半斤重

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

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

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

打赏作者

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

抵扣说明:

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

余额充值