wikipediaデータを綺麗にしてからWord2vecやってみた

今更な感じですが色々とあってWord2Vecで類義語分析とか表記ゆれとかできないかと思ってお勉強兼実験しました。もう一人のボクのためにその時のメモを置いておきます。データ加工してからword2vec使って関連する語出すとこまでです。相変わらずほぼコピペだけどね。そしてcorpusのつづりを間違えているのはお約束です。へぼすぎだな(笑)

■手順概要
1.ディスク容量拡張
2.関連ライブラリインストール
3.コーパス準備
 ・Wikipediaの日本語ダンプをダウンロード(約2時間)
 ・ダウンロードしたデータから記事本文抽出(約2時間10分)
 ・抽出した記事本文のクリーニング(約15分)
 ・記事データを1ファイルにマージ(約5分)
 ・形態素解析して分かち書きに変換(約30分)
 ・モデル学習(約2時間)
4.サンプルで遊ぶ

■実際のコマンドやプログラムなど
1.ディスク容量拡張
Hyper-Vのディスク容量が20GB程度しかなくwikipediaのデータが
2GBほどあるとのことなのでディスク容量に余裕を持たせるために
ディスクを拡張した。仮想マシンが上がっていない状態で容量拡張
・Hyper-Vマネージャからディスクの編集で容量を拡張
・Hype-Vマシンを起動後に以下のコマンドでUbuntu上で拡張
$ sudo fdisk -l
$ sudo parted
GNU Parted 3.2
/dev/sda を使用
GNU Parted へようこそ! コマンド一覧を見るには 'help' と入力してください。
(parted)print
~中略~
修正/Fix/無視(I)/Ignore? Fix
番号  開始    終了    サイズ  ファイルシステム  名前                  フラグ
1    1049kB  538MB   537MB   fat32             EFI System Partition  boot, esp
2    538MB   21.5GB  20.9GB  ext4
~中略~
(parted) resizepart 2
警告: パーティション /dev/sda2 は使用中です。それでも実行しますか?
はい(Y)/Yes/いいえ(N)/No?  Y
終了?  [21.5GB]? 50GB
~中略~
(parted) print
~中略~
(parted) quit
$ sudo resize2fs /dev/sda2

2.関連ライブラリインストール
データの前処理で必要となるので追加ライブラリをpipで導入
  $ sudo apt-get -y install nkf
  $ pip3 install scipy
  $ pip3 install gensim
  $ pip3 install wikipedia2vec
  $ pip3 install neologdn
  $ pip3 install emoji

