前回書いた記事でWindowsにigraphをインストールすることに成功しました。
www.pytry3g.com
今回は自分で用意したデータ(テキスト)を使って共起関係のグラフ(語と語のつながり)を表示させるところまでやってみます。
環境
実行環境です。
WindowsにMeCabをインストールするには
https://www.pytry3g.com/entry/2018/04/24/143934#Windows
関連リンク
Tutorial
python-igraph manual
方針
今回は自分で用意したデータを使ってグラフを表示させます。そのため、まずデータを用意するところから軽く説明してそれからグラフの作り方について書いていきます。
データの用意
ロシアワールドカップが行われた期間にサッカー日本代表に関するツイートを集めることができたので、今回はそのデータを使ってグラフを生成させてみたいと思います。
www.pytry3g.com
データの中身はこんな感じです。
原口と槙野も先発だと期待してます。
槙野は出ると思うんですが、原口はもしかすると乾のサブかもねー。どちらにしても頑張ってー!
今日日本戦!!!たのしみ!頑張れ!コロンビア!
それ!もう日本出なくていい。経費の無駄
本田スタメン外したのは英断だけど中盤誰が守備すんねんw
このメンツなら原口だな。
コロンビアってサッカーつよいんですか
そうなんか今日日本と試合するんしょ?
グラフの生成
これからグラフを生成しますが、そのためにいくつかの前準備が必要になります。
順を追って説明していきます。
1. データを読み込む
集めたツイートが入ったファイルはpositive.txtという名前のテキストファイルになっています。これを改行区切りでcorpus
というリストに入れます。
import codecs
with codecs.open('positive.txt', 'r', 'utf-8') as f:
corpus = f.read().splitlines()
リストcorpus
に入っているすべてのテキストを形態素解析し名詞の基本形を取り出します。
import MeCab
tagger = MeCab.Tagger("-Ochasen")
def tokenizer(sentence):
tag = tagger.parseToNode(sentence)
tokens = []
while tag:
features = tag.feature.split(',')
pos = features[0]
token = features[-3]
if token == "*":
tag = tag.next
continue
if pos == '名詞':
tokens.append(token)
tag = tag.next
return tokens if tokens else None
tokenslist = []
for sentence in corpus:
tokens = tokenizer(sentence)
assert tokens, "m9(^Д^)プギャー"
tokenslist.append(tokens)
print(corpus[0])
print(tokenslist[0])
tokenslist
はリストになっており、中身も文単位で単語の基本形が入ったリストになっています。
3. 共起リストを作る
pythonに標準で入っているitertoolsのcombinationsメソッドを使って、tokenslist
から共起ペアを作っていきます。
combinations
itertools.combinations(iterable, r)
iterableな要素から長さrの重複なしの部分列(タプルで)返してくれます。
試しにtokenslist
の一つの文を渡してみます。ペアを作るのでr = 2にしています。
from itertools import combinations
list(combinations(tokenslist[0], 2))
"""結果
[('原口', '槙野'),
('原口', '先発'),
('原口', '期待'),
('槙野', '先発'),
('槙野', '期待'),
('先発', '期待')]
"""
共起ペアを作る
リストco_occur
に共起ペアを入れたリストを入れていく。
from itertools import combinations
co_occur = []
for tokens in tokenslist:
if len(tokens) < 2:
continue
co_occur.append(list(combinations(tokens, 2)))
print(co_occur[0])
co_occur
はリストが入ったリストになっているので、これをフラットなリストにする。
co_occur_flatten = []
for pairs in co_occur:
co_occur_flatten.extend(pairs)
print(co_occur_flatten[0])
print(len(co_occur_flatten))
共起ペアをカウントする
共起ペアをカウントしてみます。
from collections import Counter
cnt = Counter(co_occur_flatten)
頻度が高いトップ10を見てみる。
print(*sorted(cnt.items(), key=lambda x: x[1], reverse=True)[:10], sep="\n")
"""Top10
(('日本', 'ん'), 26)
(('決勝', 'トーナメント'), 23)
(('日本', '代表'), 22)
(('コロンビア', '日本'), 21)
(('日本', '笑'), 21)
(('セネガル', 'コロンビア'), 21)
(('日本', '試合'), 20)
(('試合', 'ん'), 20)
(('セネガル', '戦'), 20)
(('日本', '日本'), 18)
"""
4. 共起辞書を作る
10回以上現れる共起ペアをグラフに表示させます。すべての共起ペアを表示させようとするとぐちゃぐちゃになってしまうので。
10回以上出現する共起ペアを辞書にしてみます。
co_occur_dict = {k: cnt[k] for k in cnt.keys() if cnt[k] >=10}
print(len(co_occur_dict))
print(list(co_occur_dict.items())[0])
10回以上出現する共起ペアは全部で73個ありました。
5. 頂点の準備
今回作るグラフは共起関係(語と語のつながり)を表示させます。語と語のつながりを表示させるので頂点は語になります。
vertices
には頂点となる語が入ります。
vertices = []
for pairs in co_occur_dict.keys():
token1, token2 = pairs
if token1 not in vertices:
vertices.append(token1)
if token2 not in vertices:
vertices.append(token2)
print(len(vertices))
頂点(語)は全部で33個になりました。
6. 辺の準備
頂点から辺を生成します。
下のプログラムは共起ペア (['単語1', '単語2']) から単語IDのペア([単語1のID, 単語2のID])に変換しています。
edges = [(vertices.index(pairs[0]), vertices.index(pairs[1])) for pairs in co_occur_dict.keys()]
print(edges[0])
7. グラフを作る
ここでようやくグラフを作ります。
from igraph import Graph
g = Graph(
vertex_attrs={"label": vertices},
edges=edges,
directed=False
)
igraphのGraph()
に頂点のラベル(単語)と辺(単語IDのペア)を渡してグラフを生成しています。
8. グラフの表示
igraphのplot
でグラフを表示します。
from igraph import plot
plot(
g,
vertex_size=25,
bbox=(600, 600),
vertex_color="skyblue"
)
結果
グラフを表示させるとこんな感じになりました。

