深層学習とその他

機械学習したいマン

日本のWikipediaのデータを使ったWord2vecでの類似語表示とngramで文生成 (1)

まともに使ったことがなかったWord2vecを使っていきます。

データを手に入れる

まず、Wikipediaのデータはここから拾ってきます。
Wikipedia:データベースダウンロード - Wikipedia
基本は最新の全ページを拾ってくればいいと思います。
英語を使いたい人は少し前処理を変える必要がありますが、普通にいけると思います。
wgetで拾います。容量が大きいので要注意。

wget https://dumps.wikimedia.org/jawiki/latest/jawiki-latest-pages-articles.xml.bz2
前処理

データが大きいので分割して処理します。
wikiextractorをcloneして使いましょう。

git clone https://github.com/attardi/wikiextractor.git
cd wikiextractor

extractというフォルダに、1ファイル50Mずつで分割して出力します。

python WikiExtractor.py -b 50M -o extract jawiki-latest-pages-articles.xml.bz2
正規化

こちらのコードを使わせていただきました。
umiushizn.blogspot.jp

normalize_neologd.py

# encoding: utf8
from __future__ import unicode_literals
import re
import unicodedata

def unicode_normalize(cls, s):
    pt = re.compile('([{}]+)'.format(cls))

    def norm(c):
        return unicodedata.normalize('NFKC', c) if pt.match(c) else c

    s = ''.join(norm(x) for x in re.split(pt, s))
    s = re.sub('-', '-', s)
    return s

def remove_extra_spaces(s):
    s = re.sub('[  ]+', ' ', s)
    blocks = ''.join(('\u4E00-\u9FFF',  # CJK UNIFIED IDEOGRAPHS
                      '\u3040-\u309F',  # HIRAGANA
                      '\u30A0-\u30FF',  # KATAKANA
                      '\u3000-\u303F',  # CJK SYMBOLS AND PUNCTUATION
                      '\uFF00-\uFFEF'   # HALFWIDTH AND FULLWIDTH FORMS
                      ))
    basic_latin = '\u0000-\u007F'

    def remove_space_between(cls1, cls2, s):
        p = re.compile('([{}]) ([{}])'.format(cls1, cls2))
        while p.search(s):
            s = p.sub(r'\1\2', s)
        return s

    s = remove_space_between(blocks, blocks, s)
    s = remove_space_between(blocks, basic_latin, s)
    s = remove_space_between(basic_latin, blocks, s)
    return s

def normalize_neologd(s):
    s = s.strip()
    s = unicode_normalize('0-9A-Za-z。-゚', s)

    def maketrans(f, t):
        return {ord(x): ord(y) for x, y in zip(f, t)}

    s = re.sub('[˗֊‐‑‒–⁃⁻₋−]+', '-', s)  # normalize hyphens
    s = re.sub('[﹣-ー—―─━ー]+', 'ー', s)  # normalize choonpus
    s = re.sub('[~∼∾〜〰~]', '', s)  # remove tildes
    s = s.translate(
        maketrans('!"#$%&\'()*+,-./:;<=>?@[¥]^_`{|}~。、・「」',
              '!”#$%&’()*+,-./:;<=>?@[¥]^_`{|}〜。、・「」'))

    s = remove_extra_spaces(s)
    s = unicode_normalize('!”#$%&’()*+,-./:;<>?@[¥]^_`{|}〜', s)  # keep =,・,「,」
    s = re.sub('[’]', '\'', s)
    s = re.sub('[”]', '"', s)
    return s

if __name__ == "__main__":
    assert "0123456789" == normalize_neologd("0123456789")
    assert "ABCDEFGHIJKLMNOPQRSTUVWXYZ" == normalize_neologd("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
    assert "abcdefghijklmnopqrstuvwxyz" == normalize_neologd("abcdefghijklmnopqrstuvwxyz")
    assert "!\"#$%&'()*+,-./:;<>?@[¥]^_`{|}" == normalize_neologd("!”#$%&’()*+,-./:;<>?@[¥]^_`{|}")
    assert "=。、・「」" == normalize_neologd("=。、・「」")
    assert "ハンカク" == normalize_neologd("ハンカク")
    assert "o-o" == normalize_neologd("o₋o")
    assert "majikaー" == normalize_neologd("majika━")
    assert "わい" == normalize_neologd("わ〰い")
    assert "スーパー" == normalize_neologd("スーパーーーー")
    assert "!#" == normalize_neologd("!#")
    assert "ゼンカクスペース" == normalize_neologd("ゼンカク スペース")
    assert "おお" == normalize_neologd("お             お")
    assert "おお" == normalize_neologd("      おお")
    assert "おお" == normalize_neologd("おお      ")
    assert "検索エンジン自作入門を買いました!!!" == \
        normalize_neologd("検索 エンジン 自作 入門 を 買い ました!!!")
    assert "アルゴリズムC" == normalize_neologd("アルゴリズム C")
    assert "PRML副読本" == normalize_neologd("   PRML  副 読 本   ")
    assert "Coding the Matrix" == normalize_neologd("Coding the Matrix")
    assert "南アルプスの天然水Sparking Lemonレモン一絞り" == \
        normalize_neologd("南アルプスの 天然水 Sparking Lemon レモン一絞り")
    assert "南アルプスの天然水-Sparking*Lemon+レモン一絞り" == \
        normalize_neologd("南アルプスの 天然水- Sparking* Lemon+ レモン一絞り")

conv.py

import sys
import normalize_neologd as nneo
import re
for line in sys.stdin:
    line = line.replace("。","。\n")
    line = re.sub(r'<[^\]]*>', '', line)
    print(nneo.normalize_neologd(line))

全ファイルに対して処理をすると重いので、今回は1ファイルだけ使います。
mecabで-bオプションをつけないとうまくいきませんでした。

cat extract/AA/wiki | python conv.py | mecab -b 100000000 -Owakati -d /usr/local/lib/mecab/dic/ipadic/ > wiki.txt

ここから生成したテキストを処理していきます。