![](/img/trans.png)
[英]Compute cosine similarity between 3D numpy array and 2D numpy array
[英]Efficient way to compute cosine similarity between 1D array and all rows in a 2D array
我有形状的一个一维数组(300, )
和形状的2D阵列(400, 300)
现在,我想计算此2D数组中的每一行与1D数组之间的余弦相似度。 因此,我的结果应该是形状(400, )
,它表示这些向量有多相似。
我最初的想法是使用for
循环遍历2D数组中的行,然后计算向量之间的余弦相似度。 使用广播方法是否有更快的选择?
这是一个人为的示例:
In [29]: vec = np.random.randn(300,)
In [30]: arr = np.random.randn(400, 300)
下面是我要计算一维数组之间相似度的方法:
inn = (vec * arr[0]).sum()
vecnorm = numpy.sqrt((vec * vec).sum())
rownorm = numpy.sqrt((arr[0] * arr[0]).sum())
similarity_score = inn / vecnorm / rownorm
如何将其概括为arr[0]
被2D数组替换?
cos相似性的分子可以表示为一个矩阵乘法,然后分母应该可以工作了:)。
a_norm = np.linalg.norm(a, axis=1)
b_norm = np.linalg.norm(b)
(a @ b) / (a_norm * b_norm)
其中a
是2D数组, b
是1D数组(即矢量)
以下是与@Bi Rico's post
相同的方法,但是使用einsum
进行norm
计算-
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.