修正的余弦相似度效率

时间:2019-10-15 05:05:47

标签: python arrays numpy scikit-learn scipy

问题

我正在尝试计算两个数组之间的余弦相似度,但是基本公式略有更改。即,我只关心与“引用”数组重叠的组件。例如,如果我们要计算以下两个数组之间的余弦相似度:

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中当前用于计算相似度的行。

我必须在稍大的数组上重复运行此计算,因此,非常感谢任何优化技巧。或者,如果此计算对应于我不熟悉的一些已经优化的内置函数,那会更好。谢谢!

2 个答案:

答案 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)