PythonでWordCloudを作成してみました


PyLadies Advent Calendar 2018 の3日目の記事です。
Pythonで Word Cloud を使ってみたことを書きました。


*Word Cloud とは

文章データを可視化する手法のひとつで、文章のなかで出現頻度が高い文字を大きく、出現頻度が低い文字を小さくして分布をわかりやすくした図のことです。


*環境

  • MacOS
  • Python 2.7.14
  • matplotlib 2.2.3
  • mecab-python 0.996
  • requests 2.20.1
  • wordcloud 1.5.0
  • beautifulsoup4 4.6.3
  • image 1.5.27


*各種ライブラリのインストール

任意の作業用のフォルダに移動し、仮想環境を作成します。
$ virtualenv env
$ source env/bin/activate

Word Cloud のライブラリをインストールします。
GitHubにパッケージが上がっているので、クローンしてからインストールします。
$ git clone https://github.com/amueller/word_cloud
$ cd word_cloud/
$ python setup.py install

各種ライブラリをインストールします。
$ brew install mecab-ipadic
$ pip install mecab-python

$ pip install beautifulsoup4
$ pip install requests

$ pip install -U matplotlib
$ pip install image
$ pip install requests[security]


*テキストデータを準備

今回は PyCon2018の発表資料について書かれている Qiita の記事から文章データを取得させていただきました。
取得は、HTML や XML のパーサである BeautifulSoup を使ってWebスクレイピングをしています。
# -*- coding: utf-8 -*-
from bs4 import BeautifulSoup  
import requests


url = 'https://qiita.com/kobaboy/items/46ff9f19b9ea5638fa8e'
res = requests.get(url)
soup = BeautifulSoup(res.text)
text = soup.body.section.get_text().replace('\n', '').replace('\t', '')


*テキストを単語区切りに編集

文章を単語ごとに区切るために、形態素解析をするための解析エンジンである MeCab を使います。
MeCab.Tagger()のパラメーターに-Owakatiを指定すると分かち書き、-Ochasenを指定すると形態素解析をしてくれます。
今回は形態素解析をして、単語と品詞のセットをリストで取得しています。
# -*- coding: utf-8 -*-
from bs4 import BeautifulSoup  
import requests
import MeCab as mc     <--追加


url = 'https://qiita.com/kobaboy/items/46ff9f19b9ea5638fa8e'
res = requests.get(url)
soup = BeautifulSoup(res.text)
text = soup.body.section.get_text().replace('\n', '').replace('\t', '')

# ------- 追加 -------
st_text = text.encode('utf-8')
tagger = mc.Tagger('-Ochasen')
words = tagger.parse(st_text)

<出力結果>
PyCon PyCon PyCon 名詞-固有名詞-組織  
JP JP JP 名詞-一般  
2018 2018 2018 名詞-数  
ひろがる ヒロガル ひろがる 動詞-自立 五段・ラ行 基本形
Python Python Python 名詞-一般  
の ノ の 助詞-連体化  
資料 シリョウ 資料 名詞-一般
...  


*Word Cloud を作成

WordCloud()にパラメータを指定して作成します。
パラメータの説明は下記に載っています。
stop_words=を指定することで、意味のない単語を除外することができます。
font_path=に日本語のフォントを指定しないと、文字化けをしてしまいます。今回はMacにデフォルトで用意されているフォントを使用しましたが、日本語のフォントであれば他でも大丈夫です。
今回は指定していませんが、WordCloud()の引数にmask=で画像を指定すると、その形で Word Cloud を作成してくれます。

Word Cloud を作成したら、word_cloud.to_file()で指定したフォルダに結果を書き出すことができます。
# -*- coding: utf-8 -*-  
from wordcloud import WordCloud  
from bs4 import BeautifulSoup  
import requests  
import MeCab as mc  
from os import path     <--追加


# 文章データを取得
url = 'https://qiita.com/kobaboy/items/46ff9f19b9ea5638fa8e'
res = requests.get(url)
soup = BeautifulSoup(res.text)
text = soup.body.section.get_text().replace('\n', '').replace('\t', '')

# 形態素解析
st_text = text.encode('utf-8')
tagger = mc.Tagger('-Ochasen')
words = tagger.parse(st_text)

# ------- 追加 -------
stop_words = [u'てる', u'いる', u'なる', u'れる', u'する', u'ある', u'こと', u'これ', u'さん', u'して', \  
              u'くれる', u'やる', u'くださる', u'そう', u'せる', u'した', u'思う', \  
              u'それ', u'ここ', u'ちゃん', u'くん', u'', u'て', u'に', u'を', u'は', u'の', u'が', u'と', u'た', u'し', u'で', \  
              u'ない', u'も', u'な', u'い', u'か', u'ので', u'よう', u'']

# WordCloudを作成
word_cloud = WordCloud(  
    font_path='/System/Library/Fonts/ヒラギノ明朝 ProN.ttc',  
    background_color="white",  
    width=900,  
    height=500,  
    stopwords=set(stop_words)).generate(keywords)

