摘要:Numpy
,Python
余弦相似度公式
余弦相似度是衡量向量夾角的余弦值作為相似度度量指標(biāo)向叉,夾角越小相似度越高
公式為兩個(gè)向量的點(diǎn)乘除以向量的模長(zhǎng)的乘積
計(jì)算向量之間余弦相似度
使用Python的Numpy框架可以直接計(jì)算向量的點(diǎn)乘(np.dot)
,以及向量的模長(zhǎng)(np.linalg.norm
),余弦相似度在[-1, 1]
之間居兆,為了能更直觀地和相似度等價(jià)剧防,通常轉(zhuǎn)化為[0, 1]
之間,如下代碼實(shí)現(xiàn)計(jì)算兩個(gè)一維向量之間的余弦相似度
def get_cos_similar(v1: list, v2: list):
num = float(np.dot(v1, v2)) # 向量點(diǎn)乘
denom = np.linalg.norm(v1) * np.linalg.norm(v2) # 求模長(zhǎng)的乘積
return 0.5 + 0.5 * (num / denom) if denom != 0 else 0
計(jì)算向量和矩陣的余弦相似度
如果要計(jì)算一個(gè)向量和候選所有向量的余弦相似度奇唤,使用如下代碼將一維向量和多維向量直接點(diǎn)乘
def get_cos_similar_multi(v1: list, v2: list):
num = np.dot([v1], np.array(v2).T) # 向量點(diǎn)乘
denom = np.linalg.norm(v1) * np.linalg.norm(v2, axis=1) # 求模長(zhǎng)的乘積
res = num / denom
res[np.isneginf(res)] = 0
return 0.5 + 0.5 * res
計(jì)算矩陣和矩陣的余弦相似度
如果要計(jì)算兩個(gè)向量庫(kù)內(nèi)幸斥,兩兩向量的余弦相似度,對(duì)之前代碼稍作修改即可
def get_cos_similar_matrix(v1, v2):
num = np.dot(v1, np.array(v2).T) # 向量點(diǎn)乘
denom = np.linalg.norm(v1, axis=1).reshape(-1, 1) * np.linalg.norm(v2, axis=1) # 求模長(zhǎng)的乘積
res = num / denom
res[np.isneginf(res)] = 0
return 0.5 + 0.5 * res
效率對(duì)比
先對(duì)比計(jì)算結(jié)果是否一致咬扇,沒(méi)啥問(wèn)題甲葬,三個(gè)方法計(jì)算的結(jié)果一致
print(get_cos_similar([1, 2, 3], [2, 3, -1])) # 0.6785714285714286
print(get_cos_similar([1, 2, 3], [2, -1, -1])) # 0.3363365823230057
print(get_cos_similar([2, 5, -1], [2, 3, -1])) # 0.9879500364742666
print(get_cos_similar([2, 5, -1], [2, -1, -1])) # 0.5
print(get_cos_similar_multi([1, 2, 3], [[2, 3, -1], [2, -1, -1]])) # [[0.67857143 0.33633658]]
print(get_cos_similar_matrix([[1, 2, 3], [2, 5, -1]], [[2, 3, -1], [2, -1, -1]]))
# [[0.67857143 0.33633658]
# [0.98795004 0.5 ]]
再對(duì)比一下計(jì)算一個(gè)向量和向量庫(kù)內(nèi)其他所有向量的余弦相似度,使用方法一懈贺,和使用方法二的效率差異经窖,可以遍歷所有向量分別計(jì)算一次和直接點(diǎn)乘向量和矩陣效率相差10倍,具體差異需要看向量長(zhǎng)度和向量數(shù)目
import time
v1 = [1, 2, 3, 5, 7, 6, 2, 5, 9, 10]
v2 = [[2, 5, 1, 8, 4, 1, 1, 3, 1, -5]] * 10000
t1 = time.time()
[get_cos_similar(v1, x) for x in v2]
t2 = time.time()
print(t2- t1) # 0.25322484970092773
t3 = time.time()
get_cos_similar_multi(v1, v2)
t4 = time.time()
print(t4 - t3) # 0.025495529174804688
最后對(duì)比一下兩個(gè)向量庫(kù)兩兩計(jì)算余弦相似度分別使用三個(gè)方法的效率差異梭灿,可見(jiàn)矩陣一次點(diǎn)乘的效率最高画侣,遍歷之后多次點(diǎn)乘的效率最低
v3 = [v1] * 100
v4 = [[2, 5, 1, 8, 4, 1, 1, 3, 1, -5]] * 100
t5 = time.time()
for vv1 in v3:
for vv2 in v4:
get_cos_similar(vv1, vv2)
t6 = time.time()
print(t6 - t5) # 0.2532625198364258
t7 = time.time()
for vv1 in v3:
get_cos_similar_multi(vv1, v4)
t8 = time.time()
print(t8 - t7) # 0.03303122520446777
t9 = time.time()
get_cos_similar_matrix(v3, v4)
t10 = time.time()
print(t10 - t9) # 0.0014848709106445312