はじめに
word2vecやfasttextなどで得られた単語ベクトルから類似度の高い単語をランキングする際に,コサイン類似度の行列があれば楽そうなので勉強がてら実装してみた.
参考
コサイン類似度とは
2つのベクトルのなす角θのコサインの値を求めている.
\cos{(\vec{p},\vec{q})}= \frac{\vec{p} \vec{q}}{|\vec{p}| |\vec{q}|} = \frac{|\vec{p}| |\vec{q}|}{|\vec{p}| |\vec{q}|} \cos\theta = \cos\theta
コード
単語ベクトルのコサイン類似度の行列を計算する関数.単位ベクトルに正規化した後に,全ての単語の組み合わせの内積を計算してコサイン類似度を計算している..
import numpy as np
def cosine_similarity_matrix (vectors):
unit_vectors = vectors / np.linalg.norm(vectors, axis=1, keepdims=True)
return np.matmul(unit_vectors, unit_vectors.T)
実行例
コサイン類似度が高い順に単語を出力する例.
import numpy as np
import pandas as pd
# 10,000語の単語とベクトル(256次元)
words = ['word_{}'.format(i) for i in range(10000)]
vectors = np.random.rand(10000, 256)
# コサイン類似度行列を計算
matrix = cosine_similarity_matrix(vectors)
df = pd.DataFrame(matrix, index=words, columns=words)
# word_1と類似度が高い順に単語を出力
result = df['word_1'].sort_values(ascending=False).drop(index='word_1')
print(result)
# word_6049 0.809170
# word_7033 0.808725
# word_8884 0.805947
# word_6607 0.805759
# word_8257 0.805468
# word_1865 0.805220
# word_5849 0.805014
# word_4910 0.804502
# word_4079 0.804210
# word_6249 0.803592
# ...
さいごに
コサイン類似度は2つのベクトルの成す角のみを考慮しているが,ベクトルの大きさは関係ないのだろうか?と疑問に思った.今後時間があるときに実際に単語ベクトルを求めて適用してみようと思う.