deepblueインターン生で統計を勉強している中山です. 今回は前回の続きのColaboratoryでmecabの実行を行ってみたいと思います.

対象の読者

  • python初学者
  • 自然言語処理初学者
  • Google Colaboratoryで実行したい方

mecab準備

Google Colaboratory では,ローカルで実行する場合と異なり,毎回mecabをinstallする必要があります.mecabって何?という方もいると思いますが,とりあえず以下の文章を実行してください.

!apt-get -q -y install sudo file mecab libmecab-dev mecab-ipadic-utf8 git curl python-mecab > /dev/null
!git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git > /dev/null 
!echo yes | mecab-ipadic-neologd/bin/install-mecab-ipadic-neologd -n > /dev/null 2>&1
!pip install mecab-python3 > /dev/null
!echo mecab-config --dicdir"/mecab-ipadic-neologd"

これをそのまま実行するとmecabの準備ができます.大体1分ぐらいかかります.

mecabとは

mecabについて簡単に説明したいと思います.mecabは形態素解析を行うことを行うために使われます.形態素解析は文章を『 意味を持つ最小限の単位 』に分割することです.
どういうことかわからないと思うので実際に実行してみます.

import MeCab
m = MeCab.Tagger('-Owakati')
result = m.parse('形態素解析を練習で実行してみる')
print(result)

形態素 解析 を 練習 で 実行 し て みる

これは『形態素解析を練習で実行してみる』という文章を形態素に分けたということになります.中学校の国語で習った単語切りに似ていると思います.この半角スペースの入った文章のことを『分かち書き』と呼びます.

ですが,これだと『形態素解析』が『形態素』と『解析』に分かれてしまいます.別れることも正解ではあるのですが,『 形態素解析 』で1つの意味なので分けたくないです.
そこで,NEologdという辞書を用いることでこの問題が解決します.先ほど書いたimport文の中にNEologdを呼び出すコードも書いておいたので,既に読み込まれている状態です.
実際にやってみるとこのようになります.

import MeCab
m = MeCab.Tagger('-Owakati -d /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd')
result = m.parse('形態素解析を練習で実行してみる')
print(result)

形態素解析 を 練習 で 実行 し て みる

はい!『 形態素解析 』が分かれずに,きれいになっていることが確認できると思います.
このように,mecabでは形態素解析を実行できます.また,上では分かち書きを利用しましたが,語句の品詞も以下のように実行することで,調べることができます.

import MeCab
path = '-d /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd'
m = MeCab.Tagger(path)
result = m.parse('形態素解析を実行してみる')
print(result)

形態素解析 名詞,固有名詞,一般,*,*,*,形態素解析,ケイタイソカイセキ,ケイタイソカイセキ
を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
実行 名詞,サ変接続,*,*,*,*,実行,ジッコウ,ジッコー
し 動詞,自立,*,*,サ変・スル,連用形,する,シ,シ
て 助詞,接続助詞,*,*,*,*,て,テ,テ
みる 動詞,非自立,*,*,一段,基本形,みる,ミル,ミル
EOS

このように,形態素解析では品詞や読み方なども調べることができます.
ちなみに,EOSはEnd Of Sentence の略で,文末を意味します.

このようにして,mecabを実行することができます.word2vecでは,分かち書きした文章が必要となるため,文章の分かち書きを行います.

形態素解析の実行

word2vecでは形態素を用いて学習を行います.しかし,気を付ける点が2つあります.

  • 品詞を選択する
  • 原形に絞る

この2点です.これらを簡単に説明します.
1つ目の品詞を選択する点は,『名詞』,『動詞』,『形容詞』以外の品詞はあまり特徴を持たないので,ノイズと判断して外しました.
2つ目の原形にする点は,表記揺れを防ぐためです.例えば,『猫』と『ねこ』を別の単語として判断したくないので,このようにしました.
これらを関数定義すると,このようになります.

