LoginSignup
2
5

More than 3 years have passed since last update.

言語処理100本ノック-88:類似度の高い単語10件

Last updated at Posted at 2020-01-15

言語処理100本ノック 2015の88本目「類似度の高い単語10件」の記録です。
すべての単語から似たやつを抜き出します。これまた、自分のメールボックスや議事録等からやってみたい処理ですね。
技術的には前回の内容とほぼ同じです。

参考リンク

リンク 備考
088.類似度の高い単語10件.ipynb 回答プログラムのGitHubリンク
素人の言語処理100本ノック:88 言語処理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を使っています。

88. 類似度の高い単語10件

85で得た単語の意味ベクトルを読み込み,"England"とコサイン類似度が高い10語と,その類似度を出力せよ.

回答

回答プログラム 088.類似度の高い単語10件.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)

# 'Englandの単語ベクトルを読み込み、ノルムも計算
v1 = matrix_x300[group_t.index.get_loc('England')]
v1_norm = np.linalg.norm(v1)


# コサイン類似度計算
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番最後から-11(-12)までを1件ずつ出力(トップはEngland自身)
for index in cos_sim_sorted[:-12:-1]:
    print('{}\t{}'.format(group_t.index[index], cos_sim[index]))

回答解説

コサイン類似度計算部分を関数にしました。count_nonzero関数で判定して、ベクトルがすべてゼロの場合は-1を返すようにしています。

# コサイン類似度計算
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))]

上記の計算に対して、numpyだとこっちのapply_along_axisを使った方が速いかとも思いましたが、むしろ遅かったので非採用です。

cos_sim = np.apply_along_axis(get_cos_similarity, 1, matrix_x300)

最後の出力結果です。ScotlandやItalyなどが上位にいます。
Japanもいるのが意外です。島国だからなのでしょうか。

England 1.0000000000000002
Scotland    0.6364961613062289
Italy   0.6033905306935802
Wales   0.5961887337227456
Australia   0.5953277272306978
Spain   0.5752511915429617
Japan   0.5611603300967408
France  0.5547284075334182
Germany 0.5539239745925412
United_Kingdom  0.5225684232409136
Cheshire    0.5125286144779688
2
5
2

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
2
5