##やること
前回word2vecのデモを試せた ので、今回は日本語で試してみたいと思います。
すぐ使えるword2vec用の日本語データも公開はされているようですが、今後いろいろなデータからベクトルを作れるよう、学習用の前処理を手元でやってみたいと思います。
ここではWikipedia日本語版の公開データからベクトルデータを作成するまでを行います。
##環境
- Linux系
- MacBookAir 2015 で検証。
- 小型扇風機(ファイル処理の計算中にノートPCが熱くなりがち)
##やり方
word2vecをインストールする
(参考)前回記事
$ cd word2vec #任意の作業ディレクトリに移動してください
$ git clone https://github.com/svn2github/word2vec.git
$ cd word2vec
$ make
$ chmod +x *.sh
すでにword2vecがインストール済みであれば、word2vecディレクトリへの移動だけを実施する。前回記事はインストールからデモで遊ぶところまでを試しました。
日本語版wikiのデータをダウンロードする。
$ curl -O https://dumps.wikimedia.org/jawiki/latest/jawiki-latest-pages-articles.xml.bz2
#または $ wget https://dumps.wikimedia.org/jawiki/latest/jawiki-latest-pages-articles.xml.bz2
https://dumps.wikimedia.org/ の中の https://dumps.wikimedia.org/jawiki/latest/ で最新の日本語版wikiデータが公開されているので、本文ファイルの最新版をダウンロードします。3Gぐらいのファイルサイズになります。
日本語版wikiデータの中身をチェック
ここでファイルを解凍して中身を見ると理解が深まります。
$ bunzip2 jawiki-latest-pages-articles.xml.bz2
.bz2の圧縮ファイルはbunzip2コマンドで解凍できます。PCが熱くなったら扇風機で冷やしましょう。解凍後は13Gぐらいになります。
$ head -n 50 jawiki-latest-pages-articles.xml
解凍済みのファイルの先頭50行だけ覗いてみます。
タグらだけでファイルが重くなっているだろうことがわかります。
wikiextractorでデータからxmlをクリンナップする
wikiextractorという専用のツールが公開されているのでありがたく利用させていただきます。
参考)http://kzkohashi.hatenablog.com/entry/2018/07/22/212913
$ git clone https://github.com/attardi/wikiextractor.git
上記のgit URLは変更される場合があるので、もしダウンロードできなかった場合には、検索して有効なものに差し替えてください。
ダウンロードできたら、wikiextractor を jawiki-latest-pages-articles.xml.bz2に対して実行します。
$ python ./wikiextractor/WikiExtractor.py jawiki-latest-pages-articles.xml.bz2 -q -b 10M -o wiki_texts
wikiextractorは.bz2 の圧縮ファイルのまま作業をしてくれます。
オプションについては、
-q 出力レポート停止(速度UP)
-b 出力ファイルを区切るサイズの指定。今回は10M毎。
-o クリンナップしたファイルの格納場所。今回はwiki_textsを作成。
と指示しています。
作業中、いくつかのエラーが出ますが最後まで出力できます。
# エラー例
WARNING: Template errors in article '1996年全豪オープン' (744789):
ある程度時間のかかる工程です。デスクトップなどからwiki_textsのディレクトリを見るとファイルが刻々と生成されるので、進捗が確認できます。
上記の分割設定では、AA、AB、ACの3ディレクトリに収まりました。一つのディレクトリにwiki_00からwiki_99までのファイルが格納されます。
手元では1時間ちょっとぐらいで終了し、./wiki_texts/AC/wiki_94までファイルが作成されました。ノートブックが熱くなるので扇風機で冷却しながらの作業です。
$ head -n 5 ./wiki_texts/AA/wiki_00
<doc id="5" url="https://ja.wikipedia.org/wiki?curid=5" title="アンパサンド">
アンパサンド
アンパサンド (&、英語名:) とは並立助詞「…と…」を意味する記号である。ラテン語の の合字で、Trebuchet MSフォントでは、と表示され "et" の合字であることが容易にわかる。ampersa、すなわち "and per se and"、その意味は"and [the symbol which] by itself [is] and"である。
head で生成されたファイルを確認すると、若干のタグや改行が残っています。
ここからさらにクリンナップしていきます。
ファイルを連結する
$ find wiki_texts/ | grep wiki | awk '{system("cat "$0" >> wiki_all.txt")}'
参考サイトのコマンドをお借りしてファイルを連結します。
この例では、./wiki_texts 配下のディレクトリでwikiを含むファイルをwiki_all.txt(容量約3.09GB)にまとめています。
うまく行かない場合は、一つずつ連結すると成功するかもしれません。
$ find ./wiki_texts/AA/ | grep wiki_ | awk '{system("cat "$0" >> wiki_allAA.txt")}'
$ find ./wiki_texts/AB/ | grep wiki_ | awk '{system("cat "$0" >> wiki_allAB.txt")}'
$ find ./wiki_texts/AC/ | grep wiki_ | awk '{system("cat "$0" >> wiki_allAC.txt")}'
$ cat wiki_allAA.txt wiki_allAB.txt wiki_allAC.txt > wiki_all.txt
$ rm wiki_allAA.txt wiki_allAB.txt wiki_allAC.txt
$ brew install nkf
$ nkf -w --overwrite wiki_all.txt
仕上げのクリンナップをする
残りのタグを除去する
$ sed -e 's/<[^>]*>//g' ./wiki_all.txt > ./wiki_notag.txt
各項目の文頭についているタグを削除します。この時点でファイルは2.96GBになります。
丸括弧の中身を除去する
#全角カッコを半角に
$ sed -i -e 's/(/(/g' ./wiki_notag.txt && sed -i -e 's/)/)/g' ./wiki_notag.txt
#カッコ内を削除
$ sed -i -e 's/([^)]*)//g' ./wiki_notag.txt
丸括弧の中身は大事な要素のような気もしますが、今回は削除してみました。2.77GB。
最後に改行や余白を削除しました。
#空白をすべて埋めたあと空行を削除
$ sed -i -e 's/ //g' ./wiki_notag.txt && sed -i -e '/^$/d' ./wiki_notag.txt
みっちとしたファイルになり2.75GB。
ファイルの中身を確認するには、
$ less wiki_notag.txt
とします。
それぞれの項目が前後の関係ない項目と距離が近くなってしまう気がしますが、そのあたりの処理が必要であればいずれ。
mecabをインストールして分かち書きする
文章をみっちりに作れたので、単語ごとに分かち書きを行い、スペースで区切っていきます。
参考)https://qiita.com/paulxll/items/72a2bea9b1d1486ca751
参考)http://kzkohashi.hatenablog.com/entry/2018/07/22/212913
参考)https://akamist.com/blog/archives/2815
mecabのインストール
分かち書きを行うmecab関連の必要ファイルを導入します。
$ brew install mecab
$ brew install mecab-ipadic
$ brew install xz
Mac以外ではbrewの代わりにaptなどを使います。
またコンソールで指示が出た場合には、brew reinstall mecab や brew reinstall mecab-ipadic などの再インストールも実行しておきます。
新語に対応した辞書も導入しておきます。
$ git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
$ cd mecab-ipadic-neologd
$ ./bin/install-mecab-ipadic-neologd -n -a
3行めはオプションに -a をつけることで新語全部入りでの実行となります。
少し時間がかかります。最後の方で Do you want to install mecab-ipadic-NEologd?と尋ねられるのでyesを入力。インストールが終わるとFinish..と表示されます。
python用のmecabもインストールしておきます。
$ cd ../ #作業ディレクトリに戻ります
$ pip install mecab-python3
分かち書きを実行
$ mecab -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd -Owakati wiki_notag.txt -o wiki_wakati.txt -b 163840
現在のディレクトリの位置や mecab-ipadic-neologd のパス指定にミスがなければこれで分かち書きが実行されます。-b の後の数字は小さいと失敗しました。
$ nkf -w --overwrite wiki_wakati.txt
ここで再度、念のためのデータ整理をしておいても良いかもしれません。
$ less wiki_wakati.txt
分かち書き後のファイルは3.24GB。上記コマンドで分かち書き後のテキストファイルの様子を確認できます。
これで下準備が整いました。
ベクトル化を実行
word2vecによるベクトル化を実行します。
$ ./word2vec -train wiki_wakati.txt -output wiki_wakati_w2v.bin -size 200 -window 5 -sample le-3 -negative 5 -hs 0 -threads 1 -binary 1 -iter 1
参考)https://qiita.com/dskst/items/a9571bdd74a30a5e8d55
オプションの意味は、
-train 学習に使用するファイル
-output 学習結果を出力するファイル名
-size ベクトルの次元数
-window 文脈の最大単語数
-sample 単語を無視する頻度
-negative ネガティブサンプリングに用いる単語数
-hs 学習に階層化ソフトマックスを使用するかどうか
-threads 学習に使用するスレッド数
-binary バイナリ形式で出力するかどうか
-iter トレーニング反復回数
となります。他にも単語リストを出力するなど、様々なオプションがあります。次元数を下げたり学習回数を増やすなど、サイズと精度をいろいろ調整できそうです。
しばらく待てば処理終了。手元では30分ぐらいかかりました。
wiki_wakati_w2v.bin が今回生成されたベクトルデータになります。
Vocab size: 1290027
Words in train file: 1004450612
という129万語のベクトルデータになりました。
(ちなみにファイルサイズはノートだと1.06GB、デスクトップだと0.73GBでした。ほぼ同じ手順で行いましたがデスクトップの方が精度もよかったので、手元のノートはデータ作成に失敗している可能性が高いです。)
新しい辞書を試す
$ ./distance wiki_wakati_w2v.bin
関連の高い単語を探します。
Enter word or sentence (EXIT to break): アムロ
Word: アムロ Position in vocabulary: 30293
Word Cosine distance
------------------------------------------------------------------------
シャア 0.837395
アスラン 0.772420
アムロ・レイ 0.766061
シンジ 0.742949
悟飯 0.739751
カミーユ 0.725921
鬼太郎 0.724508
それっぽいのが出ました。先ほども触れましたが、デスクトップPCで試した方がよい精度でした。ノートPCの方は2単語以上が?記号で連結された状態の単語も多く見られたので、処理に一部失敗しているようです。
日本に対する東京はフランスに対しては何?の問題もやってみました。
$ ./word-analogy wiki_wakati_w2v.bin
ルーク・スカイウォーカーに対するダース・ベイダーは、のび太に対して何でしょう?
Enter three words (EXIT to break): ルーク・スカイウォーカー ダース・ベイダー のび太
Word: ルーク・スカイウォーカー Position in vocabulary: 95245
Word: ダース・ベイダー Position in vocabulary: 68735
Word: のび太 Position in vocabulary: 11432
Word Distance
------------------------------------------------------------------------
ジャイアン 0.652843
スネ夫 0.645669
しずか 0.614481
ドラえもん 0.609560
ケロロ 0.608829
鬼太郎 0.607345
ジャイアンやスネ夫が上位に出てきて良い感じです。なぜかまた鬼太郎がいます。
おわりに
近しい手順を踏むことで、いろいろな団体がテキストファイルとして提供してくれているコーパスを活用することができるようになりそうです。
小さくて性能のよいベクトルデータを作ることにも興味が出てきました。