Python

[Python]NetworkXの使い方まとめ

今回は、PythonライブラリであるNetworkXについて紹介します。

僕自身、研究でNetworkXを使用していたのでその知識を踏まえて解説していきます。

NetworkX使う前に

NetworkXを使う前に知っておきたいことや環境構築の方法について紹介します。

[超基本]グラフ理論

NetworkXを使う上で超基本的な知識としてグラフ理論というものがあります。

グラフとは、頂点(node)と辺(edge)から構成された集合で構成されるグラフに関する数学の理論です。

この辺には、重み(weight)をつけることができ、これにより最短経路問題などを解くことができます。

グラフ理論(無向グラフ)
覚えておきたい基本用語
  • ネットワーク(Graph
  • 頂点(node)
  • 辺(edge)
  • 重み(weight)

このグラフ理論を応用してさまざま場面のシュミュレーションを行うことができます。

NetworkXとは

NetworkXとはPythonのネットワーク・グラフを生成できるライブラリです。

主にデータ分析を行う際に用いられ、簡単にグラフを生成することができます。

また、他のライブラリとの相性も良く、matplotlibを用いてグラフを描写したり、pandasなどのデータ操作系のライブラリと併用して用いることができます。

環境構築

NetworkXは、Pythonの組み込みライブラリではないため、インストールが必要です。

pipの場合

pip install network

Anacondaの場合

conda install -c anaconda networkx

Anacondaの場合だとインストールしなくても初期ライブラリとしてインストールされている場合があります。

また、Google Colaboratoryを使用すると環境構築をせずに使うことができます。

基本的な使い方

ここからは、NetworkXの基本的な使い方を紹介します。

グラフオブジェクト作成

空のグラフオブジェクトを作成します。

NetwrokXでは、グラフの種類を選択することができ、ここでは無向グラフと有向グラフの2種類を紹介します。

無向グラフと有向グラフの違いは有向グラフでは、矢印の方向にしかフローを流すことができません。

無向グラフと有向グラフ

NetworkXをインポートします。

import networkx as nx

グラフオブジェクトを生成

G1 = nx.Graph()  #有向グラフ

G2 = nx.DiGraph()  #無向グラフ

グラフ構築

グラフを構築するために頂点(node)と辺(edge)を追加する必要があります。

ここでは、その方法と削除する方法も紹介します。

import networkx as nx
G = nx.Graph()

#nodeの追加
G.add_node(3)
G.add_nodes_from()

#nodeの削除
G.remove_node(3)
G.remove_nodes_from()

#edgeの追加
G.add_edge(3, 5)
G.add_edges_from([(3, 5), (6, 7), (8, 5)])

#edgeの削除
G.remove_edge(3, 5)
G.add_edges_from([(1, 3), (6, 7), (8, 5)])

辺(edge)を追加する際、2つの頂点(node)を指定すると

それに対応した辺(edge)と頂点(node)が作成されます。

値の取得

nodeとedgeの総数を所得します。

#node総数を所得
G.number_of_nodes()
#5

#edge総数を所得
G.number_of_edges()
#3

属性

頂点や辺に属性を指定することができます。属性は、頂点や辺の辞書型に設定されます。

辞書型になっているのがすごく便利です!

この属性を指定する仕組みを用いてグラフ理論で説明した重みを指定することができます。

属性の指定

import networkx as nx
G = nx.Graph()

#nodeの属性追加
G.add_nodes_from([(2, {"weight": 3}),(3, {"weight": 4})])

#edgeの属性追加
G.add_edges_from([(6,7,{'weight':3}),(8,9,{'weight':5})])

#nodeの一覧取得
print(dict(G.nodes))
#{2: {'weight': 3}, 3: {'weight': 4}}

#edgeの一覧取得
print(dict(G.edges))
#{(6, 7): {'weight': 3}, (8, 9): {'weight': 5}}

全ての属性を指定する方法

#全てのnodeの属性を100に指定
nx.set_node_attributes(G, 100, "weight")

#全てのedgeの属性を100に指定
nx.set_edge_attributes(G, 50, "weight")

print(dict(G.nodes))
#{2: {'weight': 100}, 3: {'weight': 100}, 6: {'weight': 100}, 7: {'weight': 100}, 8: {'weight': 100}, 9: {'weight': 100}}

print(dict(G.edges))
#{(6, 7): {'weight': 50}, (8, 9): {'weight': 50}}

属性取得

#nodeの属性取得
a = nx.get_node_attributes(G, "weight")

#edgeの属性取得
b = nx.get_edge_attributes(G, "weight")

#node2の属性取得
print(a)
#100

#edge(6,7)の属性所得
print(b[(6,7)])
#50

グラフの可視化

NetworkXで作成したグラフを可視化していきます。

可視化をするためにPythonのライブラリであるMatplotlib使用します。

Matplotlib

Matplotlibは、棒グラフや折線グラフなどさまざまなグラフを描画するためのPythonライブラリです。

2次元関数や3次元関数にも対応しており、グラフも可視化することができます。

グラフを可視化することで、グラフを可視化することで隠れた情報や特徴を明示することができます。

可視化を実装

では、可視化していきましょう!

import matplotlib.pyplot as plt
import networkx as nx

G = nx.Graph()
G.add_edges_from([(0,1), (1,2), (2,4),(5,1)])
nx.draw(G, with_labels = True)
plt.show()
グラフの可視化
nx.draw(G, with_labels = True)

Matplotlibで図を作成する時に行う記述で、with_labelsをTrueにすることでラベルをつけることができます。

plt.show()

これで図を表示します。

知っておくと便利な使い方

NetworkXの使い方は、本当にたくさんあります。

Networkx公式ドキュメントを参考に自分のやりたいことにあった使い方をしていきましょう。

次は、僕が実際に使っていたものを紹介します。

経路探索

NetworkXでは、さまざまな探索アルゴリズムを簡単に呼びだすことができます。

本来なら50行ほど必要なアルゴリズムをたったの1行で行うことができます。

ここでは、ダイクストラ法という最短経路アルゴリズムの実装例を紹介します。

import networkx as nx

G = nx.Graph()
G.add_edges_from([("S","A",{'weight':4}), ("S","B",{'weight':3}), ("A","G",{'weight':6}),("B","G",{'weight':4}),("A","B",{'weight':4})])
作成したグラフ
#最短経路のパスを表示する
print(nx.dijkstra_path(G, "S", "G"))
#['S', 'B', 'G']

#始点から各頂点までの距離を返す
print(nx.dijkstra_predecessor_and_distance(G, "S"))
#({'S': [], 'A': ['S'], 'B': ['S'], 'G': ['B']}, {'S': 0, 'B': 3, 'A': 4, 'G': 7})

#最短経路の距離を表示する。
print(nx.dijkstra_path_length(G, "S","G"))
#7

ダイクストラ法で最短経路を求めました。

ダイクストラ法は、NetworkXを使用せずにPythonで作成すると、30行ほどは必要となる複雑なアルゴリズムです。

しかし、NetworkXを用いると簡単に探索することができます。

他にも経路探索系のアルゴリズムはたくさんあるので、興味があれば公式ドキュメントを参考にしてください。

隣の頂点(node)を返す

all_neighbors(graph, node)

隣の頂点をイテレータとして返すことができます。

イテレータの意味については、イテレータを参照してください。

for a in nx.all_neighbors(G,"S"):
    print(a[0])

#A
#B

隣接している頂点をfor文で順に返すことができます。

参考文献

まとめ

今回は、NetworkXの使い方について紹介しました。

NetworkXは、簡単にグラフを作成することができ、他のライブラリと組み合わせる汎用性の高いライブラリです。

まだまだ、使い方があるので今後もNetworkXについて、紹介しようと思います!!!