Igraph Graph из numpy или pandas матрица смежности
У меня есть матрица смежности, сохраненная как pandas.DataFrame
:
node_names = ['A', 'B', 'C']
a = pd.DataFrame([[1,2,3],[3,1,1],[4,0,2]],
index=node_names, columns=node_names)
a_numpy = a.as_matrix()
Я хотел бы создать igraph.Graph
из матриц смежности pandas
или numpy
. В идеальном мире узлы будут называться как ожидалось.
Возможно ли это? В учебнике, кажется, не говорится об этой проблеме.
Ответы
Ответ 1
В igraph вы можете использовать igraph.Graph.Adjacency
для создания графика из матрицы смежности без использования zip
. Есть некоторые вещи, о которых следует знать, когда взвешенная матрица смежности используется и хранится в np.array
или pd.DataFrame
.
-
igraph.Graph.Adjacency
не может принимать аргумент np.array
в качестве аргумента, но это легко решить с помощью tolist
.
-
Целые числа в матрице смежности интерпретируются как количество ребер между узлами, а не весами, которые решаются с помощью смежности как булева.
Пример того, как это сделать:
import igraph
import pandas as pd
node_names = ['A', 'B', 'C']
a = pd.DataFrame([[1,2,3],[3,1,1],[4,0,2]], index=node_names, columns=node_names)
# Get the values as np.array, it more convenenient.
A = a.values
# Create graph, A.astype(bool).tolist() or (A / A).tolist() can also be used.
g = igraph.Graph.Adjacency((A > 0).tolist())
# Add edge weights and node labels.
g.es['weight'] = A[A.nonzero()]
g.vs['label'] = node_names # or a.index/a.columns
Вы можете восстановить свой фрейм-код смежности, используя get_adjacency
:
df_from_g = pd.DataFrame(g.get_adjacency(attribute='weight').data,
columns=g.vs['label'], index=g.vs['label'])
(df_from_g == a).all().all() # --> True
Ответ 2
Строго говоря, матрица смежности является логической, причем 1 указывает на наличие соединения и 0 указывает на отсутствие. Поскольку многие из значений в вашей матрице a_numpy
составляют > 1, я буду считать, что они соответствуют весам граней в вашем графике.
import igraph
# get the row, col indices of the non-zero elements in your adjacency matrix
conn_indices = np.where(a_numpy)
# get the weights corresponding to these indices
weights = a_numpy[conn_indices]
# a sequence of (i, j) tuples, each corresponding to an edge from i -> j
edges = zip(*conn_indices)
# initialize the graph from the edge sequence
G = igraph.Graph(edges=edges, directed=True)
# assign node names and weights to be attributes of the vertices and edges
# respectively
G.vs['label'] = node_names
G.es['weight'] = weights
# I will also assign the weights to the 'width' attribute of the edges. this
# means that igraph.plot will set the line thicknesses according to the edge
# weights
G.es['width'] = weights
# plot the graph, just for fun
igraph.plot(G, layout="rt", labels=True, margin=80)
![enter image description here]()