YutaKaのPython教室

Python の文法やライブラリ、API、環境構築について画像・動画・ソースコード付きで徹底解説!

Pythonでネットワーク分析【図解でわかりやすく解説】

Pythonには、データ分析をサポートする様々なモジュールが存在します。

その一つに、強力なネットワーク分析ツールとしてNetworkXというものがあります。

NetworkXを使えば、次のようなネットワーク分析を簡単に行うことができます。

  • ネットワーク分析
  • ネットワーク構造の可視化
  • 中心性や連結性などの解析

この記事では、NetworkXの基本的な使い方を中心にわかりやすく解説していきます。

さらに詳しい内容については、次のような書籍を参考にしてみてください。

ネットワーク分析の準備

まずはネットワーク分析の基礎知識、分析のための環境構築について解説していきます。

ちなみに以下で解説するような基本的な内容を網羅的に学びたい場合は次のような書籍がおススメです。

私もこの書籍から入門しています。

ネットワーク分析の基礎知識

ネットワーク分析に関する超基本用語を整理していきましょう。

次の4つの用語をおさえれば、基本的な可視化を行うことができます。

要素 NetwrokXでの名前 適用
ネットワーク Graph ネットワーク図全体のこと
頂点 node 一つ一つの要素のこと
edge 頂点と頂点を繋ぐ線のこと
次数 degree 頂点の持つ辺の数のこと

ネットワーク図を使って、各要素がどこに対応するか確認してみましょう。

この他にも必要に応じて各要素に任意の属性を持たせることも可能です。

例えば、次のような要素を与えることができます。

  • size: nodeの大きさ
  • weight: nodeedgeの重み(経路探索などの最適化問題で使うことがある)
  • color: nodeedgeの色

これらは属性として与えられるというだけで、属性をネットワーク図に反映するには別途設定が必要です。

基本用語を把握できたので、次はネットワーク分析用のモジュールNetworkXについて解説します。

NetworkXとは?

NetworkXとは、Pythonでネットワーク分析を行うため外部モジュールです。

NetworkXを使うと次の様な操作を行うことができます。

  • ネットワーク図の作成
  • 各要素のデータの出力
  • ネットワークの分析(最適解の探索など)

特にグラフの作成が非常に簡単かつ高速なので、Pythonでネットワーク分析を行う際には必須のモジュールとも言えます。

以下でNetworkXの基本的な使い方をわかりやすく解説していきます。

環境構築

NetworkXは組み込みライブラリではないので、pipまたはcondaでインストールします。

pipでインストールする場合は、ターミナルで以下のコマンドを実行します。

pip install pypdf

Anacondaの場合は次のコマンドでインストールしましょう。

conda install networkx

ただし、condaの場合はNetworkXのバージョンが古い場合があります。

最新のNetworkXに比べて、バージョンが古い場合はconda-forgeからインストールするのも一つの手です。

conda install networkx -c conda-forge
  • 【参考】conda-forgeの使い方については、次の記事で詳しく解説しています。
≫バッチファイルでJupyter Lab起動!ダブルクリックで起動可能に!
Jupyter Labを起動するときに、いちいちコンソールを開いて、jupyter labと打つのがめんどくさい!という方のために、Jupyter Labを起動するバッチファイルの作成方法を紹介します。少し応用すると、ノートブックを指定して起動するバッチファイルも作成可能です!これでダブルクリックだけで、Jupyter Labを起動できるようになりますね。
www.yutaka-note.com/entry/jupyter_bat
 

環境構築は飛ばして、とりあえずネットワーク分析を試したい場合は、Google Colaboratoryを使用すれば、初めからインストールされているので設定不要です。

≫5min. Python解説動画【入門編】|第2回 Colaboratoryで環境構築!
Google Colaboratoryを使えば、初心者の方でもすぐにPythonを始められます。この記事ではColaboratoryの初期設定方法、コードの書き方、押さえておきたい便利な使い方を紹介しています!
www.yutaka-note.com/entry/5min_python_02
 

NetworkXのインポート

NetworkXのインストールが終わったらコード上でインポートして使いましょう。

NetworkXnxという別名でインポートする慣例があるようです。

import networkx as nx

ネットワーク分析ではグラフの出力をすることもあるので、一緒にMaplotlibもインストールしておくと良いですね。

import matplotlib.pyplot as plt
import networkx as nx

NetworkXのバージョンは次のスクリプトで確認できます。

