LoginSignup
1
1

More than 3 years have passed since last update.

言語処理100本ノック-89:加法構成性によるアナロジー

Posted at

言語処理100本ノック 2015の89本目「加法構成性によるアナロジー」の記録です。
「加法構成性」ということでベクトル演算をして結果を求めます。有名な「王 + 女性 - 男性 = 王女」の計算ですね。「上司 - 有能 = ?」のような計算で、世の中のいろいろなことで試してみたい演算です。

参考リンク

リンク 備考
089.加法構成性によるアナロジー.ipynb 回答プログラムのGitHubリンク
素人の言語処理100本ノック:89 言語処理100本ノックで常にお世話になっています

環境

種類 バージョン 内容
OS Ubuntu18.04.01 LTS 仮想で動かしています
pyenv 1.2.15 複数Python環境を使うことがあるのでpyenv使っています
Python 3.6.9 pyenv上でpython3.6.9を使っています
3.7や3.8系を使っていないことに深い理由はありません
パッケージはvenvを使って管理しています

上記環境で、以下のPython追加パッケージを使っています。通常のpipでインストールするだけです。

種類 バージョン
numpy 1.17.4
pandas 0.25.3

課題

第9章: ベクトル空間法 (I)

enwiki-20150112-400-r10-105752.txt.bz2は,2015年1月12日時点の英語のWikipedia記事のうち,約400語以上で構成される記事の中から,ランダムに1/10サンプリングした105,752記事のテキストをbzip2形式で圧縮したものである.このテキストをコーパスとして,単語の意味を表すベクトル(分散表現)を学習したい.第9章の前半では,コーパスから作成した単語文脈共起行列に主成分分析を適用し,単語ベクトルを学習する過程を,いくつかの処理に分けて実装する.第9章の後半では,学習で得られた単語ベクトル(300次元)を用い,単語の類似度計算やアナロジー(類推)を行う.

なお,問題83を素直に実装すると,大量(約7GB)の主記憶が必要になる. メモリが不足する場合は,処理を工夫するか,1/100サンプリングのコーパスenwiki-20150112-400-r100-10576.txt.bz2を用いよ.

今回は「1/100サンプリングのコーパスenwiki-20150112-400-r100-10576.txt.bz2を使っています。

89. 加法構成性によるアナロジー

85で得た単語の意味ベクトルを読み込み,vec("Spain") - vec("Madrid") + vec("Athens")を計算し,そのベクトルと類似度の高い10語とその類似度を出力せよ.

回答

回答プログラム 089.加法構成性によるアナロジー.ipynb

import numpy as np
import pandas as pd

# 保存時に引数を指定しなかったので'arr_0'に格納されている
matrix_x300 = np.load('085.matrix_x300.npz')['arr_0']

print('matrix_x300 Shape:', matrix_x300.shape)

group_t = pd.read_pickle('./083_group_t.zip')


# 'vec("Spain") - vec("Madrid") + vec("Athens") のベクトル計算
vec = matrix_x300[group_t.index.get_loc('Spain')] \
      - matrix_x300[group_t.index.get_loc('Madrid')] \
      + matrix_x300[group_t.index.get_loc('Athens')]
vec_norm = np.linalg.norm(vec)

# コサイン類似度計算
def get_cos_similarity(v2):

    # ベクトルが全てゼロの場合は-1を返す
    if np.count_nonzero(v2) == 0:
        return -1
    else:
        return np.dot(v1, v2) / (v1_norm * np.linalg.norm(v2))

cos_sim = [get_cos_similarity(matrix_x300[i]) for i in range(len(group_t))]
print('Cosign Similarity result length:', len(cos_sim))

# インデックスを残してソート
cos_sim_sorted = np.argsort(cos_sim)

# 昇順でソートされた配列の1番最後から-10(-11)までを1件ずつ出力
for index in cos_sim_sorted[:-11:-1]:
    print('{}\t{}'.format(group_t.index[index], cos_sim[index]))

回答解説

今回のメインの部分です。
ただ足し算、引き算をしているだけです。

# 'vec("Spain") - vec("Madrid") + vec("Athens") のベクトル計算
vec = matrix_x300[group_t.index.get_loc('Spain')] \
      - matrix_x300[group_t.index.get_loc('Madrid')] \
      + matrix_x300[group_t.index.get_loc('Athens')]

最後の出力結果です。
Spainから首都のマドリッドを引いて、アテネを足しているので、意味としてはギリシャが正解なのでしょうか。
ギリシャは12位でコサイン類似度は0.686でした。

Spain   0.8178213952646727
Sweden  0.8071582503798717
Austria 0.7795030693787409
Italy   0.7466099164394225
Germany 0.7429125848677439
Belgium 0.729240312232219
Netherlands 0.7193045612969573
Télévisions   0.7067876635156688
Denmark 0.7062857691945504
France  0.7014078181006329
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1