初心者向けにgensimとWord2Vecの利用方法と、類似単語の可視化を解説します。

Word2Vecは、自然言語処理の一つで大量のテキストデータを解析し、各単語の意味をベクトル表現をする手法です。単語の意味の近さや類似度などを計算することが出来ます。

Gensimとは

gensimは、統計的機械学習を使用した、教師なしトピックモデリングと自然言語処理のためのオープンソースライブラリです。無料で使えるPython向けライブラリです。

主な機能としては、fastTextWord2vecDoc2vec潜在意味解析(LSI/LSA)トピックモデル(LDA)TF-IDFなどです。ライセンスはLGPLです。

gensim公式:https://radimrehurek.com/gensim/index.html

Word2Vecとは

Word2Vecは、大量のテキストデータを学習し、各単語の意味を数値化(ベクトル表現)する手法です。コンピュータは数値しか計算できません。なので、単語を数値化することで、単語同士の意味の近さや、単語同士の意味を足したり引いたりすることが可能になります。

Word2Vecを改良した手法にfastTextという手法もあります。今回はこちらを利用します。

なお「単語」ではなく「文章」を数値化する手法にDoc2Vecがあります。また、文章の前後の文脈からより抽象度の高い読解が可能になった手法にBERTがあります。

Word2Vec公式:https://code.google.com/archive/p/word2vec/

環境

・Windows10 pro 64bit
・Python3.7
・Gensim3.8(pip install gensim でインストールできます)

1.Word2Vecの学習済みモデルの取得

コーパスから学習済みモデルを生成するのは少し大変だったので、公開されている学習済みモデルを使用しました。

利用した学習済みモデル:fastTextの学習済みモデルを公開しました

WikipediaをMeCabのNEologdを使って分かち書きしたテキストを、fastTextによって学習させたモデル(model_neologd.vec)を使用します。(次元数:300)
import gensim
model = gensim.models.KeyedVectors.load_word2vec_format('model/model.vec', binary=False)

2.Word2Vecによる単語ベクトル化

fastText(Word2Vec)で単語の意味をベクトル化(分散表現とも言います)し、いくつか演算してみます。

類似度の高い単語を表示する

「機械学習」に似ている単語は、「進化的アルゴリズム」や「遺伝的アルゴリズム」のようです。
>> print(model.most_similar('機械学習'))
[('進化的アルゴリズム', 0.713220477104187), ('遺伝的アルゴリズム', 0.6929397583007812), ('アルゴリズム情報理論', 0.6830018162727356), ('決定的アルゴリズム', 0.6799790859222412), ('アルゴリズム', 0.6766400337219238), ('組合せ最適化', 0.6756596565246582), ('ニューラルネットワーク', 0.6749129295349121), ('乱択アルゴリズム', 0.6715476512908936), ('データマイニング', 0.6635973453521729), ('コンパイラ最適化', 0.6590137481689453)]


複数の単語で類似度の高いものを表示する

>> print(model.most_similar(['りんご', 'スイカ']))
[('リンゴ', 0.664942741394043),
('トマト', 0.6449971199035645),
('サクランボ', 0.6403110027313232),
('イチゴ', 0.6343967914581299),
('果物', 0.6201387643814087),
('ブドウ', 0.6004226207733154),
('みかん', 0.5951300859451294),
('青リンゴ', 0.5951046347618103),
('カボチャ', 0.5930560827255249),
('フルーツ', 0.5922333598136902)]


単語を四則演算する

「研究者」から「調査」を引くと、「哲学者」になりました。
>> print(model.most_similar(positive=['研究者'], negative=['調査']))
[('哲学者', 0.3975968360900879),
('文芸評論家', 0.3687889575958252),
('学者', 0.3613121509552002),
('論理学者', 0.35852164030075073),
('インド哲学', 0.35495686531066895),
('物理学者', 0.351429283618927),
('理論物理学者', 0.3484882414340973),
('アカデミズム', 0.3483889400959015),
('精神分析家', 0.34501272439956665),
('学界', 0.3397941589355469)]


単語間の類似度を算出する

「コロッケ」と「メンチカツ」の類似度は、0.537のようです。割と似ている感じですね。
>> print(model.similarity('コロッケ', 'メンチカツ'))
0.5367063

3.類似単語の分布図を書いてみる

今回利用させて頂いた、fastTextの学習済みモデルの単語ベクトルは300次元です。それを主成分分析(PCA)で次元圧縮して2次元に落とし込んだ後に可視化してみました。

ちなみに、Windows環境だとmatplotlibの日本語が文字化けすることがあります。こちらのサイトの手順を実行したところ、文字化けが治りました。
def draw_word_scatter(word, topn=30):
    """ 入力されたwordに似ている単語の分布図を描くためのメソッド """

    # 似ている単語を求めるためにはGensim word2vecの以下の機能を利用
    words = [x[0] for x in sorted(model.most_similar(word, topn=topn))]

    vecs = []
    # 各単語のベクトル表現を求めます  
    for word in words:
        vec = model.wv[word]
        vecs.append(vec)
        
    # Scikit-learnのPCAによる次元削減とその可視化
    pca = PCA(n_components=2)
    coords = pca.fit_transform(vecs)
    
    # matplotlibによる可視化
    fig, ax = plt.subplots()
    x = [v[0] for v in coords]
    y = [v[1] for v in coords]
    
    ax.scatter(x, y)
    
    for i, txt in enumerate(words):
        ax.annotate(txt, (coords[i][0], coords[i][1]))
    plt.show()

"副業"という単語の分布図を書きました。
# "副業"に似てる単語を可視化
draw_word_scatter('副業',40)
Figure_2
割と納得感があり、fastTextの優秀さが分かります。

参考記事:【word2vec】会社のクチコミを自然言語処理した結果を可視化してみる

4.まとめ

今回は公開されている学習済みモデルを使用しましたが、gensimではコーパスデータから簡単に学習済みモデルを作成することができます(それなりのCPUとメモリは必要ですが)。

自然言語処理の急速な発展で、Word2Vecはもう古い技術ですが、数行のコードで単語を可視化できるので、最初の一手で始めるのは悪くないと感じます。

関連記事:自然言語処理の分散表現(Word2Vec,fastText)の課題