import networkx as nx
print(nx.__version__)

# 3.1

NetworkXMatplotlibで、どちらかのバージョンが極端に古いと互換性がない場合があります。

両方とも新しいバージョンにしておくと、そういったトラブルを避けやすくなると思います。

  • 【参考】Matplotlibの使い方については、次の記事で詳しく解説しています。
≫【初心者向け】Matplotlibの特徴と使い方をわかりやすく解説!
脱初心者のためのMatplotlibマスターガイドです。そもそもどういう流れでプロットするのか?どんな種類のグラフが描けるのか?日本語設定は?タイトルや軸の設定は?オブジェクト指向って何?そんな疑問を解決します!この記事で、脱Matplotlib初心者を目指そう!
www.yutaka-note.com/entry/matplotlib_guid
 

ネットワーク分析・可視化の超基本形

ネットワークの可視化のためには、次の手順を踏みます。

  1. Graphオブジェクトの作成:G = nx.Graph()
  2. nodeの追加:G.add_nodes_from([node1, node2, node3,…])
  3. edgeの追加:G.add_edges_from([(node1, node2), (node2, node3), …])
  4. ネットワークの可視化:nx.draw(G, witlabels = True)

オブジェクト作成から、可視化までの基本形は次のようになります。

# Graphオブジェクトの作成
G = nx.Graph()
 
# nodeデータの追加
G.add_nodes_from(["A", "B", "C", "D", "E", "F"])
 
# edgeデータの追加
G.add_edges_from([("A", "B"), ("B", "C"), ("B", "F"),("C", "D"), ("C", "E"), ("C", "F"), ("B", "F")])

# ネットワークの可視化
nx.draw(G, with_labels = True)
plt.show()

これで、次のようなグラフが描けます。

各手順について詳細を確認していきましょう。

Graphオブジェクトの作成

まずは、Graphオブジェクトを生成します。

  • G = nx.Graph()

この時点では、空のグラフが生成されているだけです。

このグラフにnodeedgeを追加して、ネットワークを完成させていきます。

nodeの追加

次にnodeを追加していきます。

1つだけ追加する場合は、.add_node(), 2つ以上追加する場合は.add_nodes_from()を使います。

  • G.add_node(node1)
  • G.add_nodes_from([node1, node2, node3,…])

nodeの要素としては辞書のキーとして使えるものが使用できると考えると良いです。

G = nx.Graph()
G.add_nodes_from(["A", "B", "C", "D", "E", "F"])

nx.draw(G, with_labels = True)
plt.savefig("03_add_nodes_fromの例.png", bbox_inches="tight")
plt.show()

次のようにnodeが生成されています。

edgeは指定していないので、node同士は結合していませんね。

次のようにnodeに属性を与えることもできます。

  • G.add_nodes_from(["A", "B"], size=10)
  • G.add_nodes_from([("A", {"size":10}), ("B", {"size":20})])

任意の属性を与えることが可能です。

ただし、属性を設定するだけで自動でグラフの見た目が変化するわけではないです。

グラフに反映する場合は自分で見た目の変更を行いましょう。

edgeの追加

次にnodeを追加していきます。

1組だけ追加する場合は、.add_edge(), 2つ以上追加する場合は.add_edges_from()を使います。

  • G.add_edge(node1, node2)
  • G.add_edges_from([(node1, node2), (node2, node3), …])

存在しないnodeを指定すると自動で追加されます。

## edgeの追加

# ネットワーク可視化の実行例
# Graphオブジェクトの作成
G = nx.Graph()
 
# nodeデータの追加
G.add_nodes_from(["A", "B", "C", "D", "E", "F"])
 
# edgeデータの追加
G.add_edges_from([("A", "B"), ("B", "C"), ("B", "F"),("C", "D"), ("C", "E"), ("C", "F"), ("B", "F")])

# ネットワークの可視化
nx.draw(G, with_labels = True)
plt.savefig("04_edgeの追加例.png", bbox_inches="tight")
plt.show()

次のようなネットワーク図が完成します。

nodeと同様に、edgeにも属性を与えることができます。

edgeの属性としては、wieghtを与えることが多いので、weightを与えるためのメソッドも存在します。

  • G.add_edges_from([("A", "B"), ("B", "C")], weight=1)
  • G.add_weighted_edges_from([("A", "B", 1), ("B", "C", 2)])

.add_weighted_edges_from()では、("node1", "node2", weight)の組み合わせを渡しています。

