引き続き、NNablaの「Word2Vec」サンプルで遊んでみるの2回めです。
この記事は長くなるので以下のように3つにわけてます。
1回めである前回は、Word_to_Vector.pyで、日本語のごく小さなテキストファイルを読み込んで、とりあえず、動かしてどんな結果が得られるかを確認しました。
2回めである今回は、ネットから何か適当なテキストデータをとってきて、自然言語処理をおこなって、Word2Vecで利用できるインプットデータを作るところまでやってみます。
3回めで、それを学習させて、その結果を利用して、任意の単語で類義語を取得して遊んでみようかなと思っている・・とまあ、こんな構成です。
元になるテキストデータの取得
まず、もとになるテキストデータですけど、理想的にはWikipediaの全文データみたいなのがいいんだろうなとは思います。
Wikipediaの日本語全文データはこちらからダウンロードできますしね。
でも、とてつもなくでかいデータになります。
それこそ、数GBにも及ぶデータを処理すると、途方もない時間がかかります。
二週間・三週間、そればっかり・・とか。
それは嫌なので短い小説でやってみます
今回は、青空文庫から短い小説を一本ダウンロードして、それを使ってやろうと思います。
自分が昔から好きな、O・ヘンリーの「賢者の贈り物」にしようかな。
準備として、HTMLでダウンロードして、HTMLのタグとかを消して、小説部分のテキストデータだけのファイルを作ります。
そんな複雑なHTMLではないので、手作業でやっても10分もかからないし。
そうするとこんな感じの書き出しのテキストデータができます。
1ドル87セント。
それで全部。
しかもそのうち60セントは小銭でした。
小銭は一回の買い物につき一枚か二枚づつ浮かせたものです。
乾物屋や八百屋や肉屋に無理矢理まけさせたので、
しまいに、こんなに値切るなんてという無言の非難で頬が赤くなるほどでした。
デラは三回数えてみました。
でもやっぱり1ドル87セント。
明日はクリスマスだというのに。
ただ、このままだと、Word2Vecで処理できません。
単語ごとに、空白で区切られていないとならないですから。
なので、このテキストデータを処理できる形式に変換していきます。
自然言語処理のさわりをやってみる
こういう文章テキストデータ(文章や会話など)をコンピュータで処理するのを「自然言語処理」といいます。
今回の変換は、その自然言語処理のさわりを軽くやってみる感じになります。
自然言語処理の手順をざっくりわけると以下の3つ段階になります
まあ、構文解析するにせよ意味解析するにせよ、まず、単語に分割しないことには話にならないということですね。
ただ、単語が空白で区切られている英語等と違って、日本語は「単語分割」が非常に難しく昔から沢山の人が研究しています。
ここは、その成果をさくっと使わせていただきます。
さて、作業していきます。
なお、例によって、ここからの説明は以下の手順で環境が作られていることを前提にしていますので、違う方は読み替えてくださいね。
janomeを使って単語分割
単語分割(形態素解析とかいいますが)を行えるツールは色々ありますが、今回はpythonで一番気軽に使える「janome」を使います。
まず、例によってコマンドプロンプトで、「Activate nnabla」をして、nnabla環境にします。
ここで、janomeをインストールします。
インストールは以下を実行するだけです。
pip install janome
そうすると、しばらくインストールが行われて、以下のような画面になったら成功です。
じゃあ、IDLEを立ち上げて、New Fileを開きます。
まず、janomeの機能を確かめてみます。
以下のようなソースを打ち込み、適当な名前で保存して、F5キーで実行します。
from janome.tokenizer import Tokenizer
t = Tokenizer()
malist = t.tokenize(u"僕はこの美しい場所に立っているよ")
for n in malist:
print(n.surface)
print(n.part_of_speech)
そうすると、こんな出力が得られます。
僕
名詞,代名詞,一般,*
は
助詞,係助詞,*,*
この
連体詞,*,*,*
美しい
形容詞,自立,*,*
場所
名詞,一般,*,*
に
助詞,格助詞,一般,*
立っ
動詞,自立,*,*
て
助詞,接続助詞,*,*
いる
動詞,非自立,*,*
よ
助詞,終助詞,*,*
なるほど、なるほど。
つまり、ここで名詞・動詞・形容詞だけ抜き出して、空白区切りでつないで出力したらなんとなくいけそうですね。
じゃあ、正規表現を使ってこんな感じに変更してやってみます。
from janome.tokenizer import Tokenizer
import repat = r'名詞|動詞|形容詞'
regex = re.compile(pat)
t = Tokenizer()
malist = t.tokenize(u"僕はこの美しい場所に立っているよ")
for n in malist:
if(regex.match(n.part_of_speech)):
print(n.surface)
print(n.part_of_speech)
実行結果はこうです。
僕
名詞,代名詞,一般,*
美しい
形容詞,自立,*,*
場所
名詞,一般,*,*
立っ
動詞,自立,*,*
いる
動詞,非自立,*,*
よさげですね。
じゃあ、あとは、元の文章のテキストファイルにを読み込んで、行ごとに上記のように名詞・動詞・形容詞だけ抜き出して、空白をデリミタにしたデータを出力すれば良いわけです。
ただ、janomeが処理する文字コードが「UTF-8」で、元のテキストデータが「SJIS」なので、一旦UTF-8に変換して、処理して、ファイルに書き出すときはまたSJISに戻すという手続きも追加する必要があります。
それを追加したソースです。
# -*- coding: utf-8 -*-
from janome.tokenizer import Tokenizer
import re
import codecs as co#正規表現
pat = r'名詞|動詞|形容詞'
regex = re.compile(pat)#JANOME
t = Tokenizer()
#ファイルオープン(文字コード指定)
inf = co.open("magi.txt","r","shift_jis")
outf = co.open("w2v_magi.txt","w","shift_jis")
#ファイルを一気に読み込む
s = inf.read()
isFirstWrite = True
#形態素解析処理を行いファイルに書き出す
malist = t.tokenize(s.strip())
for n in malist:
if(regex.match(n.part_of_speech)):
#最初の単語以外は空白を頭につける
if(isFirstWrite == False):
outf.write(' ')
else:
isFirstWrite = False
outf.write(n.surface)inf.close()
outf.close()
とりあえず、もとの小説データを"magi.txt"、単語分割して名詞・動詞・形容詞のみを抜き出して空白区切りで出力するファイルを”w2v_magi.txt"という名前をつけてます。
出力結果はこんな感じです。
よさげですね。
じゃあ、次回はこのデータを使って、Word2Vecをやってみます。
あ・・、おまけを忘れてました。
janomeにもっと興味がある場合はこちらをどうぞ。
関連情報
NNabla関連の記事一覧はこちらです。
ニューラルネットワークコンソール関連の記事一覧はこちらです。