我正在尝试计算两个数组之间的余弦相似度,但是基本公式略有更改。即,我只关心与“引用”数组重叠的组件。例如,如果我们要计算以下两个数组之间的余弦相似度:
A = [1 0 1] B = [1 1 0]
[0 1 1] [0 1 1]
假设B
是参考数组。然后A
相对于B中的每一行更改,以仅包括与该行重叠的组件。例如,B
中的第一行是[1 1 0]
,因此相似性计算是使用修改后的A矩阵进行的:
[1 0 0]
[0 1 0]
要计算与[0 1 1]
的下一个相似度,修改后的A
变为:
[0 0 1]
[0 1 1]
我的问题是:有没有办法在不显着降低性能的情况下引入这种修改(与sklearn.metrics.pairwise.cosine_similarity
等内置余弦相似度选项相比)?我知道没有什么能像标准的余弦相似度计算那样快,但是现在我尝试引入这种变化的结果导致速度降低了近100倍,因此在此方面的任何改进都将是巨大的。
除了在参考数组中逐行浏览,根据当前行屏蔽另一个数组,然后进行矩阵向量余弦相似度之外,我真的不知道有什么方法可以做到这一点。像这样:
def modified_cosine_sim(arr1, arr2):
# arr2 is reference array
final_arr = []
for row in arr2:
masked_arr1 = arr1 * np.where(row > 0, 1, 0)
final_arr.append(cosine_similarity(masked_arr1, row))
return final_arr
但是,这效率很低。我检查了是否有某种巧妙的方法来修改sklearn cosine_similarity
代码以实现此处的目标,但是该代码依赖于在进行计算之前对两个数组进行归一化,而我确实不能做到这一点-{ {1}}有效地改变了整个计算过程,具体取决于arr1
中当前用于计算相似度的行。
我必须在稍大的数组上重复运行此计算,因此,非常感谢任何优化技巧。或者,如果此计算对应于我不熟悉的一些已经优化的内置函数,那会更好。谢谢!
答案 0 :(得分:1)
以下内容主要使用矩阵乘法来实现修改后的公式。
def modified_similarity(a,b):
bc = np.maximum(b,0)/np.linalg.norm(b,axis=1,keepdims=True)
return a@bc.T/np.sqrt(np.square(a)@np.sign(bc).T)
答案 1 :(得分:0)
我相信以下代码和您的函数modified_cosine_sim
是等效的。
def faster_cosine_sim(arr1, arr2):
return cosine_similarity(arr1 * np.where(arr2 > 0, 1, 0), arr2)