自然言語処理:MeCab と Python によるワードクラウド作成


最近、研究目的でワードクラウド作成用の簡易的な WEB-API を実装する機会があったため、手順をまとめてみました。

環境構築(Unbutu / MeCab / WordCloud)

AWS の EC2 (Ubuntu 20) 上に以下の手順で環境を構築します。

pip (Python 用パッケージマネージャ)をインストールします。

sudo apt-get update
sudo apt install python3-pip

WordCloud(Python 用ワードクラウド作成ライブラリ)をインストールします。

sudo pip3 install wordcloud

MeCab のインストールします。

sudo apt install mecab
sudo apt install libmecab-dev
sudo apt install mecab-ipadic-utf8

Python用の MeCab ライブラリをインストールします。

sudo pip3 install mecab-python3
sudo pip3 install unidic-lite

日本語フォントをインストールします。

sudo apt install fontconfig
sudo apt install fonts-ipaexfont

ワードクラウド作成用のスクリプトの作成

wc_test.py というファイル名で、以下のようなワードクラウド作成用のスクリプトを作成します。

import MeCab

from wordcloud import WordCloud

FILE_NAME = "sample.txt"

with open(FILE_NAME, "r", encoding="utf-8") as f:
    text = f.read()

stop_words = [
	'あ','い','う','え','お',
	'か','き','く','け','こ',
	'さ','し','す','せ','そ',
	'た','ち','つ','て','と',
	'な','に','ぬ','ね','の',
	'は','ひ','ふ','へ','ほ',
	'ま','み','む','め','も',
	'や','ゆ','よ',
	'ら','り','る','れ','ろ',
	'わ','を','ん',
	'が','ぎ','ぐ','げ','ご',
	'ざ','じ','ず','ぜ','ぞ',
	'だ','ぢ','づ','で','ど',
	'だ','ぢ','づ','で','ど',
	'する', 'いる', 'ある', 'ない', 'おる',
	'もの', 'いう', 'そう', 'なる', '見る',
	''
]

#MeCab を使用して形態素解析
mecab = MeCab.Tagger("-O chasen -d /var/lib/mecab/dic/ipadic-utf8/")
node  = mecab.parseToNode(text)
words = []

#名詞、動詞、動詞である単語のみを抽出
while node:
    if node.feature.split(",")[0] == u"名詞":
        words.append(node.surface)
    elif node.feature.split(",")[0] == u"形容詞":
        words.append(node.feature.split(",")[6])
    elif node.feature.split(",")[0] == u"動詞":
        words.append(node.feature.split(",")[6])
    node = node.next

#単語を空白で結合
text = ' '.join(words);

#ワードクラウドを作成
wordcloud = WordCloud(
	width = 400,  # 幅
	height = 300,  # 高さ
	background_color = 'white', # 背景色
	font_path = '/usr/share/fonts/truetype/fonts-japanese-gothic.ttf', # 日本語フォントを指定
	stopwords = set(stop_words), # 出力から除外する単語
)

wordcloud.generate(text)
wordcloud.to_file("wordcloud.png")

sample.txt というファイル名で、以下のようなサンプル用のテキストを作成します。

