NetworkXで共起ネットワークのグラフを描く

今回はテキストマイニングにおける共起ネットワークを表現するためにNetworkXをいじってみます。

やりたいこと
– Word間の結びつきを図示する
– 結びつきの強さをグラフの線の太さで表現する

  • 1: NetworkXの情報集め
  • 2: ネットワーク図を作ってみる
  • 3: 最後に

NetworkXの情報集め

こちらのページが公式のようです。
Latestのdocに載っています。

Tutorialで使い方、Referenceで関数について調べながらやりました。

ネットワーク図を作ってみる

サイトを確認すると以下のような流れのようです。
– 空のグラフを作る
– nodeを足す
– edgeを足す

さっそくトライしてみます。
# networkxをインストール
!pip install networkx
Google Colaboratoryには最初から入っていたのでinstallは不要でした。
# networkxをimport
import networkx as nx
まずは空のグラフを作成します。
# 空のグラフを作成
G = nx.Graph()
グラフにnode(頂点)を加えます。
networkx.Graph.add_nodeで加えることができるようです。
# nodeに"1"を加える
G.add_node(1)
さっそく図示してみます。
Tutrialの「Drawing graphs」を確認するとmatplotlibを使って描けるようです。
drawの引数にグラフを与えれば取り急ぎはOKですね。
# 図示
# matplotをimport
import matplotlib.pyplot as plt

# 図示する
nx.draw(G)
おお、ちゃんとnodeが一つできました。
networkx.Graph.add_nodes_fromだとlist等まとめてできるようです。
# nodeを複数追加する
G.add_nodes_from([2,3])
with_labelsでラベルを付けるかどうか選べます。
# 図示する
nx.draw(G, with_labels=True)
ちゃんと番号も入ってました。

edgeも全く話一緒のようです。つなぐ組み合わせを入れればOK
# edgeを加える
G.add_edges_from([(1,2),(1,3)])

# 図示
nx.draw(G, with_labels=True)
ちゃんと(1,2), (1,3)がつながって(2,3)はつながってないですね。

一度に情報を入れることもできます。
今度は属性情報としてweightも入れてしまいましょう。テキストマイニングで求めたJaccard係数をweightとして線の太さに使えば良さそうです。
グラフに加えるには「networkx.Graph.add_weighted_edges_from」を使います。
# 空のグラフを作成
H = nx.Graph()

# weight付でnodeとエッジも入れる
H.add_weighted_edges_from([(1,2,1),(2,3,0.8),(3,4,1),(5,6,1),(6,7,1),(2,6,0.5)])

# 図示
nx.draw(H, with_labels=True)
いいですね。weightを線の太さに指定してみます。
drawのパラメーターにwidthを入れればいいですが、エッジによって違うのでListを作ってfor文で入れます。線が細かったので一律10倍しました。
# weightによって線の太さを変える
edge_width = [d["weight"] * 10 for (u, v, d) in H.edges(data=True)]

# posを定義
pos = nx.spring_layout(H, k=0.3)  # k = node間反発係数

# 図示
nx.draw(H,pos, with_labels=True, width=edge_width)
いい感じになりました。ちゃんと線の幅でweightの大きさが表現されています。
posはレイアウトのアルゴリズムの指定です。ちゃんと調べてないですが、いい感じに落ち着かせてくれるspring_layoutにしました。

最後に線が多過ぎて邪魔くさいと感じた時のためにedgeの剪定を考えます。
weightが小さい=細いedgeは線を無くしてしまいたいです。

networkx.Graph.remove_edges_fromでedgeの組を指定すればOKです。
# weight 0.6以下のedgeを消す
removeEdges = [] #空のリスト

for (u, v, d) in H.edges(data=True):
  if d["weight"] <= 0.6:
    removeEdges.append([u,v]) #weightが0.6以下ならremoveEdgesに追加

# グラフから削除
H.remove_edges_from(removeEdges)

# 図示
nx.draw(H,pos, with_labels=True, width=edge_width)
できました。ちゃんと指定したweight以下のエッジが消えています。

これでテキストマイニングの共起ネットワークも表現できそうです。

最後に

NetworkXは他にも最短距離を出す等の分析でも使えるようです。
今回は今必要な部分だけやってみました。