nx.adjacency_matrix计算邻接矩阵与真实结果不一致的解决

 更新时间:2022年12月16日 09:20:46   作者:小猪上吊ing  
这篇文章主要介绍了nx.adjacency_matrix计算邻接矩阵与真实结果不一致的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

问题描述

我自己根据edgelist计算的邻接矩阵,与调用networkx.adjacency_matrix(g)返回的结果不一样,经过调试发现了问题原因以及解决办法,记录如下。

原来的代码

edgelist = [
        (0, 1),
        (1, 3),
        (2, 4),
        (1, 5),
        (1, 3),
        (5, 5),
        (1, 3)
    ]
"""由于nx.MultiGraph()可累计多条重复边作为权重,所以(1,3)出现3次权重是3"""
g = nx.MultiGraph()  # 无向多边图
g.add_edges_from(edgelist)
adj = sp.lil_matrix(nx.adjacency_matrix(g))
print(adj.todense())

实际运行输出

[[0 1 0 0 0 0]
 [1 0 3 0 0 1]
 [0 3 0 0 0 0]
 [0 0 0 0 1 0]
 [0 0 0 1 0 0]
 [0 1 0 0 0 1]]

理论结果

[[0 1 0 0 0 0]
 [1 0 0 3 0 1]
 [0 0 0 0 1 0]
 [0 3 0 0 0 0]
 [0 0 1 0 0 0]
 [0 1 0 0 0 1]]

节点id从0开始。对于边(1,3),矩阵的第二行第四列应当为权重3,可以看到实际运行输出结果中,3却出现在了第二行第三列!

调试过程

查看了networkx.adjacency_matrix()的源代码,其中有一条说明如下:

def adjacency_matrix(G, nodelist=None, weight='weight'):
    """Return adjacency matrix of G.

    Parameters
    ----------
    G : graph
       A NetworkX graph

    nodelist : list, optional
       The rows and columns are ordered according to the nodes in nodelist.
       If nodelist is None, then the ordering is produced by G.nodes().

    weight : string or None, optional (default='weight')
       The edge data key used to provide each value in the matrix.
       If None, then each edge has weight 1.
    				...
    				...
    """
    return nx.to_scipy_sparse_matrix(G, nodelist=nodelist, weight=weight)

第二个参数的说明需要格外注意!对于nodelist这个参数,说明是这样的:邻接矩阵的行和列的排序按照nodelist中节点顺序来!如果不传这个参数,默认是按照传进来的图G调用G.nodes()时返回的节点的顺序!

所以我查看了我传进去的图g的节点默认顺序是什么样的:

edgelist = [
        (0, 1),
        (1, 3),
        (2, 4),
        (1, 5),
        (1, 3),
        (5, 5),
        (1, 3)
    ]
"""由于nx.MultiGraph()可累计多条重复边作为权重,所以(1,3)出现3次权重是3"""
g = nx.MultiGraph()  # 无向多边图
g.add_edges_from(edgelist)
print(g.nodes())
adj = sp.lil_matrix(nx.adjacency_matrix(g))
print(adj.todense())

运行结果居然:

[0, 1, 3, 2, 4, 5]
[[0 1 0 0 0 0]
 [1 0 3 0 0 1]
 [0 3 0 0 0 0]
 [0 0 0 0 1 0]
 [0 0 0 1 0 0]
 [0 1 0 0 0 1]]

图g的节点列表居然不是按照从小到大的顺序排列,id为3的节点居然是第三而不是第四位序,这就是为什么边(1,3)的权重会写在矩阵的第三列…因为矩阵第三列对应节点3!

那…为什么图g的节点列表不是排好序的,为什么是[0, 1, 3, 2, 4, 5]这个顺序?

因为:加新边sdd_edges的时候会自动加新节点!!!

边(0,1)加进去的时候,节点列表是[0,1];加边(1, 3)的时候,节点列表[0,1,3];…。所以节点默认列表的顺序,跟你加新边时候哪个节点先出现有关系。

解决方案

那么在添加新边之前,先把节点按id从小到大顺序排好同意添加,就可以了。

具体就是:在g.add_edges_from(edgelist)操作之前,先把edgelist中的节点抽取出来按顺序排好,用操作g.add_nodes_from()把节点统一添加进图g中。修改后的代码如下:

修改后的代码