吾輩わがはいは猫である。名前はまだ無い。
 どこで生れたかとんと見当けんとうがつかぬ。何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。吾輩はここで始めて人間というものを見た。しかもあとで聞くとそれは書生という人間中で一番獰悪どうあくな種族であったそうだ。この書生というのは時々我々を捕つかまえて煮にて食うという話である。しかしその当時は何という考もなかったから別段恐しいとも思わなかった。ただ彼の掌てのひらに載せられてスーと持ち上げられた時何だかフワフワした感じがあったばかりである。掌の上で少し落ちついて書生の顔を見たのがいわゆる人間というものの見始みはじめであろう。この時妙なものだと思った感じが今でも残っている。第一毛をもって装飾されべきはずの顔がつるつるしてまるで薬缶やかんだ。その後ご猫にもだいぶ逢あったがこんな片輪かたわには一度も出会でくわした事がない。のみならず顔の真中があまりに突起している。そうしてその穴の中から時々ぷうぷうと煙けむりを吹く。どうも咽むせぽくて実に弱った。これが人間の飲む煙草たばこというものである事はようやくこの頃知った。
 この書生の掌の裏うちでしばらくはよい心持に坐っておったが、しばらくすると非常な速力で運転し始めた。書生が動くのか自分だけが動くのか分らないが無暗むやみに眼が廻る。胸が悪くなる。到底とうてい助からないと思っていると、どさりと音がして眼から火が出た。それまでは記憶しているがあとは何の事やらいくら考え出そうとしても分らない。
 ふと気が付いて見ると書生はいない。たくさんおった兄弟が一疋ぴきも見えぬ。肝心かんじんの母親さえ姿を隠してしまった。その上今いままでの所とは違って無暗むやみに明るい。眼を明いていられぬくらいだ。はてな何でも容子ようすがおかしいと、のそのそ這はい出して見ると非常に痛い。吾輩は藁わらの上から急に笹原の中へ棄てられたのである。
 ようやくの思いで笹原を這い出すと向うに大きな池がある。吾輩は池の前に坐ってどうしたらよかろうと考えて見た。別にこれという分別ふんべつも出ない。しばらくして泣いたら書生がまた迎に来てくれるかと考え付いた。ニャー、ニャーと試みにやって見たが誰も来ない。そのうち池の上をさらさらと風が渡って日が暮れかかる。腹が非常に減って来た。泣きたくても声が出ない。仕方がない、何でもよいから食物くいもののある所まであるこうと決心をしてそろりそろりと池を左ひだりに廻り始めた。どうも非常に苦しい。そこを我慢して無理やりに這はって行くとようやくの事で何となく人間臭い所へ出た。ここへ這入はいったら、どうにかなると思って竹垣の崩くずれた穴から、とある邸内にもぐり込んだ。縁は不思議なもので、もしこの竹垣が破れていなかったなら、吾輩はついに路傍ろぼうに餓死がししたかも知れんのである。一樹の蔭とはよく云いったものだ。この垣根の穴は今日こんにちに至るまで吾輩が隣家となりの三毛を訪問する時の通路になっている。さて邸やしきへは忍び込んだもののこれから先どうして善いいか分らない。そのうちに暗くなる、腹は減る、寒さは寒し、雨が降って来るという始末でもう一刻の猶予ゆうよが出来なくなった。仕方がないからとにかく明るくて暖かそうな方へ方へとあるいて行く。今から考えるとその時はすでに家の内に這入っておったのだ。ここで吾輩は彼かの書生以外の人間を再び見るべき機会に遭遇そうぐうしたのである。第一に逢ったのがおさんである。これは前の書生より一層乱暴な方で吾輩を見るや否やいきなり頸筋くびすじをつかんで表へ抛ほうり出した。いやこれは駄目だと思ったから眼をねぶって運を天に任せていた。しかしひもじいのと寒いのにはどうしても我慢が出来ん。吾輩は再びおさんの隙すきを見て台所へ這はい上あがった。すると間もなくまた投げ出された。吾輩は投げ出されては這い上り、這い上っては投げ出され、何でも同じ事を四五遍繰り返したのを記憶している。その時におさんと云う者はつくづくいやになった。この間おさんの三馬さんまを偸ぬすんでこの返報をしてやってから、やっと胸の痞つかえが下りた。吾輩が最後につまみ出されようとしたときに、この家うちの主人が騒々しい何だといいながら出て来た。下女は吾輩をぶら下げて主人の方へ向けてこの宿やどなしの小猫がいくら出しても出しても御台所おだいどころへ上あがって来て困りますという。主人は鼻の下の黒い毛を撚ひねりながら吾輩の顔をしばらく眺ながめておったが、やがてそんなら内へ置いてやれといったまま奥へ這入はいってしまった。主人はあまり口を聞かぬ人と見えた。下女は口惜くやしそうに吾輩を台所へ抛ほうり出した。かくして吾輩はついにこの家うちを自分の住家すみかと極きめる事にしたのである。

実行ようにスクリプトを実行すると、ワードクラウドの画像ファイルが生成されます。

