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 addedG.add_edge(1,2)
G.add_edge(3,2)
# Adding multiple edges at a timeG.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 graphG.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 graphG.remove_edge(2, 1)
# Removing edge 3-4 and 1-4 at onceG.remove_edges_from([(3, 4), (1, 4)])
print()
print(G.nodes())
print(G.edges())
# Removing node 5 from graphG.remove_node(5)
# Removing node 7 and 8G.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 33 |
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_nodeG.add_node(1, data = "data1")
# Using add_nodes_fromG.add_nodes_from([(2, {"data": "data2"}),
(3, {"data": "data3"})],
node_type = "child node")
# Adding more attributes on node 1 using G.nodesG.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_edgeG.add_edge(1, 2, weight = 50)
# Using add_edges_fromG.add_edges_from([ (1, 3, {"weight": 70}),
(1, 4, {"weight": 100})
])
# Using subscript notationG.add_edge(4,5)
G[4][5]["weight"] = 175
# Using G.edgesG.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_edgeG.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_edgeG.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 4print("Out edges of node 4 are:",DG.out_edges(4))
# Print in degree of node 2print("In Degree of node 2 is:",DG.in_degree(2))
# Print successors of node 4print("Successors of node 4 are:",list(DG.successors(4)))
# Print predecessors of node 2print("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: 2Successors 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 パッケージと、それを使ってグラフを作成、操作、視覚化する方法について学びました。
このライブラリは、複雑なネットワークやグラフを研究する際に役立ちます。
数学者、物理学者、生物学者、コンピュータ科学者などが研究のために使用します。
お読みいただきありがとうございました。