web-dev-qa-db-fra.com

Matrice d'adjacence en Python

Je ne trouve aucune explication claire sur la façon de créer une matrice d'adjacence en Python, avec des poids pris en considération. Je suppose que sa création devrait être relativement simple.

J'ai la matrice suivante ...

   1   2   3   4   5   6
1  0   15  0   7   10  0
2  15  0   9   11  0   9
3  0   9   0   0   12  7
4  7   11  0   0   8   14
5  10  0   12  8   0   8
6  0   9   7   14  8   0

Les nombres 1 à 6 sont des sommets et les nombres à l'intérieur sont les poids entre chaque sommet voisin. Par exemple, Edge 1-2 a un poids de 15.

Comment pourrais-je implémenter cela en python? J'ai juste besoin d'un exemple simple, n'utilisant pas nécessairement celui que j'ai fourni.

Je sais comment créer une liste de contiguïté ...

graph = {'1': [{'2':'15'}, {'4':'7'}, {'5':'10'}],
    '2': [{'3':'9'}, {'4':'11'}, {'6':'9'}],
    '3': [{'5':'12'}, {'6':'7'}],
    '4': [{'5':'8'}, {'6':'14'}],
    '5': [{'6':'8'}]}

mais j'ai besoin d'une matrice d'adjacence.

8
Bolboa

Je pense que le concept le plus courant et le plus simple pour stocker une matrice d'adjacence est d'utiliser un tableau 2D, qui en python correspond à des listes imbriquées

mat = [[0, 15, 0, 7, 10, 0], [15, 0, ...], [...], [...]]
m[0][1]  # = 15 (weight of 1-2)

Si les valeurs sont en lecture seule, vous pouvez utiliser des tuples imbriqués à la place :)

Bien sûr, vous pouvez devenir aussi fou que vous le souhaitez et utiliser des dictionnaires ou écrire une classe et redéfinir __getattr__ pour être plus efficace sur les temps d'accès et de stockage car la matrice est symétrique.

2
enpenax

J'aime les clés tuplées pour les structures 2d comme celle-ci en python.

{(1, 1): 0, (3, 2): 9... }

Je pense que c'est conceptuellement plus clair car il supprime la structure de données intermédiaire dans la solution ci-dessus. Néanmoins, cette structure de données intermédiaire - la liste interne ou la ligne/colonne - peut être utile si vous avez l'intention d'accéder à votre structure par ligne ou par colonne.

 for x, row in enumerated(matrix, 1):
       # process whole row 
       for y in enumerate(row, 1):
             # process cell...

Si l'accès aux données par cellule est votre jeu, il est difficile de battre ce qui suit pour une simplicité expressive:

for (x, y), value in matrix.iteritems():
      # act on cell

Triez-le si vous le souhaitez.

 # (1, 1), (1, 2)...
 for (x, y), value in sorted(matrix.iteritems()):
       # act on cell
4
jwilner

Cela convertit votre "liste d'adjacence" (vraiment un dict, pas une liste) en une véritable matrice:

import networkx as nx

graph = {'1': [{'2':'15'}, {'4':'7'}, {'5':'10'}],
    '2': [{'3':'9'}, {'4':'11'}, {'6':'9'}],
    '3': [{'5':'12'}, {'6':'7'}],
    '4': [{'5':'8'}, {'6':'14'}],
    '5': [{'6':'8'}]}
new_graph = nx.Graph()
for source, targets in graph.iteritems():
    for inner_dict in targets:
        assert len(inner_dict) == 1
        new_graph.add_Edge(int(source) - 1, int(inner_dict.keys()[0]) - 1,
                           weight=inner_dict.values()[0])
adjacency_matrix = nx.adjacency_matrix(new_graph)

(Le format de votre graph n'est pas particulièrement pratique pour une utilisation dans networkx.) networkx prend en charge toutes sortes d'opérations sur les graphiques et leurs matrices d'adjacence, donc avoir le graphique dans ce le format devrait être très utile pour vous. Notez également que j'ai déplacé votre graphique pour utiliser les indices Python (c'est-à-dire commençant à 0).

In [21]: adjacency_matrix
Out[21]: 
matrix([[  0.,  15.,   0.,   7.,  10.,   0.],
        [ 15.,   0.,   9.,  11.,   0.,   9.],
        [  0.,   9.,   0.,   0.,  12.,   7.],
        [  7.,  11.,   0.,   0.,   8.,  14.],
        [ 10.,   0.,  12.,   8.,   0.,   8.],
        [  0.,   9.,   7.,  14.,   8.,   0.]])
2
dbliss

Comme mentionné précédemment, la façon standard de traiter les matrices dans Python consiste à utiliser NumPy . Voici une fonction qui lit simplement la matrice d'adjacence de la liste d'adjacence. ( L'ordre implicite des nœuds est rendu explicite par le paramètre nodes.)

import numpy

def weighted_adjmatrix(adjlist, nodes):
    '''Returns a (weighted) adjacency matrix as a NumPy array.'''
    matrix = []
    for node in nodes:
        weights = {endnode:int(weight)
                   for w in adjlist.get(node, {})
                   for endnode, weight in w.items()}
        matrix.append([weights.get(endnode, 0) for endnode in nodes])
    matrix = numpy.array(matrix)
    return matrix + matrix.transpose()

Dans ce cas, weighted_adjmatrix(graph, nodes=list('123456')) donne le tableau NumPy

array([[ 0, 15,  0,  7, 10,  0],
       [15,  0,  9, 11,  0,  9],
       [ 0,  9,  0,  0, 12,  7],
       [ 7, 11,  0,  0,  8, 14],
       [10,  0, 12,  8,  0,  8],
       [ 0,  9,  7, 14,  8,  0]])

Si une liste régulière est souhaitée, la méthode tolist() peut être appelée.

1
egnha