import MeCab
def mecab_tokenizer(text):
    m = MeCab.Tagger("-d /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd")
    node = m.parseToNode(text)
    wordtype_list = ['名詞','動詞','形容詞']
    subtype_list = ["数", "非自立", "代名詞","接尾"]
    output = []
    while node:
        if node.surface != "":
            wordtype = node.feature.split(",")[0]
            subtype = node.feature.split(",")[1]
            original = node.feature.split(",")[6]
            if wordtype in wordtype_list and subtype not in subtype_list and original != '*':
                output.append(original)
        node = node.next
        if node is None:
            break
    return output

これで望み通りの形態素解析を行う関数定義ができます.
試しに,実行してみるとこのようになります.

text = 'これで望み通りの形態素解析を行う関数定義ができます.'
mecab_tokenizer(text)

['望み', '形態素解析', '行う', '関数', '定義', 'できる']

うまく,助詞などが弾かれている事がわかると思います.

import pandas as pd
text_data = pd.read_table('吾輩は猫である_ルビなし.txt', encoding='cp932', header = None)
text_data.columns = ['text']
text_data['wakati'] = text_data['text'].apply(lambda x: ' '.join(mecab_tokenizer(x)))

これで,text_dataのdataframeが作成され,元のtextと分かち書きの列が作成できました.text_dataを確認するとこのようになっています.

以上で形態素解析は完全に終了です!

text_data.wakati.to_csv('wakati.csv', sep='\n', header=True, index=False)

word2vecの実行

形態素解析が完了したら,word2vecに投げるだけです.
実装をするとこのようになります.

from gensim.models import word2vec
import logging
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
sentence_data = word2vec.LineSentence('wakati.csv')
model_w2v = word2vec.Word2Vec(sentence_data,
                         sg=1,        # Skip-gram
                         size=200,    # 次元数
                         min_count=5, # min_count回未満の単語を破棄
                         window=5,    # 文脈の最大単語数
                         hs=1,        # 階層ソフトマックス(ネガティブサンプリングするなら0)
                         negative=5,  # ネガティブサンプリング
                         iter=50      # Epoch数
                         )

出力結果に関しては割愛します.
これで,学習が完了します.文章が短いので,30秒程度で学習が完了すると思います.
パラメータの調整があるのですが,とりあえずこの値に設定しました.調節したい方は調節してみてください.
類似度の測定はこのように行うことでできます.

s = input('類似度の計測をしたい単語を入力:')
try:
    results = model_w2v.most_similar(positive=[s], topn=20)
    for i, result in enumerate(results):
        print(i+1, '\t', '{0:.5f}'.format(result[1]), ' ', result[0])
except KeyError:
    print('{}が辞書の中に入っていない'.format(s))

1 0.32748 動物
2 0.31177 衣服
3 0.30977 する
4 0.30956 歴史
5 0.30434 赤裸
6 0.30149 ある
7 0.29940 個人
8 0.29394 無能
9 0.28921 猫
10 0.28526 案出
11 0.27976 云う
12 0.27799 もっとも
13 0.27320 同一
14 0.27196 条件
15 0.27086 証明
16 0.26697 全能
17 0.26412 運命
18 0.26111 世の中
19 0.25952 乏しい
20 0.25749 生涯

どうでしょうか.人間は動物であることは間違いないですが,文章中で人間が服を着ていることに吾輩が言及している点や,吾輩が人間を無能扱いしていることもうまく拾えているのではないでしょうか.
また,学習に乱数が用いられているため,同じ結果にはなりません.

最後に,作成したモデルの保存についてですが,driveのマウントをする必要があります.マウントをした状態であれば以下のコードを打つことで,モデルの保存ができます.

model_w2v.save('/content/drive/hoge/fuga/word2vec.model')

driveのマウントを実行したい方は,こちらに記事を書いたのでご覧になってください.

まとめ

以上で,word2vecの利用は終了です.
word2vecでの学習自体はそこまで大変ではないですが,前処理が色々とめんどくさかった気がします.

(著:中山 翔太)

Deepblueでは統計やAIの平和的活用を一緒に取り組んでいただける方を募集してます。詳しくはRecruitをご覧ください。

関連記事