ロシアワールドカップの期間中に集めたツイートを使ってこの共起グラフを生成してみましたが、このグラフを見てみるとやはり日本代表についてや他の国に関するツイートがあることが分かります。
それからグラフでも大迫はやっぱり半端なかった。
コードをまとめると以下のようになります。
MeCabとigraphがインストールされていれば以下のコードをコピペで実行できるようしています。
import MeCab
import codecs
from collections import Counter
from igraph import Graph, plot
from itertools import combinations
corpus = ["セネガルつええ、ボルト三体くらいいるわ笑笑",
"しょーみコロンビアより強い",
"それなまちがいないわ"]
tagger = MeCab.Tagger("-Ochasen")
def tokenizer(sentence):
tag = tagger.parseToNode(sentence)
tokens = []
while tag:
features = tag.feature.split(',')
pos = features[0]
token = features[-3]
if token == "*":
tag = tag.next
continue
if pos == '名詞':
tokens.append(token)
tag = tag.next
return tokens if tokens else None
tokenslist = []
for sentence in corpus:
tokens = tokenizer(sentence)
assert tokens, "m9(^Д^)プギャー"
tokenslist.append(tokens)
co_occur = []
for tokens in tokenslist:
if len(tokens) < 2:
continue
co_occur.append(list(combinations(tokens, 2)))
co_occur_flatten = []
for pairs in co_occur:
co_occur_flatten.extend(pairs)
cnt = Counter(co_occur_flatten)
co_occur_dict = {k: cnt[k] for k in cnt.keys() if cnt[k] >=10}
vertices = []
for pairs in co_occur_dict.keys():
token1, token2 = pairs
if token1 not in vertices:
vertices.append(token1)
if token2 not in vertices:
vertices.append(token2)
edges = [(vertices.index(pairs[0]), vertices.index(pairs[1])) for pairs in co_occur_dict.keys()]
g = Graph(
vertex_attrs={"label": vertices},
edges=edges,
directed=False
)
plot(
g,
vertex_size=25,
bbox=(600, 600),
vertex_color="skyblue"
)