edgelist = [
        (0, 1),
        (1, 3),
        (2, 4),
        (1, 5),
        (1, 3),
        (5, 5),
        (1, 3)
    ]
"""由于nx.MultiGraph()可累计多条重复边作为权重,所以(1,3)出现3次权重是3"""
g = nx.MultiGraph()  # 无向多边图

""" 节点id按照顺序排!!否则生成的邻接矩阵不一样 """
nodeset = sorted(set(itertools.chain(*edgelist)))
g.add_nodes_from(nodeset)

g.add_edges_from(edgelist)
print(g.nodes())
adj = sp.lil_matrix(nx.adjacency_matrix(g))
print(adj.todense())

修改代码后的运行结果

[0, 1, 2, 3, 4, 5]
[[0 1 0 0 0 0]
 [1 0 0 3 0 1]
 [0 0 0 0 1 0]
 [0 3 0 0 0 0]
 [0 0 1 0 0 0]
 [0 1 0 0 0 1]]

函数说明

nodeset = sorted(set(itertools.chain(*edgelist)))这行的功能,是把edgelist中的元素展开,去重,按顺序排序。分开演示就是:

edgelist = [
        (0, 1),
        (1, 3),
        (2, 4),
        (1, 5),
        (1, 3),
        (5, 5),
        (1, 3)
    ]
""" 把edgelist中的每个(a,b)元素打平成a,b """
nodes = list(itertools.chain(*edgelist))
print(nodes)
# 输出:
# [0, 1, 1, 3, 2, 4, 1, 5, 1, 3, 5, 5, 1, 3]

""" 利用set元素唯一的性质,将重复元素去重 a,a => a """
nodeset = set(nodes)
print(nodeset)
# 输出:
# {0, 1, 2, 3, 4, 5}

""" set中的元素是无序、非空、唯一的,所以对set再sorted一下,确保顺序是对的 """
nodeset = sorted(nodeset)
print(nodeset)
# 输出:
# [0, 1, 2, 3, 4, 5]

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Python3中的f-Strings增强版字符串格式化方法

    Python3中的f-Strings增强版字符串格式化方法

    这篇文章主要介绍了Python3中的f-Strings增强版字符串格式化方法,看完本文你将学习到如何以及为什么使用f-strings。对大家的工作或学习具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • 对python:print打印时加u的含义详解

    对python:print打印时加u的含义详解

    今天小编就为大家分享一篇对python:print打印时加u的含义详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-12-12
  • 利用python开发app实战的方法

    利用python开发app实战的方法

    这篇文章主要介绍了利用python开发app实战的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-07-07
  • Linux 下 Python 实现按任意键退出的实现方法

    Linux 下 Python 实现按任意键退出的实现方法

    这篇文章主要介绍了Linux 下 Python 实现按任意键退出的实现方法的相关资料,本文介绍的非常详细,具有参考借鉴价值,需要的朋友可以参考下
    2016-09-09
  • 如何将自己的python库打包成wheel文件并上传到pypi

    如何将自己的python库打包成wheel文件并上传到pypi

    这篇文章主要介绍了如何将自己的python库打包成wheel文件并上传到pypi,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • 深入掌握Python模块创建导入和使用

    深入掌握Python模块创建导入和使用

    这篇文章主要为大家介绍了深入掌握Python模块创建导入和使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • Python实现统计文本文件字数的方法

    Python实现统计文本文件字数的方法

    这篇文章主要介绍了Python实现统计文本文件字数的方法,涉及Python针对文本文件读取及字符串转换、运算等相关操作技巧,需要的朋友可以参考下
    2017-05-05
  • Python3批量生成带logo的二维码方法

    Python3批量生成带logo的二维码方法

    今天小编就为大家分享一篇Python3批量生成带logo的二维码方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-06-06
  • Python基础之pip如何更换镜像源

    Python基础之pip如何更换镜像源

    pip的源是指pip安装包所依赖的索引地址,下面这篇文章主要给大家介绍了关于Python基础之pip如何更换镜像源的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-08-08
  • Python简单实现两个任意字符串乘积的方法示例

    Python简单实现两个任意字符串乘积的方法示例

    这篇文章主要介绍了Python简单实现两个任意字符串乘积的方法,结合实例形式分析了Python针对字符串、列表的切片、转换、遍历等相关操作技巧,需要的朋友可以参考下
    2018-04-04

最新评论