ネットワーク図の保存

作成した図を保存するのは、Matplotlibと同様にplt.savefig()を使用します。

  • plt.savefig("保存名.png")

【参考】Matplotlibでの画像の保存方法については、次の記事で詳しく解説しています。

≫matplotlib 画像の保存方法|savefigの使い方
Pythonのデータ可視化ライブラリといえば、Matplotlibですね。Matplotlibで作成した画像は様々なファイル形式で保存することができます。しかし、実際に画像を保存しようとすると、次のような問題に直面することも… ① 画像として保存するにはどのメソッドを実行すればいいの? ② ファイルの種類を指定することはできる? ③ 画像の見た目を調整してから保存したい! この記事では、Matplotlibの.savefig()を使って画像を保存する方法について、分かりやすく解説していきます。
www.yutaka-note.com/entry/matplotlib_savefig
 

基本的な特性値の出力

次に作成したネットワークの基本データを出力する方法を確認していきましょう。

出力内容 出力方法
ノードとエッジの数 print(G)
ノードの数 G.number_of_nodes()
ノードの要素 G.nodes()
エッジの数 G.number_of_edges()
エッジの要素 G.edges()
各ノードの実数 G.degrees()

バージョン2.Xまでは、nx.info()という関数で基本テータを出力できましたが、3.Xからはこの関数はなくなりました。

基本データをさっと確認する場合はprint()関数で確認します。

print(G)

# Graph with 7 nodes and 6 edges

その他の実行例も確認してみましょう。

ノードの出力

ノードの基本出力メソッドは次の通りです。

  • ノードの数:G.number_of_nodes()
  • ノードの要素:G.nodes()

サンプルコードで挙動を確認してみましょう。

print("number of nodes:",G.number_of_nodes())
print("nodes:", G.nodes())
 
# number of nodes: 6
# nodes: ['A', 'B', 'C', 'D', 'E', 'F']

隣接したノードの出力方法

隣接したノードを出力したい場合は、.all_neighbors()関数を使います。

  • nx.all_neighbors(G, ノード名)

結果はイテレータで返されます。

サンプルコードで挙動を確認してみましょう。

for n in nx.all_neighbors(G, "C"):
    print(n) 
# B
# D
# E
# F

エッジの出力

エッジの基本出力メソッドは次の通りです。

  • エッジの数:G.number_of_edges()
  • エッジの要素:G.edges()

サンプルコードで挙動を確認してみましょう。

print("number of edges:",G.number_of_edges())
print("edges:", G.edges())
 
# number of edges: 6
# edges: [('A', 'B'), ('B', 'C'), ('B', 'F'), ('C', 'D'), ('C', 'E'), ('C', 'F')]

次数の出力

次数の基本出力メソッドは次の通りです。

  • 各ノードの次数:G.degrees()

各ノードの次数が自動集計を自動で集計することができます。

サンプルコードで挙動を確認してみましょう。

print("degrees:", G.degree())
 
# degrees: [('A', 1), ('B', 3), ('C', 4), ('D', 1), ('E', 1), ('F', 2)]

ネットワーク図の見た目変更

ネットワーク図の見た目を変更するには、nx.draw()メソッドでキーワード引数を設定します。

基本的な設定要素は下記の通りです。

要素 引数 設定例
nodeの色 edge_color "色名" or "色名のリスト"など
※デフォルト:'C0' 薄い青
nodeのサイズ node_size "数値" or "数値のリスト"など
※デフォルト:300
edgeの色 edge_color "色名" or "色名のリスト"など
※デフォルト:'black'
edgeの太さ width "数値" or "数値のリスト"など
※デフォルト:1

それぞれ、グラフ内で一括で設定する場合には、"色名""数値"を指定します。

要素ごとに設定する場合は、要素の数に応じた[リスト]等で指定します。

それぞれ実行例を確認してみましょう。

一括で設定(色、ノードサイズ、エッジの太さ)

キーワード引数としてシリアル値(リストでなく1つの値)を与えると、グラフ全体に適用されます。

ノードの色を"red"、エッジの色を"gray"、太さを500にしてみましょう。

nx.draw(G, with_labels=True, 
        node_color = "red",
        edge_color = "gray",
        node_size = 500, 
        width = 5)
plt.savefig("05_ネットワーク図の見た目変更(一括設定)例.png", bbox_inches="tight")
plt.show()

