NetworkXパッケージは、グラフやネットワークを研究するためのPythonライブラリです。
動的で複雑なネットワーク構造を作成、操作、研究するためのツールを提供します。
NetworkXを使用すると、多くのデータ形式でネットワークをロードして保存し、多くの種類のランダムおよび古典的なネットワークを生成し、ネットワーク構造を分析し、ネットワークモデルを構築し、新しいネットワークアルゴリズムを設計し、ネットワークを描画し、その他にも多くのことを行うことができます。
この記事では、NetworkXを使用してグラフを作成し、ネットワークを研究する方法を学びます。
NetworkX パッケージのインポート
NetworkX パッケージを使用するために、ローカルマシンにダウンロードする必要があります。
pipコマンドでダウンロードできます。
pip install networkx
|
そして、以下のようにライブラリをインポートします。
import networkx as nx
|
グラフにノードを追加する
まず、以下のように Graph()
クラスを呼び出して、空のグラフを作成します。
G = nx.Graph()
|
NetworkXのノードは、整数、文字列、画像、XMLオブジェクトなど、ハッシュ可能な任意のオブジェクトにすることができます。
また、NetworkXのグラフであることもできます。
グラフにノードを追加するには、2つのメソッドがあります。
- add_node()。ノードを1つずつ追加するメソッドです。
- add_nodes_from(): このメソッドは、1つのノードを一度に追加するために使用されます。リストやセットなどの反復可能なコンテナを受け取り、複数のノードを一度に追加するメソッドです。
import networkx as nx
G = nx.Graph()
G.add_node( 1 )
G.add_nodes_from([ 2 , 3 , "node 5" ])
print (G.nodes())
|
[1, 2, 3, 'node 5'] |
グラフにエッジを追加する
エッジとは、2つのノードの間のリンクのことです。
グラフにエッジを追加するには、主にこの2つの方法が使われます。
パラメータで指定された未知のノードは、自動的にグラフに追加される。
- add_edge()。一度に1つのエッジを追加するメソッド。
- add_edges_from(): このメソッドは、一度に1つのエッジを追加します。リストやイテレータのようなエッジのタプルの反復可能なコンテナを取る。
ノードやエッジの再追加は、NetworkX では無視されます。
import networkx as nx
G = nx.Graph()
# Adding one edge at a time # Node 1 and 2 will be automatically added G.add_edge( 1 , 2 )
G.add_edge( 3 , 2 )
# Adding multiple edges at a time G.add_edges_from([( 4 , 2 ), ( 3 , 5 ), ( 5 , 4 )])
# Adding duplicates will be ignored. G.add_node( 1 )
G.add_edge( 1 , 2 )
print (G.nodes())
print (G.edges())
|
[1, 2, 3, 4, 5] [(1, 2), (2, 3), (2, 4), (3, 5), (4, 5)] |
グラフからノードとエッジを削除する
ノードやエッジを追加するのと同様に、一度に単一のノードやエッジを削除することができますし、一度に複数のノードやエッジを削除することもできます。
- remove_node()。このメソッドは、1つのノードとそのノードに関連するエッジをグラフから削除します。もし、そのノードがグラフに存在しない場合、
NetworkXError
を発生します。 - remove_nodes_from(): このメソッドは反復可能なコンテナを取り、グラフからすべてのノードとそのノードに関連するエッジを削除します。ノードがグラフに存在しない場合は、何も変更せずに黙って破棄します。
- remove_edge()。このメソッドは、ノードをそのままにグラフからエッジを1つ削除します。もし、そのエッジがグラフに存在しない場合は、
NetworkXError
を発生します。 - remove_edges_from(): このメソッドは、反復可能なコンテナを受け取ります。このメソッドは反復可能なコンテナを取り、グラフからエッジを削除します。グラフに存在しないエッジは、変更されずに破棄される。
import networkx as nx
G = nx.Graph()
# Creating graph G.add_edges_from([( 1 , 2 ), ( 2 , 3 ), ( 3 , 4 ), ( 4 , 1 )])
G.add_edges_from([( 5 , 6 ), ( 5 , 7 ), ( 5 , 8 ), ( 7 , 8 )])
print (G.nodes())
print (G.edges())
# Removing edge 1-2 from graph G.remove_edge( 2 , 1 )
# Removing edge 3-4 and 1-4 at once G.remove_edges_from([( 3 , 4 ), ( 1 , 4 )])
print ()
print (G.nodes())
print (G.edges())
# Removing node 5 from graph G.remove_node( 5 )
# Removing node 7 and 8 G.remove_nodes_from([ 7 , 8 ])
print ()
print (G.nodes())
print (G.edges())
|
[1, 2, 3, 4, 5, 6, 7, 8] [(1, 2), (1, 4), (2, 3), (3, 4), (5, 6), (5, 7), (5, 8), (7, 8)] [1, 2, 3, 4, 5, 6, 7, 8] [(2, 3), (5, 6), (5, 7), (5, 8), (7, 8)] [1, 2, 3, 4, 6] [(2, 3)] |
グラフの要素にアクセスする
NetworkXのグラフでは,以下の4つの基本的なグラフ要素にアクセスすることができます.
- G.nodes。グラフ内のノードのリストを返します。
- G.edges: G.edges: グラフに含まれるエッジのリストを返します.
- G.adj: G.adj: すべてのノードの隣接リストを返す.ノードXの隣接リストには,ノードXに直接リンクしている隣接ノードが含まれる.ノードに隣接するすべてのノードには,添え字表記(
G.adj
の後に角括弧を使用)でアクセスできる. - G.degree: G.degree: グラフ中の各ノードにリンクしているノードの数を返す.G.degree`の後に角括弧を付けると、そのノードの学位にアクセスできる。
import networkx as nx
G = nx.Graph()
G.add_edges_from([( 1 , 2 ), ( 1 , 3 ), ( 3 , 4 ), ( 3 , 5 )])
print ( "Nodes" )
print (G.nodes)
print ( "Edges" )
print (G.edges)
print ( "Adjacency List" )
print (G.adj)
print ( "Degree" )
print (G.degree)
print ()
print ( "Adjacency List for node 3" )
print (G.adj[ 3 ])
print ( "Degree for node 3" )
print (G.degree[ 3 ])
|
Nodes [1, 2, 3, 4, 5] Edges [(1, 2), (1, 3), (3, 4), (3, 5)] Adjacency List {1: {2: {}, 3: {}}, 2: {1: {}}, 3: {1: {}, 4: {}, 5: {}}, 4: {3: {}}, 5: {3: {}}} Degree [(1, 2), (2, 1), (3, 3), (4, 1), (5, 1)] Adjacency List for node 3 {1: {}, 4: {}, 5: {}} Degree for node 3 3 |
Graph, Nodes, Edges の属性
各グラフ、ノード、エッジは、関連する属性辞書にキーと値の属性ペアを保持することができます。
デフォルトではこれらは空であるが、 add_edge
や add_node
を用いて属性を追加したり変更したり、グラフ G
に対して G.graph
, G.nodes
, G.edges
という名前の属性辞書を直接操作したりすることができる。
1. グラフの属性
nx.Graph()`を使用してグラフを作成する際に、グラフに属性を割り当てることができます。
import networkx as nx
G = nx.Graph(graph_description = "This is an empty graph" )
print (G.graph)
# Output: {'graph_description': 'This is an empty graph'} |
また、辞書オブジェクトのように後から属性を追加・変更することもできます。
import networkx as nx
G = nx.Graph()
G.graph[ "description" ] = "This is empty graph"
G.graph[ "data" ] = 5
print (G.graph)
# Output: {'description': 'This is empty graph', 'data': 5} |
2. ノードの属性
ノードに属性を追加するには、 add_node()
, add_nodes_from()
または G.nodes
を使用します。
また、G.nodes.data()
を使用すると、すべてのノードの属性を取得することができます。
特定のノードを指定する場合は、角括弧を使用してください。
import networkx as nx
G = nx.Graph()
# Using add_node G.add_node( 1 , data = "data1" )
# Using add_nodes_from G.add_nodes_from([( 2 , { "data" : "data2" }),
( 3 , { "data" : "data3" })],
node_type = "child node" )
# Adding more attributes on node 1 using G.nodes G.nodes[ 1 ][ "type" ] = "root node"
print (G.nodes.data())
# Output: [(1, {'data': 'data1', 'type': 'root node'}), (2, {'node_type': 'child node', 'data': 'data2'}), (3, {'node_type': 'child node', 'data': 'data3'})] print (G.nodes[ 1 ])
# Output: {'data': 'data1', 'type': 'root node'} |
3. エッジの属性 – 重み付けグラフの作成
エッジの属性は、 add_edge()
, add_edges_from()
, G.edges
または添え字記法を用いて追加することができる。
エッジに属性を付与することで、図のような重み付きグラフを作成することができます。
import networkx as nx
G = nx.Graph()
# Using add_edge G.add_edge( 1 , 2 , weight = 50 )
# Using add_edges_from G.add_edges_from([ ( 1 , 3 , { "weight" : 70 }),
( 1 , 4 , { "weight" : 100 })
])
# Using subscript notation G.add_edge( 4 , 5 )
G[ 4 ][ 5 ][ "weight" ] = 175
# Using G.edges G.edges[ 1 , 2 ][ "weight" ] = 10
print (G.edges.data())
# Output: [(1, 2, {'weight': 10}), (1, 3, {'weight': 70}), (1, 4, {'weight': 100}), (4, 5, {'weight': 175})] |
NetworkXパッケージのグラフの可視化
NetworkXパッケージでは、図のようにdraw()
メソッドを用いてグラフを描き、可視化することができます。
import networkx as nx
G = nx.Graph()
# Using add_edge G.add_edge( 1 , 2 , weight = 12.5 )
G.add_edge( 3 , 2 , weight = 50.0 )
G.add_edge( 1 , 3 , weight = 17 )
G.add_edge( 4 , 2 , weight = 100 )
G.add_edge( 2 , 5 , weight = 1 )
G.add_edge( 4 , 6 , weight = 25.5 )
G.add_edge( 7 , 4 , weight = 175 )
G.add_edge( 5 , 8 , weight = 90 )
nx.draw(G, with_labels = True , font_weight = 'bold' )
|
import networkx as nx
import matplotlib.pyplot as plt
G = nx.Graph()
# Using add_edge G.add_edge( 1 , 2 , weight = 12.5 )
G.add_edge( 3 , 2 , weight = 50.0 )
G.add_edge( 1 , 3 , weight = 17 )
G.add_edge( 4 , 2 , weight = 100 )
G.add_edge( 2 , 5 , weight = 1 )
G.add_edge( 4 , 6 , weight = 25.5 )
G.add_edge( 7 , 4 , weight = 175 )
G.add_edge( 5 , 8 , weight = 90 )
pos = nx.circular_layout(G)
nx.draw(G, pos, with_labels = True , font_weight = 'bold' )
edge_weight = nx.get_edge_attributes(G, 'weight' )
nx.draw_networkx_edge_labels(G, pos, edge_labels = edge_weight)
plt.show() |
重みのあるグラフを描画したい場合は、グラフ、pos、edge_label属性を指定した nx.draw()
と共に draw_networkx_edge_labels()
を使用します。
import networkx as nx
DG = nx.DiGraph()
DG.add_edges_from([( 1 , 2 ), ( 2 , 3 ), ( 3 , 4 ), ( 4 , 5 ), ( 5 , 2 ), ( 4 , 6 )])
# Print edges going out from node 4 print ( "Out edges of node 4 are:" ,DG.out_edges( 4 ))
# Print in degree of node 2 print ( "In Degree of node 2 is:" ,DG.in_degree( 2 ))
# Print successors of node 4 print ( "Successors of node 4 are:" , list (DG.successors( 4 )))
# Print predecessors of node 2 print ( "Predecessors of node 2 are:" , list (DG.predecessors( 2 )))
nx.draw(DG, with_labels = True , font_weight = 'bold' )
|
Out edges of node 4 are: [(4, 5), (4, 6)] In Degree of node 2 is: 2 Successors of node 4 are: [5, 6] Predecessors of node 2 are: [1, 5] |
NetworkX パッケージを用いた有向グラフの作成
NetworkX では、有向グラフに特化した追加のメソッドやプロパティ、例えば DiGraph.out_edges
, DiGraph.in_degree
, DiGraph.predecessors()
, DiGraph.successors()
等を提供する DiGraph()
クラスを用いて、有向グラフを作成することも可能です。
まとめ
この記事では、NetworkX パッケージと、それを使ってグラフを作成、操作、視覚化する方法について学びました。
このライブラリは、複雑なネットワークやグラフを研究する際に役立ちます。
数学者、物理学者、生物学者、コンピュータ科学者などが研究のために使用します。
お読みいただきありがとうございました。