📋 このステップで学ぶこと
- ネットワーク図(グラフ理論)の基礎概念
- NetworkXライブラリの基本的な使い方
- ノードとエッジの作成・操作
- レイアウトアルゴリズムの種類と選び方
- 有向グラフと重み付きグラフ
- 実務での活用例(SNS分析、組織図、推薦システム)
🌐 1. ネットワーク図とグラフ理論
ネットワーク図とは何か
ネットワーク図(Network Graph)は、つながり(関係性)を持つデータを可視化する手法です。数学ではグラフ理論(Graph Theory)と呼ばれる分野に属します。
ここで言う「グラフ」は棒グラフや折れ線グラフとは別物です。「点(ノード)」と「線(エッジ)」で構成される図形のことを指します。
💡 身近なネットワークの例
私たちの周りには様々なネットワークがあります:
SNS:ユーザー(ノード)とフォロー関係(エッジ)
交通網:駅(ノード)と路線(エッジ)
組織図:社員(ノード)と報告関係(エッジ)
Webサイト:ページ(ノード)とリンク(エッジ)
友人関係:人(ノード)と友達関係(エッジ)
【ネットワーク図の構成要素】
■ ノード(Node)/ 頂点(Vertex)
├── 個々の要素を表す「点」
├── 人、組織、商品、駅など
└── 円や点で描画される
■ エッジ(Edge)/ 辺(Link)
├── ノード間のつながりを表す「線」
├── フォロー関係、友達関係、路線など
└── 直線や曲線で描画される
【図解】
(A)───(B)
│ ╲ │
│ ╲ │
(C)───(D)
ノード: A, B, C, D
エッジ: A-B, A-C, A-D, B-D, C-D
🕸️ ネットワーク図の活用場面
| 分野 |
ノード |
エッジ |
分析の目的 |
| SNS分析 |
ユーザー |
フォロー関係 |
インフルエンサー発見 |
| 組織分析 |
社員・部署 |
コミュニケーション |
情報伝達の改善 |
| 推薦システム |
商品 |
同時購入 |
関連商品の発見 |
| 交通最適化 |
駅・交差点 |
路線・道路 |
最短経路の計算 |
| 知識グラフ |
概念・エンティティ |
関係性 |
知識の構造化 |
💡 ネットワークの3つの種類
| 種類 |
特徴 |
例 |
| 無向グラフ |
エッジに方向性がない(双方向) |
友達関係、共著関係 |
| 有向グラフ |
エッジに方向性がある(一方向) |
フォロー関係、リンク |
| 重み付きグラフ |
エッジに強さや距離がある |
距離、通信量、親密度 |
📦 2. NetworkXの基本
NetworkXとは
NetworkXは、Pythonでネットワーク(グラフ)を作成・操作・分析するためのライブラリです。ノードとエッジの追加、レイアウト計算、中心性分析など、ネットワーク分析に必要な機能が揃っています。
📝 ステップ1: ライブラリのインストールと読み込み
まずはNetworkXをインストールして読み込みます。
# Google Colabではインストール済みですが、念のため
!pip install networkx
import networkx as nx
import matplotlib.pyplot as plt
【コードの意味】
!pip install networkx
├── pip: Pythonのパッケージ管理ツール
├── install networkx: NetworkXをインストール
└── Google Colabでは通常インストール済み
import networkx as nx
├── networkx: ネットワーク分析ライブラリ
└── nx という短い名前で使えるようにする
import matplotlib.pyplot as plt
├── グラフの描画に使用
└── NetworkXの描画機能はMatplotlibに依存
📝 ステップ2: 空のグラフを作成
まず空のグラフ(ネットワーク)を作成し、そこにノードとエッジを追加していきます。
# 空のグラフ(無向グラフ)を作成
G = nx.Graph()
【グラフオブジェクトの種類】
nx.Graph()
├── 無向グラフを作成
└── エッジに方向性がない(A-B = B-A)
nx.DiGraph()
├── 有向グラフ(Directed Graph)を作成
└── エッジに方向性がある(A→B ≠ B→A)
nx.MultiGraph()
├── 多重辺グラフを作成
└── 同じノード間に複数のエッジを持てる
【変数名について】
・Gはグラフ(Graph)の頭文字
・慣習的にグラフはGと書くことが多い
📝 ステップ3: ノードを追加
グラフにノード(点)を追加します。
# ノードを1つずつ追加
G.add_node(‘A’)
G.add_node(‘B’)
G.add_node(‘C’)
# 複数のノードをまとめて追加
G.add_nodes_from([‘D’, ‘E’, ‘F’])
【ノード追加メソッド】
G.add_node(‘A’)
├── 1つのノードを追加
├── ノード名は文字列、数値、タプルなど何でもOK
└── 同じ名前のノードを追加しても1つしか存在しない
G.add_nodes_from([‘D’, ‘E’, ‘F’])
├── リストで複数のノードをまとめて追加
└── 効率的に大量のノードを追加できる
【ノード名の例】
・文字列: ‘A’, ‘太郎’, ‘Tokyo’
・数値: 1, 2, 3
・タプル: (1, 2), (‘user’, 123)
📝 ステップ4: エッジを追加
グラフにエッジ(線)を追加します。エッジは2つのノードをつなぎます。
# エッジを1つずつ追加
G.add_edge(‘A’, ‘B’) # AとBをつなぐ
G.add_edge(‘B’, ‘C’) # BとCをつなぐ
G.add_edge(‘C’, ‘A’) # CとAをつなぐ
# 複数のエッジをまとめて追加
G.add_edges_from([(‘D’, ‘E’), (‘E’, ‘F’), (‘F’, ‘D’)])
【エッジ追加メソッド】
G.add_edge(‘A’, ‘B’)
├── AとBの間にエッジを追加
├── 存在しないノードを指定すると自動的にノードも追加される
└── 無向グラフでは A-B と B-A は同じエッジ
G.add_edges_from([(‘D’, ‘E’), (‘E’, ‘F’), (‘F’, ‘D’)])
├── タプルのリストで複数のエッジをまとめて追加
├── 各タプルは (ノード1, ノード2) の形式
└── 効率的に大量のエッジを追加できる
【ポイント】
・エッジを追加すると自動的にノードも追加される
・すでに存在するエッジを追加しても重複しない
📝 ステップ5: グラフの情報を確認
作成したグラフの情報を確認します。
# ノード数を確認
print(f”ノード数: {G.number_of_nodes()}”)
# エッジ数を確認
print(f”エッジ数: {G.number_of_edges()}”)
# ノード一覧を確認
print(f”ノード一覧: {list(G.nodes())}”)
# エッジ一覧を確認
print(f”エッジ一覧: {list(G.edges())}”)
ノード数: 6
エッジ数: 6
ノード一覧: [‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’]
エッジ一覧: [(‘A’, ‘B’), (‘A’, ‘C’), (‘B’, ‘C’), (‘D’, ‘E’), (‘D’, ‘F’), (‘E’, ‘F’)]
【情報取得メソッド】
G.number_of_nodes()
└── グラフ内のノード数を返す
G.number_of_edges()
└── グラフ内のエッジ数を返す
G.nodes()
├── ノードのイテレータを返す
└── list()で囲むとリストに変換
G.edges()
├── エッジのイテレータを返す
└── 各エッジは (ノード1, ノード2) のタプル
【その他の便利なメソッド】
G.degree(‘A’) # ノードAの次数(接続数)
G.neighbors(‘A’) # ノードAに隣接するノード
G.has_node(‘A’) # ノードAが存在するか
G.has_edge(‘A’,’B’) # エッジA-Bが存在するか
基本的なネットワーク図を描画
作成したグラフを可視化します。nx.draw()関数で簡単に描画できます。
import networkx as nx
import matplotlib.pyplot as plt
# グラフ作成
G = nx.Graph()
G.add_edges_from([
(‘A’, ‘B’), (‘A’, ‘C’), (‘A’, ‘D’),
(‘B’, ‘C’), (‘B’, ‘E’),
(‘C’, ‘F’), (‘D’, ‘E’), (‘E’, ‘F’)
])
# 描画設定
plt.figure(figsize=(10, 8))
# ネットワーク図を描画
nx.draw(
G,
with_labels=True, # ノードにラベル表示
node_color=’lightblue’, # ノードの色
node_size=1500, # ノードのサイズ
font_size=16, # フォントサイズ
font_weight=’bold’, # フォントの太さ
edge_color=’gray’, # エッジの色
width=2 # エッジの太さ
)
plt.title(‘基本的なネットワーク図’, fontsize=18, fontweight=’bold’)
plt.axis(‘off’) # 軸を非表示
plt.tight_layout()
plt.show()
【nx.draw()のパラメータ詳細】
nx.draw(G, …)
├── G: 描画するグラフオブジェクト
└── 以下はオプションパラメータ
with_labels=True
├── ノードにラベル(名前)を表示する
└── Falseにすると点だけ表示
node_color=’lightblue’
├── ノードの塗りつぶし色
├── 色名、カラーコード、リストで指定可能
└── リストを渡すと各ノードを異なる色にできる
node_size=1500
├── ノードの大きさ(ピクセル)
├── デフォルトは300程度
└── リストを渡すと各ノードを異なるサイズにできる
font_size=16
└── ラベルのフォントサイズ
edge_color=’gray’
└── エッジの色
width=2
└── エッジの太さ
plt.axis(‘off’)
└── X軸・Y軸を非表示にする(ネットワーク図では通常非表示)
🎨 3. レイアウトアルゴリズム
レイアウトとは
ネットワーク図のノードをどこに配置するかを決めるのがレイアウトアルゴリズムです。同じネットワークでもレイアウトによって見え方が大きく変わります。
NetworkXには複数のレイアウトアルゴリズムが用意されており、目的に応じて使い分けます。
🎨 主要なレイアウトアルゴリズム
| レイアウト |
関数 |
特徴 |
適した用途 |
| Spring |
spring_layout() |
バネモデルで自然な配置 |
一般的なネットワーク |
| Circular |
circular_layout() |
ノードを円形に配置 |
対称性の強調 |
| Random |
random_layout() |
ランダムに配置 |
初期確認用 |
| Shell |
shell_layout() |
同心円状に配置 |
グループ分けがある場合 |
| Kamada-Kawai |
kamada_kawai_layout() |
距離を考慮した配置 |
距離を重視する場合 |
# レイアウトの使い方
pos = nx.spring_layout(G) # ノードの位置を計算
# 計算した位置を使って描画
nx.draw(G, pos=pos, …)
【レイアウトの仕組み】
pos = nx.spring_layout(G)
├── レイアウト関数はノードの座標を計算
├── 戻り値は辞書形式: {‘A’: (x, y), ‘B’: (x, y), …}
└── この座標をnx.draw()のpos引数に渡す
nx.draw(G, pos=pos, …)
├── pos: ノードの配置位置を指定
└── 同じposを使えば再現性のある描画ができる
【Spring Layoutの仕組み】
・ノードを「質点」、エッジを「バネ」と見なす
・バネの力で引っ張り合い、反発力で離れる
・この物理シミュレーションで自然な配置になる
レイアウトの比較
※ コードが長い場合は横スクロールできます
import networkx as nx
import matplotlib.pyplot as plt
# サンプルグラフ(Zachary’s Karate Club – 有名なサンプルデータ)
G = nx.karate_club_graph()
# 複数のレイアウトを比較
layouts = {
‘Spring Layout’: nx.spring_layout(G, seed=42), # バネモデル
‘Circular Layout’: nx.circular_layout(G), # 円形配置
‘Random Layout’: nx.random_layout(G, seed=42), # ランダム配置
‘Shell Layout’: nx.shell_layout(G) # シェル配置
}
# 2×2のサブプロット
fig, axes = plt.subplots(2, 2, figsize=(14, 12))
axes = axes.flatten()
for i, (name, pos) in enumerate(layouts.items()):
ax = axes[i]
nx.draw(
G, pos,
node_color=’lightcoral’,
node_size=300,
with_labels=False,
edge_color=’gray’,
width=0.5,
ax=ax
)
ax.set_title(name, fontsize=14, fontweight=’bold’)
ax.axis(‘off’)
plt.suptitle(‘レイアウトアルゴリズムの比較’, fontsize=18, fontweight=’bold’)
plt.tight_layout()
plt.show()
【コードの解説】
nx.karate_club_graph()
├── NetworkXに付属の有名なサンプルデータ
├── 空手クラブのメンバー間の友人関係
└── 34ノード、78エッジ
seed=42
├── 乱数のシード値を固定
└── 毎回同じレイアウトを再現できる
ax=ax
├── 描画先のサブプロットを指定
└── 複数のグラフを並べて表示するときに使用
💡 レイアウトの調整パラメータ
Spring Layoutは調整パラメータで見やすさを改善できます。
pos = nx.spring_layout(
G,
k=2, # ノード間の最適距離(大きいほど離れる)
iterations=50, # 計算の繰り返し回数(多いほど最適化)
seed=42 # 乱数シード(再現性のため)
)
【spring_layoutのパラメータ】
k=2
├── ノード間の最適距離を調整
├── デフォルトは 1/√n(nはノード数)
├── 大きくするとノードが離れる
└── ノードが重なるときは大きくする
iterations=50
├── 物理シミュレーションの繰り返し回数
├── デフォルトは50
├── 多いほど最適化されるが時間がかかる
└── レイアウトが安定しないときは増やす
seed=42
├── 乱数シードを固定
└── 同じレイアウトを再現したいときに使用
🎯 4. ネットワーク図のカスタマイズ
ノードのサイズと色を変える
ノードのサイズや色をデータに応じて変えると、情報量が増して読み取りやすくなります。例えば、「接続数が多いノードを大きく表示する」といった表現ができます。
import networkx as nx
import matplotlib.pyplot as plt
# ソーシャルネットワークの例
G = nx.Graph()
# 友人関係を追加
connections = [
(‘太郎’, ‘花子’), (‘太郎’, ‘次郎’), (‘太郎’, ‘美咲’),
(‘花子’, ‘次郎’), (‘花子’, ‘健太’),
(‘次郎’, ‘美咲’), (‘次郎’, ‘健太’),
(‘美咲’, ‘健太’), (‘美咲’, ‘愛’),
(‘健太’, ‘愛’), (‘健太’, ‘大輔’),
(‘愛’, ‘大輔’)
]
G.add_edges_from(connections)
# 各ノードの接続数(次数)を計算
degree_dict = dict(G.degree())
print(“各ノードの接続数:”, degree_dict)
# ノードの色とサイズを次数に応じて変更
node_colors = [degree_dict[node] for node in G.nodes()]
node_sizes = [degree_dict[node] * 500 for node in G.nodes()]
【コードの解説】
G.degree()
├── 各ノードの次数(接続しているエッジの数)を取得
├── [(‘太郎’, 3), (‘花子’, 3), …] のような形式
└── dict()で辞書に変換: {‘太郎’: 3, ‘花子’: 3, …}
node_colors = [degree_dict[node] for node in G.nodes()]
├── ノードごとの次数をリスト化
├── この数値がカラーマップに渡される
└── 数値が大きい → 色が濃い(赤に近い)
node_sizes = [degree_dict[node] * 500 for node in G.nodes()]
├── 次数 × 500 でノードサイズを計算
├── 接続数が多いほど大きく表示
└── 500は調整用の係数(適宜変更)
# 可視化
plt.figure(figsize=(12, 10))
pos = nx.spring_layout(G, k=2, iterations=50)
# エッジを描画(薄めに)
nx.draw_networkx_edges(G, pos, alpha=0.3, width=2, edge_color=’gray’)
# ノードを描画(色とサイズを変更)
nx.draw_networkx_nodes(
G, pos,
node_color=node_colors,
node_size=node_sizes,
cmap=’YlOrRd’, # 黄→オレンジ→赤のカラーマップ
alpha=0.9
)
# ラベルを描画
nx.draw_networkx_labels(G, pos, font_size=12, font_weight=’bold’)
plt.title(‘ソーシャルネットワーク\n(ノードサイズ・色 = 友達の数)’, fontsize=16, fontweight=’bold’)
plt.axis(‘off’)
plt.tight_layout()
plt.show()
【描画関数の使い分け】
nx.draw()
└── ノード、エッジ、ラベルをまとめて描画
より細かく制御したい場合は以下を個別に呼び出す:
nx.draw_networkx_edges(G, pos, …)
├── エッジだけを描画
├── alpha: 透明度(0〜1)
└── 先に描画して背景に配置
nx.draw_networkx_nodes(G, pos, …)
├── ノードだけを描画
├── cmap: カラーマップ(色の配色)
└── node_colorに数値リストを渡すと自動で色分け
nx.draw_networkx_labels(G, pos, …)
├── ラベルだけを描画
└── 最後に描画して前面に配置
【この順序の理由】
1. エッジ(背景)
2. ノード(中間)
3. ラベル(前面)
→ 見やすい重なり順になる
🔀 5. 有向グラフと重み付きグラフ
有向グラフ(方向性のあるグラフ)
SNSのフォロー関係のように、「AがBをフォローしている」けど「BはAをフォローしていない」という一方向の関係を表現するには有向グラフを使います。
# 有向グラフを作成
G = nx.DiGraph() # DiGraph = Directed Graph
# フォロー関係(一方向)
follows = [
(‘太郎’, ‘花子’), # 太郎が花子をフォロー
(‘太郎’, ‘次郎’), # 太郎が次郎をフォロー
(‘花子’, ‘太郎’), # 花子が太郎をフォロー(相互フォロー)
(‘花子’, ‘美咲’),
(‘次郎’, ‘花子’),
(‘美咲’, ‘太郎’)
]
G.add_edges_from(follows)
【有向グラフと無向グラフの違い】
無向グラフ: nx.Graph()
├── A-B と B-A は同じエッジ
├── 双方向の関係
└── 例: 友達関係、共著関係
有向グラフ: nx.DiGraph()
├── A→B と B→A は別のエッジ
├── 一方向の関係
└── 例: フォロー関係、リンク、引用
【相互フォローの表現】
・(‘太郎’, ‘花子’) と (‘花子’, ‘太郎’) の両方を追加
・矢印が双方向に向く
# 有向グラフの可視化
plt.figure(figsize=(10, 8))
pos = nx.spring_layout(G, k=2)
nx.draw_networkx_nodes(G, pos, node_color=’lightblue’, node_size=2000)
nx.draw_networkx_labels(G, pos, font_size=12, font_weight=’bold’)
# 矢印付きエッジを描画
nx.draw_networkx_edges(
G, pos,
edge_color=’gray’,
width=2,
arrows=True, # 矢印を表示
arrowsize=20, # 矢印のサイズ
arrowstyle=’->’, # 矢印のスタイル
connectionstyle=’arc3,rad=0.1′ # エッジを少し曲げる
)
plt.title(‘フォロー関係(有向グラフ)’, fontsize=16, fontweight=’bold’)
plt.axis(‘off’)
plt.tight_layout()
plt.show()
【矢印付きエッジのパラメータ】
arrows=True
└── エッジに矢印を表示
arrowsize=20
└── 矢印の大きさ(デフォルトは10程度)
arrowstyle=’->’
├── 矢印のスタイル
├── ‘->’: 標準の矢印
├── ‘-|>’: 三角形の矢印
└── ‘fancy’: 装飾的な矢印
connectionstyle=’arc3,rad=0.1′
├── エッジの曲がり具合
├── rad=0: 直線
├── rad=0.1: 少し曲がる
└── 相互エッジが重ならないようにするため
重み付きグラフ(エッジに値があるグラフ)
都市間の距離や、通信量のように、エッジに重み(値)を持たせたグラフを重み付きグラフと呼びます。
# 重み付きグラフ(都市間の距離)
G = nx.Graph()
# エッジに重み(距離)を追加
edges_with_weights = [
(‘東京’, ‘名古屋’, 350),
(‘東京’, ‘仙台’, 350),
(‘東京’, ‘大阪’, 550),
(‘名古屋’, ‘大阪’, 190),
(‘大阪’, ‘広島’, 330),
(‘大阪’, ‘福岡’, 550),
(‘仙台’, ‘札幌’, 800)
]
for city1, city2, distance in edges_with_weights:
G.add_edge(city1, city2, weight=distance)
【重み付きエッジの追加】
G.add_edge(city1, city2, weight=distance)
├── weight: エッジの属性名(任意の名前でOK)
├── distance: 属性の値
└── 複数の属性も追加可能: weight=350, color=’red’
【重みの取得】
G[city1][city2][‘weight’]
└── エッジの重みを取得
【他の属性の例】
・weight: 重み、距離、コスト
・capacity: 容量(フロー問題)
・label: ラベル(表示用)
# 重み付きグラフの可視化
plt.figure(figsize=(12, 10))
pos = nx.spring_layout(G, k=3)
# ノード
nx.draw_networkx_nodes(G, pos, node_color=’lightgreen’, node_size=2500)
nx.draw_networkx_labels(G, pos, font_size=14, font_weight=’bold’)
# エッジ(太さを距離に応じて変更)
edges = G.edges()
weights = [G[u][v][‘weight’] for u, v in edges]
max_weight = max(weights)
# 距離が短いほど太い線(関係が強い)
edge_widths = [(max_weight – w) / 100 + 1 for w in weights]
nx.draw_networkx_edges(G, pos, width=edge_widths, alpha=0.6, edge_color=’gray’)
# エッジのラベル(距離を表示)
edge_labels = nx.get_edge_attributes(G, ‘weight’)
edge_labels = {k: f'{v}km’ for k, v in edge_labels.items()}
nx.draw_networkx_edge_labels(G, pos, edge_labels, font_size=10)
plt.title(‘都市間の距離ネットワーク’, fontsize=16, fontweight=’bold’)
plt.axis(‘off’)
plt.tight_layout()
plt.show()
【重み付きエッジの可視化】
weights = [G[u][v][‘weight’] for u, v in edges]
├── 各エッジの重みをリスト化
└── 線の太さや色を決めるために使用
edge_widths = [(max_weight – w) / 100 + 1 for w in weights]
├── 重み(距離)が小さいほど太い線にする
├── max_weight – w: 逆転(近いほど大きい値)
├── / 100: スケール調整
└── + 1: 最小の太さを確保
nx.get_edge_attributes(G, ‘weight’)
├── 全エッジの’weight’属性を取得
└── 辞書形式: {(‘東京’, ‘名古屋’): 350, …}
nx.draw_networkx_edge_labels(G, pos, edge_labels, …)
├── エッジにラベル(テキスト)を表示
└── 距離などの情報を可視化
📊 6. 中心性分析(重要なノードを見つける)
中心性とは
ネットワーク内でどのノードが重要かを数値化するのが中心性(Centrality)です。様々な指標があり、「重要さ」の定義によって使い分けます。
📊 主要な中心性指標
| 指標 |
意味 |
高いノードの特徴 |
関数 |
| 次数中心性 |
接続数の多さ |
友達が多い人 |
degree_centrality() |
| 媒介中心性 |
最短経路を通る頻度 |
橋渡し役、情報のハブ |
betweenness_centrality() |
| 近接中心性 |
他のノードへの近さ |
全体に近い位置にいる |
closeness_centrality() |
| 固有ベクトル中心性 |
重要なノードとのつながり |
影響力のある人の知り合い |
eigenvector_centrality() |
# 中心性の計算
degree_cent = nx.degree_centrality(G) # 次数中心性
betweenness_cent = nx.betweenness_centrality(G) # 媒介中心性
# 結果を表示
print(“次数中心性(友達が多い人):”)
for node, score in sorted(degree_cent.items(), key=lambda x: x[1], reverse=True)[:3]:
print(f” {node}: {score:.3f}”)
print(“\n媒介中心性(橋渡し役):”)
for node, score in sorted(betweenness_cent.items(), key=lambda x: x[1], reverse=True)[:3]:
print(f” {node}: {score:.3f}”)
【中心性の使い分け】
次数中心性(degree)
├── 単純に接続数をカウント
├── 使う場面: SNSのフォロワー数、論文の引用数
└── 「直接つながっている数」で重要度を測る
媒介中心性(betweenness)
├── 最短経路をどれだけ通過するか
├── 使う場面: 情報伝達の要、組織内のキーパーソン
└── 「橋渡し役」としての重要度を測る
近接中心性(closeness)
├── 他の全ノードへの平均距離の逆数
├── 使う場面: 情報が素早く届く位置にいるか
└── 「全体への近さ」で重要度を測る
固有ベクトル中心性(eigenvector)
├── 重要なノードとつながっているか
├── 使う場面: GoogleのPageRank、影響力分析
└── 「重要な人の知り合い」としての重要度を測る
💼 7. 実務での活用例
例:組織内コミュニケーション分析
メールのやり取りをネットワーク化すると、誰がコミュニケーションのハブになっているか、部門間の連携は十分かといった分析ができます。
※ コードが長い場合は横スクロールできます
import networkx as nx
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
# 組織内のメールのやり取り
G = nx.DiGraph()
# 部署情報
departments = {
‘山田’: ‘営業’, ‘佐藤’: ‘営業’, ‘鈴木’: ‘営業’,
‘田中’: ‘開発’, ‘伊藤’: ‘開発’, ‘渡辺’: ‘開発’,
‘高橋’: ‘管理’, ‘中村’: ‘管理’
}
# コミュニケーション(送信者 → 受信者、頻度)
communications = [
(‘山田’, ‘佐藤’, 50), (‘山田’, ‘鈴木’, 30), (‘山田’, ‘田中’, 20),
(‘佐藤’, ‘山田’, 45), (‘佐藤’, ‘高橋’, 25),
(‘鈴木’, ‘山田’, 35), (‘鈴木’, ‘伊藤’, 15),
(‘田中’, ‘伊藤’, 60), (‘田中’, ‘渡辺’, 40),
(‘伊藤’, ‘田中’, 55), (‘伊藤’, ‘中村’, 10),
(‘渡辺’, ‘田中’, 35),
(‘高橋’, ‘中村’, 30), (‘高橋’, ‘山田’, 20),
(‘中村’, ‘高橋’, 28)
]
for sender, receiver, frequency in communications:
G.add_edge(sender, receiver, weight=frequency)
# 部署ごとに色を設定
dept_colors = {‘営業’: ‘#E74C3C’, ‘開発’: ‘#3498DB’, ‘管理’: ‘#2ECC71’}
node_colors = [dept_colors[departments[node]] for node in G.nodes()]
# 可視化
plt.figure(figsize=(14, 10))
pos = nx.spring_layout(G, k=3, iterations=50)
# エッジ(太さを頻度に応じて変更)
edges = G.edges()
weights = [G[u][v][‘weight’] for u, v in edges]
max_weight = max(weights)
edge_widths = [w / max_weight * 5 for w in weights]
nx.draw_networkx_edges(
G, pos, width=edge_widths, alpha=0.4,
arrows=True, arrowsize=15, edge_color=’gray’,
connectionstyle=’arc3,rad=0.1′
)
# ノード
nx.draw_networkx_nodes(G, pos, node_color=node_colors, node_size=2000, alpha=0.9)
# ラベル
nx.draw_networkx_labels(G, pos, font_size=11, font_weight=’bold’)
# 凡例
legend_elements = [
Patch(facecolor=’#E74C3C’, label=’営業部’),
Patch(facecolor=’#3498DB’, label=’開発部’),
Patch(facecolor=’#2ECC71′, label=’管理部’)
]
plt.legend(handles=legend_elements, loc=’upper right’, fontsize=12)
plt.title(‘組織内コミュニケーション分析\n(線の太さ=メール頻度)’, fontsize=16, fontweight=’bold’)
plt.axis(‘off’)
plt.tight_layout()
plt.show()
# 中心人物を特定
betweenness = nx.betweenness_centrality(G)
print(“\n【分析結果】中心人物(媒介中心性):”)
for person, score in sorted(betweenness.items(), key=lambda x: x[1], reverse=True)[:3]:
print(f” {person}({departments[person]}): {score:.3f}”)
【このコードでわかること】
1. 部門内のコミュニケーション
・同じ色のノード間のエッジが多いか確認
・部門内で孤立している人はいないか
2. 部門間の連携
・異なる色のノード間にエッジがあるか
・部門間の橋渡し役は誰か
3. 情報のボトルネック
・媒介中心性が高い人 = 情報の要
・その人が抜けると情報が滞る可能性
【凡例の作り方】
from matplotlib.patches import Patch
├── Patchオブジェクトで色見本を作成
└── plt.legend()で凡例として表示
📝 STEP 27 のまとめ
✅ このステップで学んだこと
| トピック |
重要ポイント |
| ネットワーク図の基礎 |
ノード(点)とエッジ(線)で関係性を表現 |
| NetworkXの基本 |
nx.Graph()でグラフ作成、add_node/add_edge |
| レイアウト |
spring_layout(バネモデル)が最も一般的 |
| グラフの種類 |
無向/有向/重み付きを目的に応じて選択 |
| カスタマイズ |
ノードのサイズ・色でデータを表現 |
| 中心性分析 |
次数/媒介/近接/固有ベクトル中心性 |
💡 最重要ポイント
ネットワーク図は、複雑な関係性を一目で理解できる強力なツールです。
✅ ノードのサイズや色で重要度を表現
✅ エッジの太さで関係の強さを表現
✅ 中心性分析でキーパーソンを発見
✅ レイアウトは目的に応じて選択
ただし、ノードが50を超えると見づらくなるため、フィルタリングやグループ化を検討しましょう。次のステップでは、ダッシュボードデザインの原則を学びます!
📝 実践演習
演習 1
基礎
5つのノード(A, B, C, D, E)と6つのエッジを持つ簡単なネットワーク図を作成してください。
import networkx as nx
import matplotlib.pyplot as plt
# グラフ作成
G = nx.Graph()
G.add_edges_from([
(‘A’, ‘B’), (‘B’, ‘C’), (‘C’, ‘D’),
(‘D’, ‘E’), (‘E’, ‘A’), (‘A’, ‘C’)
])
# 可視化
plt.figure(figsize=(8, 6))
nx.draw(
G,
with_labels=True,
node_color=’lightblue’,
node_size=1500,
font_size=16,
font_weight=’bold’
)
plt.title(‘シンプルなネットワーク図’)
plt.axis(‘off’)
plt.show()
ポイント:add_edges_from()でエッジを追加すると、ノードも自動的に追加されます。
演習 2
応用
有向グラフを作成し、矢印付きで表示してください(フォロー関係をイメージ)。
import networkx as nx
import matplotlib.pyplot as plt
# 有向グラフ作成
G = nx.DiGraph()
G.add_edges_from([
(‘太郎’, ‘花子’), (‘花子’, ‘太郎’), # 相互フォロー
(‘太郎’, ‘次郎’), (‘次郎’, ‘美咲’),
(‘美咲’, ‘花子’)
])
# 可視化
plt.figure(figsize=(10, 8))
pos = nx.spring_layout(G, k=2)
nx.draw_networkx_nodes(G, pos, node_color=’lightgreen’, node_size=2000)
nx.draw_networkx_labels(G, pos, font_size=12, font_weight=’bold’)
nx.draw_networkx_edges(
G, pos,
arrows=True,
arrowsize=20,
arrowstyle=’->’,
edge_color=’gray’,
width=2,
connectionstyle=’arc3,rad=0.1′
)
plt.title(‘フォロー関係(有向グラフ)’)
plt.axis(‘off’)
plt.show()
ポイント:nx.DiGraph()で有向グラフを作成し、arrows=Trueで矢印を表示します。connectionstyle=’arc3,rad=0.1’で相互エッジが重ならないよう曲げています。
演習 3
発展
重み付きグラフを作成し、エッジの太さを重みに応じて変化させてください。さらにエッジにラベル(重みの値)を表示してください。
import networkx as nx
import matplotlib.pyplot as plt
# 重み付きグラフ作成
G = nx.Graph()
edges = [
(‘A’, ‘B’, 10), (‘B’, ‘C’, 5), (‘C’, ‘D’, 15),
(‘D’, ‘A’, 8), (‘A’, ‘C’, 12)
]
for u, v, w in edges:
G.add_edge(u, v, weight=w)
# 可視化
plt.figure(figsize=(10, 8))
pos = nx.spring_layout(G, k=2)
# エッジの太さを計算
weights = [G[u][v][‘weight’] for u, v in G.edges()]
max_w = max(weights)
widths = [w / max_w * 10 for w in weights]
# 描画
nx.draw_networkx_nodes(G, pos, node_color=’lightcoral’, node_size=2000)
nx.draw_networkx_labels(G, pos, font_size=14, font_weight=’bold’)
nx.draw_networkx_edges(G, pos, width=widths, alpha=0.6, edge_color=’gray’)
# エッジラベル
edge_labels = nx.get_edge_attributes(G, ‘weight’)
nx.draw_networkx_edge_labels(G, pos, edge_labels, font_size=12)
plt.title(‘重み付きグラフ(線の太さ=重み)’)
plt.axis(‘off’)
plt.show()
ポイント:G.add_edge(u, v, weight=w)で重みを追加。nx.get_edge_attributes()で重みを取得し、nx.draw_networkx_edge_labels()でラベル表示します。
❓ よくある質問
Q1: ノードが多すぎて見づらいです。どうすればいいですか?
以下の方法を試してください:
①フィルタリング:重要なノード(次数が高いなど)だけ表示
②グループ化:コミュニティ検出でグループに分割
③インタラクティブ化:Plotlyでズーム機能を追加
④階層化:重要度に応じて段階的に表示
一般的に、50ノードを超えると見づらくなります。
Q2: レイアウトがきれいに配置されません。どうすればいいですか?
spring_layoutのパラメータを調整しましょう:
pos = nx.spring_layout(G, k=2, iterations=100, seed=42)
k:ノード間の距離(大きいほど離れる)
iterations:計算回数(多いほど最適化)
seed:乱数シード(毎回同じレイアウトにする)
また、他のレイアウト(circular、kamada_kawai)も試してみてください。
Q3: ネットワークの中心人物を見つけるにはどうすればいいですか?
中心性指標を計算しましょう:
①次数中心性:nx.degree_centrality(G) – つながりの数
②媒介中心性:nx.betweenness_centrality(G) – 橋渡し役
③近接中心性:nx.closeness_centrality(G) – 全体への近さ
④固有ベクトル中心性:nx.eigenvector_centrality(G) – 重要な人とのつながり
目的に応じて適切な指標を選んでください。
Q4: ネットワーク内のグループ(コミュニティ)を見つけるには?
コミュニティ検出アルゴリズムを使います:
from networkx.algorithms.community import greedy_modularity_communities
communities = greedy_modularity_communities(G)
これにより、密につながったノードのグループを自動で検出できます。検出されたコミュニティごとに色分けすると、ネットワークの構造が見えてきます。
Q5: ネットワーク図を画像として保存するには?
plt.savefig()を使います:
plt.savefig('network.png', dpi=300, bbox_inches='tight')
dpi=300:解像度(印刷用は300以上推奨)
bbox_inches=’tight’:余白を最小限に
plt.show()の前に記述してください。PDF形式にも対応しています。
artnasekai
#artnasekai #学習メモ