3.コーパス準備
・コーパスを準備するためのコマンド類
#Wikipediaの日本語ダンプをダウンロード
$ mkdir copas
$ cd copas
$ curl https://dumps.wikimedia.org/jawiki/latest/jawiki-latest-pages-articles.xml.bz2 -o jawiki-latest-pages-articles.xml.bz2
#ダウンロードしたデータから記事本文抽出
$ git clone https://github.com/attardi/wikiextractor
$ python3 wikiextractor/WikiExtractor.py jawiki-latest-pages-articles.xml.bz2
#抽出した記事本文のクリーニング
$ python3 ../src/datacleaning.py text
#記事データを1ファイルにマージ
$ cat text/*/* > jawiki.txt
#形態素解析して分かち書きに変換
$ mecab -d /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd -Owakati jawiki.txt -o data.txt -b 16384
$ nkf -w --overwrite data.txt
#モデル学習
$ python3 ../src/modelmake.py

・データクリーニング用のプログラム(datacleaning.py)
import os
import re
import sys
import time
import traceback

import emoji
import neologdn

def strnormaraizer(str):
    """
    wikipediaデータの日本語を正規化する
    """
    try:
        s = neologdn.normalize(str)
        s = re.sub(
                r'(http|https)://([-\w]+\.)+[-\w]+(/[-\w./?%&=]*)?',
                "",s
              )
        s = re.sub("<.*?>","",s)
        s = re.sub(r'(\d)([,.])(\d+)', r'\1\3', s)
        s = re.sub(r'[!-/:-@[-`{-~]', r' ', s)
        s = re.sub(u'[■-♯]', ' ', s)
        s = re.sub(r'(\d)([,.])(\d+)', r'\1\3', s)
        s = re.sub(r'\d+', '0', s)
        s = ''.join(['' if c in emoji.UNICODE_EMOJI else c for c in s])
        return s
    except Exception as e:
        t, v, tb = sys.exc_info()
        print(traceback.format_exception(t,v,tb))
        print(traceback.format_tb(e.__traceback__))

def main():
    """
    主処理
    第1引数で指定されたディレクトリ配下のファイルをすべて処理する。

    """
    try:
        start_t = time.perf_counter()
        rootdir = sys.argv[1]
        i=0
        for root, dirs, files in os.walk(rootdir):
            i +=1
        j = 0
        for root, dirs, files in os.walk(rootdir):
            if j > 0:
               print('処理ディレクトリ{0}/{1}'.format(j,i-1))
               file_count = len(files)
               print('処理対象ファイル数{0}'.format(file_count))
            j +=1
            for file_ in files:
                input_file = os.path.join(root, file_)
                with open(input_file,'r') as inf:
                     s =inf.read()
                     o = strnormaraizer(s)
                with open(input_file,'w') as outf:
                     outf.write(o)
        end_t = time.perf_counter()
        process_time = end_t - start_t
        print('処理時間は:{0}秒です。'.format(process_time))
    except Exception as e:
        t, v, tb = sys.exc_info()
        print(traceback.format_exception(t,v,tb))
        print(traceback.format_tb(e.__traceback__))

if __name__ == '__main__':
   main()

・モデル生成用プログラム(modelmake.py)
from gensim.models import word2vec
import logging

logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
sentences = word2vec.Text8Corpus('./data.txt')

model = word2vec.Word2Vec(sentences, size=200, min_count=20, window=15)
model.save("./ja_wiki.model")


4.サンプル
・コマンドラインの後ろに調べたい言葉入れると結果が返ってくる。
$ python3 word2vecsample.py 織田信長
('信長', 0.8410834670066833)
('羽柴秀吉', 0.8160404562950134)
('明智光秀', 0.7978937029838562)
('豊臣秀吉', 0.7927731275558472)
('徳川家康', 0.7548580169677734)
('毛利元就', 0.7484856843948364)
('今川義元', 0.7425110936164856)
('浅井長政', 0.7422305345535278)
('織田氏', 0.7414403557777405)
('武田信玄', 0.7356137633323669)

・実験用プログラム(word2vecsample.py)
from gensim.models import word2vec
import sys

word = sys.argv[1]
model = word2vec.Word2Vec.load("../copas/ja_wiki.model")
results = model.wv.most_similar(positive=[word])
for result in results:
    print(result)

数学が赤点な自分には詳しい仕組みはわかりませんが、矢印を2個くっつけてその間にある角度が小さかったら近しいとか、文字に数字をくっつけて座標軸上にそれを置いて計算できるようにしたとかそんな感じらしい。論文あるそうですが英語も赤点だったのでとてもではないですが読めません。興味ある方はどうぞ
https://arxiv.org/abs/1301.3781
https://arxiv.org/abs/1310.4546
https://arxiv.org/abs/1402.3722
https://arxiv.org/abs/1411.2738

他にも文書をエイやっとするdoc2vecなるものもあるらしい。どちらかというとこちらの方が用途的にはより近しいのかもしれないかなぁと思いつつ、まぁ使い方はほぼ同じみたいだが、、、、word2vecとどこがどう違うんだ?とか思いました。


■参考サイト

・Word2vec関連

・前処理

プログラムよりデータ加工の前処理でかなり時間がかかります。
前処理してデータ量減らしておくの大事ですね。
学習済データ込みでAPIになっててるのがGoogleAmazonのがあるみたいですね。というよりAmazonは日本語対応できていないのか、、、、。MSもやっとるみたいだけど日本語でってなるとGoogleか自前で考えるしかないのが現状の様ですな。

そしてHyper-Vと低スペックPCで実行すると遅いのでとてもじゃないけど実用レベルじゃないです。もっと高スペックなPCで試した方がいいだろうと思った。

コメント

このブログの人気の投稿

GASでGoogleDriveのサブフォルダとファイル一覧を出力する

証券外務員1種勉強(計算式暗記用メモ)

マクロ経済学(IS-LM分析)