web-dev-qa-db-ja.com

numpyまたはpandas隣接行列からのigraphグラフ

隣接行列が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()

pandasまたはnumpy隣接行列のいずれかからigraph.Graphを作成したいと思います。理想的な世界では、ノードには期待どおりの名前が付けられます。

これは可能ですか? チュートリアル はこの問題について沈黙しているようです。

21
LondonRob

Igraphでは、 igraph.Graph.Adjacency を使用して、Zipを使用せずに隣接行列からグラフを作成できます。重み付けされた隣接行列が使用され、np.arrayまたはpd.DataFrameに格納される場合に注意すべきことがいくつかあります。

  • igraph.Graph.Adjacencynp.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's 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
29
RickardSjogren

厳密に言えば、 隣接行列 はブール値であり、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

11
ali_m