ネットワーク図の見た目が一括で変更されていますね。

要素毎に設定

[リスト]で設定値を渡すことで、各ノード、エッジに異なる設定を適用できます。

各要素の順番に対応するように設定値を渡します。

次の例ではノードの各要素の色をcolorsというリストで渡しています。

colors = ["lightblue", "green", "red", "cyan", "magenta", "yellow"]
nx.draw(G, with_labels=True, node_color = colors)
plt.savefig("06_ネットワーク図の見た目変更(個別設定)例.png", bbox_inches="tight")

plt.show()

次のようにノードに色が設定されます。

色の設定で個別に色を設定する場合は、Matplotlibのカラーサイクルを使うとキレイに色付けできます。

カラーマップを生成して、要素の数だけ色を準備しておきます。

  • カラーマップ生成:cmap = plt.get_cmap("Pastel1")
  • node数の色を準備:node_color = [cmap(i) for i in range(G.number_of_nodes())]

サンプルコードで挙動を確認してみましょう。

# カラーマップから色の準備
cmap = plt.get_cmap("Pastel1")
node_color = [cmap(i) for i in range(G.number_of_nodes())]

# ネットワークの可視化
nx.draw_networkx(G, with_labels=True, node_color = node_color)
plt.savefig("01_simple_network.png", bbox_inches="tight")

plt.show()

次のようにカラーマップで色付けされたネットワーク図が作れます。

  • 【参考】カラーマップの使い方については、次の記事で詳しく解説しています。
≫Matplotlib color 色の指定 | 一文字指定からカラーマップの使い方まで徹底解説
伝わるグラフを作るためのポイントはなんでしょうか?いかに視覚的にわかりやすいか、これが大切です。それには重要な要素に色をつけて、視覚的にうったえることが超大切!この記事では、matplotlibでの色の指定方法について、基本から応用まで徹底解説!
www.yutaka-note.com/entry/matplotlib_color
 

ネットワーク可視化例|次数に応じた配色・サイズ変更

最後に、各ノードの次数に応じて配色・サイズ変更する例を紹介します。

これまで、紹介してきた特性値の出力方法、ネットワーク図の見た目変更を組み合わせていきます。

実行例として、次のようなグラフを作成してみましょう。

このグラフは次の様なグラフになっています。

  • ネットワーク図のnodeのサイズが次数の数に比例
  • ネットワーク図と棒グラフで各nodeの色が対応

色やサイズの設定が適切に設定できれば簡単に作成できます。

簡単な工夫ですが、デフォルトのネットワーク図よりも視認性がだいぶ上がっていますね。

以下で実装例を紹介していきます。

次数に応じたネットワーク図の例

まずは、ノードの色付け、次数に応じたサイズ調整を行いましょう。

d = G.degree()
import numpy as np
np.array([d for n, d in G.degree()])
degrees = np.array([d for n, d in G.degree()])
degrees.mean()
# 各nodeの次数を取得
degrees = np.array([d for n, d in G.degree()])

# ノードの次数に比例するようにサイズを設定
sizes = 300 * degrees / degrees.mean()
print(sizes)
# [150.0, 450.0, 600.0, 150.0, 150.0, 300.0]
 
# カラーマップから色を生成
cmap = plt.get_cmap("Pastel1")
node_color = [cmap(i) for i in range(G.number_of_nodes())]

# グラフの出力
plt.figure(figsize = (10,5))
plt.subplot(121)
nx.draw(G, with_labels=True, node_color = node_color, node_size = sizes, edge_color = "black")

plt.show()

次のようにノードのサイズに応じたサイズ変更ができました。

情報をわかりやすくするために、次数に関する棒グラフを作成してみましょう。

次数順の棒グラフの作成

次に各ノードの次数順の棒グラフを作成してみましょう。

nodes_sorted_by_degree = sorted(G.degree(), key=lambda x: x[1], reverse=True)
print(nodes_sorted_by_degree)
# [('C', 4), ('B', 3), ('F', 2), ('A', 1), ('D', 1), ('E', 1)]
 
# 色のリストを次数順に並び替える
colors_dict = dict(zip(G.nodes(), node_color))
colors_sorted = [colors_dict[node] for node, _ in nodes_sorted_by_degree]

# グラフの出力
x, height = list(zip(*nodes_sorted_by_degree))
plt.subplot(122)
plt.xlabel("Number of degrees")
plt.ylabel("Name of node")
plt.barh(x, height, color = colors_sorted)

