web-dev-qa-db-ja.com

Pandas DataFrameからNetworkXグラフを作成します

単純なPandas DataFrame :)からいくつかのNetworkXグラフを作成したいと思います。

_        Loc 1   Loc 2   Loc 3   Loc 4   Loc 5   Loc 6   Loc 7
Foo     0       0       1       1       0       0           0
Bar     0       0       1       1       0       1           1
Baz     0       0       1       0       0       0           0
Bat     0       0       1       0       0       1           0
Quux    1       0       0       0       0       0           0
_

ここで、_Foo…_はインデックスであり、_Loc 1_から_Loc 7_は列です。しかし、Numpy行列または再配列への変換は、nx.Graph()の入力を生成するためには機能しないようです。これを達成するための標準的な戦略はありますか? Pandas-> CSVへのダンプ-> NetworkXへのインポート)でデータを再フォーマットすることを嫌うわけではありませんが、インデックスからエッジを生成できるはずであり、値からのノード。

16
urschrei

NetworkXは正方行列を想定しています (ノードとエッジの)、おそらく*あなたはそれを渡したいでしょう:

In [11]: df2 = pd.concat([df, df.T]).fillna(0)

注:インデックスと列が同じ順序であることが重要です!

In [12]: df2 = df2.reindex(df2.columns)

In [13]: df2
Out[13]: 
       Bar  Bat  Baz  Foo  Loc 1  Loc 2  Loc 3  Loc 4  Loc 5  Loc 6  Loc 7  Quux
Bar      0    0    0    0      0      0      1      1      0      1      1     0
Bat      0    0    0    0      0      0      1      0      0      1      0     0
Baz      0    0    0    0      0      0      1      0      0      0      0     0
Foo      0    0    0    0      0      0      1      1      0      0      0     0
Loc 1    0    0    0    0      0      0      0      0      0      0      0     1
Loc 2    0    0    0    0      0      0      0      0      0      0      0     0
Loc 3    1    1    1    1      0      0      0      0      0      0      0     0
Loc 4    1    0    0    1      0      0      0      0      0      0      0     0
Loc 5    0    0    0    0      0      0      0      0      0      0      0     0
Loc 6    1    1    0    0      0      0      0      0      0      0      0     0
Loc 7    1    0    0    0      0      0      0      0      0      0      0     0
Quux     0    0    0    0      1      0      0      0      0      0      0     0

In[14]: graph = nx.from_numpy_matrix(df2.values)

これは、列/インデックス名をグラフに渡しません。必要に応じて、 relabel_nodes を使用できます(パンダで許可されている重複に注意する必要がある場合があります) 'DataFrames):

In [15]: graph = nx.relabel_nodes(graph, dict(enumerate(df2.columns))) # is there nicer  way than dict . enumerate ?

*目的のグラフの列とインデックスが何を表しているのか正確にはわかりません。

16
Andy Hayden

少し遅れた答えですが、 networkxはpandas dataframes からデータを読み取ることができます。その場合、理想的には、単純な有向グラフの形式は次のとおりです。

+----------+---------+---------+
|   Source |  Target |  Weight |
+==========+=========+=========+
| Node_1   | Node_2  |   0.2   |
+----------+---------+---------+
| Node_2   | Node_1  |   0.6   |   
+----------+---------+---------+

隣接行列を使用している場合は、Andy Haydenが正しいので、正しい形式に注意する必要があります。あなたの質問では0と1を使用したので、無向グラフを見たいと思います。 インデックスは例を表すと言ったので、最初は直感に反しているように見えるかもしれません。人、および列は特定の人が属するグループを表しますが、グループ(メンバーシップ)が人に属する他の方法でも正しいです。このロジックに従って、実際にはグループをインデックスに配置し、個人も列に配置する必要があります。

補足:この問題は、有向グラフの意味で定義することもできます。たとえば、階層カテゴリの関連付けネットワークを視覚化する場合などです。そこで、協会、例えばサムワイズギャムジーからホビットへは、通常、他の方向よりも強力です(フロドバギンズはホビットのプロトタイプである可能性が高いため)

8
Agoston T

Scipyを使用して、次のような正方行列を作成することもできます。

import scipy.sparse as sp

cols = df.columns
X = sp.csr_matrix(df.astype(int).values)
Xc = X.T * X  # multiply sparse matrix
Xc.setdiag(0)  # reset diagonal

# create dataframe from co-occurence matrix in dense format
df = pd.DataFrame(Xc.todense(), index=cols, columns=cols)

後で、データフレームからエッジリストを作成し、Networkxにインポートできます。

df = df.stack().reset_index()
df.columns = ['source', 'target', 'weight']

df = df[df['weight'] != 0]  # remove non-connected nodes

g = nx.from_pandas_edgelist(df, 'source', 'target', ['weight'])
1
tmsss