【问题标题】:How to make an adjacency matrix out of a list?如何从列表中制作邻接矩阵?
【发布时间】:2018-05-17 17:54:34
【问题描述】:

我有一个类似的列表:

[['10', '20', 2], ['10', '21', 2], ['10', '1', 2], ['10', '0', 3], ['10', '3', 2],
 ['10', '2', 2], ['10', '5', 3], ['10', '4', 3], ['10', '7', 2], ['10', '6', 2],
 ['10', '9', 2], ['10', '8', 2], ['10', '11', 2], ['10', '10', 2], ['10', '13', 2],
 ['10', '12', 2], ['10', '15', 2], ['10', '14', 2], ['10', '17', 0], ['10', '16', 3],
 ['10', '19', 2], ['10', '18', 2], ['1', '20', 3], ['1', '21', 3], ['1', '1', 3],
 ['1', '0', 0], ['1', '3', 3], ['1', '2', 3], ['1', '5', 4], ['1', '4', 4],
 ['1', '7', 3], ['1', '6', 3], ['1', '9', 3], ['1', '8', 3], ['1', '11', 3],
 ['1', '10', 3], ['1', '13', 3], ['1', '12', 3], ['1', '15', 3]]

(比这个大很多)第一项和第二项实际上是节点名称,第三项是它们之间的边权重(虽然我没有制作图表,它是一个列表)。

我想从这个列表中创建一个邻接矩阵。

【问题讨论】:

  • 是否允许使用外部库?在 NetworkX 中可以快速轻松地获取此列表,将其转换为 nx.Graph,然后使用 NetworkX 方法转换为邻接矩阵。免责声明:我是 NetworkX 的贡献者。

标签: python list adjacency-matrix


【解决方案1】:

是的,您可以通过 defaultdict 来做到这一点

In [1]: in_list =  [['10', '20', 2], ['10', '21', 2], ['10', '1', 2], ['10', '0', 3], ['10', '3', 2], ['10'
   ...: , '2', 2], ['10', '5', 3], ['10', '4', 3], ['10', '7', 2], ['10', '6', 2], ['10', '9', 2], ['10', '
   ...: 8', 2], ['10', '11', 2], ['10', '10', 2], ['10', '13', 2], ['10', '12', 2], ['10', '15', 2], ['10',
   ...:  '14', 2], ['10', '17', 0], ['10', '16', 3], ['10', '19', 2], ['10', '18', 2], ['1', '20', 3], ['1'
   ...: , '21', 3], ['1', '1', 3], ['1', '0', 0], ['1', '3', 3], ['1', '2', 3], ['1', '5', 4], ['1', '4', 4
   ...: ], ['1', '7', 3], ['1', '6', 3], ['1', '9', 3], ['1', '8', 3], ['1', '11', 3], ['1', '10', 3], ['1'
   ...: , '13', 3], ['1', '12', 3], ['1', '15', 3]]                                                        

In [2]: from collections import defaultdict

In [3]: tree = lambda: defaultdict(tree)

In [5]: adj_mat = tree()

In [6]: for edge in in_list:
   ...:     start, end, weight = edge
   ...:     adj_mat[start][end] = weight
   ...:                                 

In [7]: adj_mat
Out[7]:        
defaultdict(<function __main__.<lambda>>,
            {'1': defaultdict(<function __main__.<lambda>>,
                         {'0': 0,                          
                          '1': 3,                          
                          '10': 3,                         
                          '11': 3,                         
                          '12': 3,                         
                          '13': 3,                         
                          '15': 3,                         
                          '2': 3,                          
                          '20': 3,                         
                          '21': 3,                         
                          '3': 3,                          
                          '4': 4,                          
                          '5': 4,                          
                          '6': 3,
                          '7': 3,
                          '8': 3,
                          '9': 3}),
             '10': defaultdict(<function __main__.<lambda>>,
                         {'0': 3,
                          '1': 2,
                          '10': 2,
                          '11': 2,
                          '12': 2,
                          '13': 2,
                          '14': 2,
                          '15': 2,
                          '16': 3,
                          '17': 0,
                          '18': 2,
                          '19': 2,
                          '2': 2,
                          '20': 2,
                          '21': 2,
                          '3': 2,
                          '4': 3,
                          '5': 3,
                          '6': 2,
                          '7': 2,
                          '8': 2,
                          '9': 2})})

当我实现这个时,我注意到你所有的边都起源于 1 或 10。嗯,很奇怪。

解释

  1. defaultdict 只是一个生动的哈希映射的花哨名称(如果您来自 perl 背景)
  2. 矩阵中的条目是边权重
  3. 如果您的边是双向的,您只需在 for 循环中添加 adj_mat[end][start] = weight

【讨论】:

  • 谢谢。我会试一试。至于节点是 1,10.... 这实际上是我正在处理的数据的一小部分。我有数千个节点,所以我在这里复制了几个。
【解决方案2】:

通常,您应该将 NumPy 用于矩阵,除非某些约束迫使您使用 vanilla Python。 NumPy 非常有效地处理矩阵。

此外,如果您决定使用 NumPy(并且应该),这是过去曾针对该库提出的一个问题:numpy/scipy build adjacency matrix from weighted edgelist

【讨论】:

    【解决方案3】:
    def make_adj_matrix(data, directed=False):
        summary = {}
        result = []
        nodes = []
    
        for start, end, weight in data:
            # store nodes names for further use
            if start not in nodes:
                nodes.append(start)
            if end not in nodes:
                nodes.append(end)
    
            # collect and sum all weights
            summary.setdefault(start, {}).setdefault(end, 0)
            summary[start][end] += weight
            if not directed:
                summary.setdefault(end, {}).setdefault(start, 0)
                summary[end][start] += weight
    
        # # here you can sort your nodes
        # nodes.sort()
    
        # constructing result
        for i in nodes:
            row = []
            for j in nodes:
                row.append(summary.get(i, {}).get(j, 0))
            result.append(row)
    
        return result
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-31
      • 1970-01-01
      • 2018-04-25
      • 1970-01-01
      • 2020-08-16
      相关资源
      最近更新 更多