python3 wc_test.py

ワードクラウドは単語の重みが考慮されていない為、一般的な単語や意図しない記号が抽出されることが多くあります。そのため除外する単語リスト( stopwords )をうまく活用してデータのクレンジングを行う必要があります。

テキストからワードクラウドを作成する簡易的な WEB-API の作成

Apache をインストールし、以下のようなコードを作成することで、POSTされたテキストをワードクラウドに変換するAPIの作成も可能です。

Apache をインストールします。

sudo apt install apache2

ディレクトリの所有者を変更します。

sudo chown -R $USER:$USER /var/www/
sudo chown -R $USER:$USER /usr/lib/cgi-bin/
sudo chown -R $USER:$USER /etc/apache2/sites-available/

以下の内容で /etc/apache2/conf-available/cgi-enabled.conf を作成します。

<Directory "/usr/lib/cgi-bin">
    Options +ExecCGI
    AddHandler cgi-script .cgi .py
</Directory>

以下の内容で /usr/lib/cgi-bin/.htaccess を作成します。

AddDefaultCharset utf-8
AddType 'application/json; charset=UTF-8' .json

/usr/lib/cgi-bin/ ディレクトリ上に text2wc.py というファイル名で以下のスクリプトを作成します。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import cgi
import sys
import io
import json
import MeCab

from wordcloud import WordCloud

#print('Content-Type: text/html;charset=utf-8')
print('Content-Type: application/json;charset=utf-8')
print('')

sys.path.append('/home/ubuntu/.local/lib/python3.8/site-packages')

#ポストされたデータを取得
post_data = cgi.FieldStorage()

text = post_data.getvalue('text', 'default_value')
no   = post_data.getvalue('no', '0') #ユニークなID

#安全のため整数値に変換
no = int(no)

#除外する単語のリスト
stop_words = [
	'あ','い','う','え','お',
	'か','き','く','け','こ',
	'さ','し','す','せ','そ',
	'た','ち','つ','て','と',
	'な','に','ぬ','ね','の',
	'は','ひ','ふ','へ','ほ',
	'ま','み','む','め','も',
	'や','ゆ','よ',
	'ら','り','る','れ','ろ',
	'わ','を','ん',
	'が','ぎ','ぐ','げ','ご',
	'ざ','じ','ず','ぜ','ぞ',
	'だ','ぢ','づ','で','ど',
	'だ','ぢ','づ','で','ど',
	'する', 'いる', 'ある', 'ない', 'おる',
	'もの', 'いう', 'そう', 'なる', '見る',
	''
]

#MeCab を使用して形態素解析
mecab = MeCab.Tagger("-O chasen -d /var/lib/mecab/dic/ipadic-utf8/")
node = mecab.parseToNode(text)
words = []

while node:
    if node.feature.split(",")[0] == u"名詞":
        words.append(node.surface)
    elif node.feature.split(",")[0] == u"形容詞":
        words.append(node.feature.split(",")[6])
    elif node.feature.split(",")[0] == u"動詞":
        words.append(node.feature.split(",")[6])
    node = node.next

#単語を空白で結合
text = ' '.join(words);

#ワードクラウドを作成
wordcloud = WordCloud(
	width = 800,  # 幅
	height = 200,  # 高さ
	background_color = 'white', # 背景色
	font_path = '/usr/share/fonts/truetype/fonts-japanese-gothic.ttf', # 日本語フォントを指定
#	max_font_size = 60, # サイズフォントサイズ
#	regexp = r"[\w']+",
	stopwords = set(stop_words), # 出力から除外する単語
)

file_name = 'wordcloud_' + str(no) + '.png'

wordcloud.generate(text)
wordcloud.to_file('/var/www/html/output/' + file_name)

#出力するデータ
response = {}
response['file_name'] = file_name

#print('<img src="../output/' + file_name + '">')

#ファイル名を出力
print(response)

/cgi-bin/ text2wc.py に対して、作成の元となる文章(text)とユニークな番号(no)を POST すると、ワードクラウド画像作成後にファイル名が出力されます。

{'file_name': 'wordcloud_123456.png'}

関連記事:

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください