Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 计算一维数组和二维数组中所有行之间余弦相似性的有效方法_Python_Arrays_Numpy_Cosine Similarity - Fatal编程技术网

Python 计算一维数组和二维数组中所有行之间余弦相似性的有效方法

Python 计算一维数组和二维数组中所有行之间余弦相似性的有效方法,python,arrays,numpy,cosine-similarity,Python,Arrays,Numpy,Cosine Similarity,我有一个1D形状数组(300,)和一个2D形状数组(400300)。现在,我想计算这个二维数组中每一行与一维数组之间的余弦相似性。因此,我的结果应该是形状(400,),表示这些向量有多相似 我最初的想法是使用for循环遍历2D数组中的行,然后计算向量之间的余弦相似性。是否有一种使用广播方法的更快的替代方案 下面是一个人为的例子: In [29]: vec = np.random.randn(300,) In [30]: arr = np.random.randn(400, 300) 下面是我想

我有一个1D形状数组
(300,)
和一个2D形状数组
(400300)
。现在,我想计算这个二维数组中每一行与一维数组之间的余弦相似性。因此,我的结果应该是形状
(400,)
,表示这些向量有多相似

我最初的想法是使用
for
循环遍历2D数组中的行,然后计算向量之间的余弦相似性。是否有一种使用广播方法的更快的替代方案

下面是一个人为的例子:

In [29]: vec = np.random.randn(300,)
In [30]: arr = np.random.randn(400, 300)
下面是我想要计算1D阵列之间相似性的方法:

inn = (vec * arr[0]).sum()  
vecnorm = numpy.sqrt((vec * vec).sum())  
rownorm = numpy.sqrt((arr[0] * arr[0]).sum())  
similarity_score = inn / vecnorm / rownorm  
我如何将其推广到被2D数组替换的arr[0]。

您可以使用:

输出

(1, 400)

请注意,
cdist
返回
余弦距离
(更多),即
1-余弦相似性
,因此需要转换结果。

余弦相似性的分子可以表示为矩阵乘法,然后分母应该只起作用:)


其中,
a
是2D数组,
b
是1D数组(即向量)

对于
norm
计算,这里有一个方法与使用相同,但使用
einsum
-

den = np.sqrt(np.einsum('ij,ij->i',arr,arr)*np.einsum('j,j',vec,vec))
out = arr.dot(vec) / den
此外,我们可以使用
vec.dot(vec)
来代替
np.einsum('j,j',vec,vec)
,以获得一些细微的改进

时间安排-

In [45]: vec = np.random.randn(300,)
    ...: arr = np.random.randn(400, 300)

# @Bi Rico's soln with norm
In [46]: %timeit (np.linalg.norm(arr, axis=1) * np.linalg.norm(vec))
10000 loops, best of 3: 100 µs per loop

In [47]: %timeit np.sqrt(np.einsum('ij,ij->i',arr,arr)*np.einsum('j,j',vec,vec))
10000 loops, best of 3: 77.4 µs per loop
在更大的阵列上-

In [48]: vec = np.random.randn(3000,)
    ...: arr = np.random.randn(4000, 3000)

In [49]: %timeit (np.linalg.norm(arr, axis=1) * np.linalg.norm(vec))
10 loops, best of 3: 22.2 ms per loop

In [50]: %timeit np.sqrt(np.einsum('ij,ij->i',arr,arr)*np.einsum('j,j',vec,vec))
100 loops, best of 3: 8.18 ms per loop

你的产出是多少(300,)?如果你有400个向量要“测试”,那么你的输出将是(400,),一个简单的点积就可以了…@Julien感谢你发现了这个错误。你的余弦相似性计算是什么?您可以给我们一个完整的数组示例,如(4,3)和(3,)形状。@hpaulj用这些细节更新了问题。请检查!对于两个2D阵列的通用解决方案,请参阅我的另一篇文章。这种方法比使用scipy的
cdist
的方法快10倍。
In [45]: vec = np.random.randn(300,)
    ...: arr = np.random.randn(400, 300)

# @Bi Rico's soln with norm
In [46]: %timeit (np.linalg.norm(arr, axis=1) * np.linalg.norm(vec))
10000 loops, best of 3: 100 µs per loop

In [47]: %timeit np.sqrt(np.einsum('ij,ij->i',arr,arr)*np.einsum('j,j',vec,vec))
10000 loops, best of 3: 77.4 µs per loop
In [48]: vec = np.random.randn(3000,)
    ...: arr = np.random.randn(4000, 3000)

In [49]: %timeit (np.linalg.norm(arr, axis=1) * np.linalg.norm(vec))
10 loops, best of 3: 22.2 ms per loop

In [50]: %timeit np.sqrt(np.einsum('ij,ij->i',arr,arr)*np.einsum('j,j',vec,vec))
100 loops, best of 3: 8.18 ms per loop