web-dev-qa-db-ja.com

DataFrameからNetworkXに属性とエッジを持つノードをロードする

私は、Pythonを使ってグラフを操作する:NetworkXを使用しています。これまでにGephiを使用しました。標準的な手順があります(ただし、唯一の方法はありません)。

  1. テーブル/スプレッドシートからノード情報をロードします。列の1つはIDでなければならず、残りはノードに関するメタデータです(ノードは人なので、性別、グループ...通常はカラーリングに使用されます)。お気に入り:

    id;NormalizedName;Gender
    per1;Jesús;male
    per2;Abraham;male
    per3;Isaac;male
    per4;Jacob;male
    per5;Judá;male
    per6;Tamar;female
    ...
    
  2. 次に、通常は4つの列(Target、Source、WeightおよびType)を持つノードスプレッドシートの列IDにあるのと同じノードの名前を使用して、テーブル/スプレッドシートからもエ​​ッジをロードします。

    Target;Source;Weight;Type
    per1;per2;3;Undirected
    per3;per4;2;Undirected
    ...
    

これは、Pythonにロードしたい2つのデータフレームです。 NetworkXについて読むと、2つのテーブル(ノード用とエッジ用)を同じグラフにロードすることは完全に不可能であるようで、何が最善の方法かわかりません。

  1. DataFrameからのノード情報のみでグラフを作成し、他のDataFrameからエッジを追加(追加)する必要がありますか?もしそうなら、nx.from_pandas_dataframe()はエッジに関する情報を期待するので、それを使用してノードを作成するべきではないと思います...情報をリストとして渡すべきですか?

  2. DataFrameからのエッジ情報のみを使用してグラフを作成し、各ノードに他のDataFrameからの情報を属性として追加する必要がありますか?これを行うには、DataFrameとノードを反復処理するよりも良い方法はありますか?

13
José

nx.from_pandas_dataframe を使用して、エッジテーブルから加重グラフを作成します。

import networkx as nx
import pandas as pd

edges = pd.DataFrame({'source' : [0, 1],
                      'target' : [1, 2],
                      'weight' : [100, 50]})

nodes = pd.DataFrame({'node' : [0, 1, 2],
                      'name' : ['Foo', 'Bar', 'Baz'],
                      'gender' : ['M', 'F', 'M']})

G = nx.from_pandas_dataframe(edges, 'source', 'target', 'weight')

次に set_node_attributes を使用して辞書からノード属性を追加します:

nx.set_node_attributes(G, 'name', pd.Series(nodes.name, index=nodes.node).to_dict())
nx.set_node_attributes(G, 'gender', pd.Series(nodes.gender, index=nodes.node).to_dict())

または、グラフを反復処理してノード属性を追加します。

for i in sorted(G.nodes()):
    G.node[i]['name'] = nodes.name[i]
    G.node[i]['gender'] = nodes.gender[i]

更新:

nx 2.0以降、nx.set_node_attributesの引数の順序には 変更 があります:(G, values, name=None)

上記の例を使用すると:

nx.set_node_attributes(G, pd.Series(nodes.gender, index=nodes.node).to_dict(), 'gender')
18
harryscholes

基本的には同じ答えですが、いくつかの詳細が入力されて更新されています。基本的に同じ設定から始めますが、ここではノードのインデックスはなく、@ LancelotHolmesコメントをアドレス指定してより一般的な名前にします。

import networkx as nx
import pandas as pd

linkData = pd.DataFrame({'source' : ['Amy', 'Bob'],
                  'target' : ['Bob', 'Cindy'],
                  'weight' : [100, 50]})

nodeData = pd.DataFrame({'name' : ['Amy', 'Bob', 'Cindy'],
                  'type' : ['Foo', 'Bar', 'Baz'],
                  'gender' : ['M', 'F', 'M']})

G = nx.from_pandas_edgelist(linkData, 'source', 'target', True, nx.DiGraph())

ここで、Trueパラメータは、linkDataのすべてのプロパティをリンクプロパティとして保持するようNetworkXに指示します。この場合、それをDiGraph型にしましたが、それが必要なければ、明白な方法で別の型にすることができます。

ここで、linkDataから生成されたノードの名前でnodeDataを照合する必要があるので、nodeDataデータフレームのインデックスをnameプロパティに設定してから、NetworkX 2 .xは、ノード属性としてロードできます。

nx.set_node_attributes(G, nodeData.set_index('name').to_dict('index'))

これにより、nodeDataデータフレーム全体が、キーが名前であるディクショナリにロードされます。他のプロパティは、そのキー内のキーと値のペアです(つまり、ノードインデックスがその名前である通常のノードプロパティ)。

2
Aaron Bramson

小さな発言:

from_pandas_dataframeはnx 2では機能しません。これを参照してください

G = nx.from_pandas_dataframe(edges, 'source', 'target', 'weight')

Nx 2.0では次のようになっていると思います。

G = nx.from_pandas_edgelist(edges, source = "Source", target = "Target")
1
Ioanna