# ファイルに書き出し
word_cloud.to_file(path.join(path.dirname(__file__), 'sample.png'))  

<出力結果>












*図に描画

ファイルに書き出すだけでも十分なのですが、作成したWord Cloud を図に描画してみます。
図の描画は、Pythonでグラフや画像を作成するライブラリであるmatplotlibを使います。今回はOSの標準ビューアで表示させています。
# -*- coding: utf-8 -*-  
import matplotlib        <--追加
  
matplotlib.use('TkAgg')           <--追加
import matplotlib.pyplot as plt   <--追加
from wordcloud import WordCloud  
from bs4 import BeautifulSoup  
import requests  
import MeCab as mc  
from os import path


# 文章データを取得
url = 'https://qiita.com/kobaboy/items/46ff9f19b9ea5638fa8e'
res = requests.get(url)
soup = BeautifulSoup(res.text)
text = soup.body.section.get_text().replace('\n', '').replace('\t', '')

# 形態素解析
st_text = text.encode('utf-8')
tagger = mc.Tagger('-Ochasen')
words = tagger.parse(st_text)

stop_words = [u'てる', u'いる', u'なる', u'れる', u'する', u'ある', u'こと', u'これ', u'さん', u'して', \  
              u'くれる', u'やる', u'くださる', u'そう', u'せる', u'した', u'思う', \  
              u'それ', u'ここ', u'ちゃん', u'くん', u'', u'て', u'に', u'を', u'は', u'の', u'が', u'と', u'た', u'し', u'で', \  
              u'ない', u'も', u'な', u'い', u'か', u'ので', u'よう', u'']

# WordCloudを作成
word_cloud = WordCloud(  
    font_path='/System/Library/Fonts/ヒラギノ明朝 ProN.ttc',  
    background_color="white",  
    width=900,  
    height=500,  
    stopwords=set(stop_words)).generate(keywords)

# ファイルに書き出し
word_cloud.to_file(path.join(path.dirname(__file__), 'sample.png'))  

# ------- 追加 -------
# 図に描画
plt.imshow(word_cloud)  
plt.axis("off")  
plt.figure(figsize=(15, 12))
plt.show()

<出力結果>

















*所感

作成した図に重複した文字があったり、意味のない文字が混じっているのが気になりますが、とりあえず Word Cloud を作成することができました。
正確な結果を表示させるために、もう少し色々試してみようと思います。また、今回試したWebページの文章以外にも、CSVデータやAPIでの取得結果などといった色々なデータでも試してみたいと思います。


*まとめ

コードを少し綺麗にしたものを載せておきます。
# -*- coding: utf-8 -*-  
import matplotlib  
  
matplotlib.use('TkAgg')  
import matplotlib.pyplot as plt  
from wordcloud import WordCloud  
from bs4 import BeautifulSoup  
import requests  
import MeCab as mc  
from os import path  
  
  
def get_analysis_mecab_words(text):  
    st_text = text.encode('utf-8')  
    tagger = mc.Tagger('-Ochasen')  
    words = tagger.parse(st_text)  
  
    outputs = []  
    for w in words.split('\n'):  
        word = w.split('\t')  
        if word[0] == 'EOS':  
            break  
  
  word_type = word[3].split('-')[0]  
        if word_type in ['形容詞', '動詞', '名詞', '副詞']:  
            outputs.append(word[0])  
  
    return outputs  
  
  
def get_keywords(url):  
    res = requests.get(url)  
    soup = BeautifulSoup(res.text)  
    text = soup.body.section.get_text().replace('\n', '').replace('\t', '')  
    outputs = get_analysis_mecab_words(text)  
    return ' '.join(outputs).decode('utf-8')  
  
  
def view_image(word_cloud):  
    word_cloud.to_file(path.join(path.dirname(__file__), 'sample.png'))  
    plt.imshow(word_cloud)  
    plt.axis("off")  
    plt.figure(figsize=(15, 12))  
    plt.show()  
  
if __name__ == '__main__':  
    url = 'https://qiita.com/kobaboy/items/46ff9f19b9ea5638fa8e'  
  keywords = get_keywords(url)  
  
    stop_words = [u'てる', u'いる', u'なる', u'れる', u'する', u'ある', u'こと', u'これ', u'さん', u'して', \  
                  u'くれる', u'やる', u'くださる', u'そう', u'せる', u'した', u'思う', \  
                  u'それ', u'ここ', u'ちゃん', u'くん', u'', u'て', u'に', u'を', u'は', u'の', u'が', u'と', u'た', u'し', u'で', \  
                  u'ない', u'も', u'な', u'い', u'か', u'ので', u'よう', u'']  
  
    word_cloud = WordCloud(  
        font_path='/System/Library/Fonts/ヒラギノ明朝 ProN.ttc',  
        background_color="white",  
        width=900,  
        height=500,  
        stopwords=set(stop_words)).generate(keywords)  
  
    view_image(word_cloud)