plt.savefig("08_次数の棒グラフ.png", bbox_inches="tight")
plt.show()

ネットワーク図の描画と合わせて実行すると、次の様なグラフができます。

  • 【参考】subplotの使い方については、次の記事で詳しく解説しています。
≫Matplotlib plt.subplotの使い方徹底図解!|一つの図に複数グラフを描く
Matplotlibで一つの図の中に複数のグラフを並べるにはどうすればいいの?plt.subplot()でグラフを並べられるらしいけど、使い方がよくわからない!という方のために、「plt.subplot()の基本的な使い方」を画像付きで解説していきます!plt.subplot()でプロットをキレイに配置して、見やすく人に伝わるグラフを目指しましょう!
www.yutaka-note.com/entry/2020/01/02/232925
 
  • 【参考】Matplotlibでの棒グラフ作成方法については、次の記事で詳しく解説しています。
≫Matplotlib 棒グラフを徹底解説|複数系列・積み上げ棒グラフ全てOK
Matplotlibで棒グラフを作成する方法がよくわからない…。 棒グラフで悩むなら、MatplotlibあきらめてExcel使おうかな…。 と思ったことはありませんか?そんな方のために、Matplotlibの棒グラフ作成方法を徹底的に解説しました!複数系列?積み上げ棒グラフ?全部大丈夫!
www.yutaka-note.com/entry/matplotlib_bar
 

最短経路の探索

NetworkXにはネットワーク内の最短経路を探索する関数も準備されています。

特定の2点間の最短距離を探すには、nx.shortest_path()関数を使用します。

  • nx.shortest_path(G, source=始点ノード, target=終点ノード)

サンプルコードで挙動を確認してみましょう。

nx.shortest_path(G, source="A", target="D")
# ['A', 'B', 'C', 'D']

最短経路の探索結果をネットワーク図内に表示する例を紹介します。

探索結果をもとにネットワーク図の見た目を変更すればOKです。

# カラーマップから色を生成
cmap = plt.get_cmap("Pastel1")
node_color = [cmap(i) for i in range(G.number_of_nodes())]

# 最短経路の探索
shortest_pass = nx.shortest_path(G, source="A", target="D")
highlited_edges = list(zip(shortest_pass, shortest_pass[1:]))

# 最短経路のエッジに色付け
G.add_edges_from(highlited_edges, color="tab:blue")
edge_color_dict = nx.get_edge_attributes(G, "color")
edge_color = [edge_color_dict[p] if p in edge_color_dict else "gray" for p in G.edges()]

# ネットワーク図の描画
nx.draw(G, node_color=node_color, edge_color=edge_color, with_labels=True)

plt.savefig("09_最短経路を強調.png", bbox_inches="tight")
plt.show()

次のように最短経路を探索して、強調表示したグラフを描けます。

NetworkXの機能をうまく使えば、最短経路の描画も簡単ですね。

上の例ではMatplotlibのデフォルトの色(tab:blue)を使って、最短経路を強調表示しています。

他のグラフとの一貫性を保つために、Matplotlibのデフォルトの色を使用することも多いです。

  • 【参考】Matplotlibのデフォルトの色については、次の記事で詳しく解説しています。
≫Matplotlib デフォルトの色の変更|実は一行でできます!
Matplotlibでグラフを描くと、デフォルトで青→オレンジ→緑→…と色が変わっていきます。この記事では、`Matplotlib`のデフォルトの色(カラーサイクル)の設定変更について紹介していきます。①データが10系列以上あるときに、また青に戻ってしまう場合の対応方法②自分好みにカラーサイクルを変更する方法また、デフォルトの色を指定して使用する方法についても触れています。
www.yutaka-note.com/entry/matplotlib_color_cycle
 

ネットワーク分析おススメの1冊!

pythonでネットワーク分析をしたい方には、こちらの本がおススメです。

実は私はネットワーク分析の基本どころか、NetworkXの存在すらしらなかったのですが…。

この本では次の様な内容が詳しく解説されています。

  • ネットワーク分析の流れや用語説明
  • NetworkXをサンプルコード付きで解説

私のような初学者でもすぐに簡単なネットワーク分析をできるようになりました!

今回の記事では紹介しませんでしたが、本の中では次の様な内容についても解説しています。

  • ネットワークの中心性を解析する方法
  • グループの分割・抽出方法

ネットワーク分析の勉強にオススメな1冊でした!