結論
def cos_sim_matrix(matrix):
"""
item-feature 行列が与えられた際に
item 間コサイン類似度行列を求める関数
"""
d = matrix @ matrix.T # item-vector 同士の内積を要素とする行列
# コサイン類似度の分母に入れるための、各 item-vector の大きさの平方根
norm = (matrix * matrix).sum(axis=1, keepdims=True) ** .5
# それぞれの item の大きさの平方根で割っている(なんだかスマート!)
return d / norm / norm.T
- 英語でググれ (「cosine similarity matrix numpy」とかで)
- 元の数式をよく見ろ
導入
皆さんコサイン類似度行列は好きでしょうか?私は大好きです 。
特に協調フィルタリングなどを行おうとすると作ってみることが多いのではないのでしょうか。
ただ残念なことに、日本語で調べると2つのベクトル間のコサイン類似度の求め方はしばしば見かけるのですが、それらがまとまったコサイン類似度行列の求め方はほとんど見かけませんでした。
もしくはもう少し numpy 力がある人にとっては自明なのであえて明記していないのかもしれません。
ですので自分のへの備忘録も兼ねてここに残しておきます。
それまでにやってしまった過ち
これは失敗作ですので参考にしないでください 。
上記の数十倍時間かかります 。
@numba.jit('f8(f8[:],f8[:])', nopython=True)
def _cos_sim(v1, v2):
"""
2つのベクトルのコサイン類似度を返す
"""
return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
@numba.jit('f8[:, :](f8[:, :])', nopython=True)
def item_similarities(item_user_matrix):
"""
アイテム・ユーザー行列が与えられた際に
アイテム間類似度行列を求める関数
"""
n = item_user_matrix.shape[0] # n: item counts
sims = np.identity(n) # 同じアイテム同士の類似度は1
for i in range(n):
for j in range(i+1, n):
sim = _cos_sim(item_user_matrix[i], item_user_matrix[j])
sims[i][j] = sim
sims[j][i] = sim
return sims
最後に
I need more power...!! (もっと行列計算力が欲しい)