Numpy 中坐标距离的矢量化

Vectorisation of coordinate distances in Numpy

我试图通过应用矢量化来理解 Numpy。我试图找到最快的功能来做到这一点。

def get_distances3(coordinates):
    return np.linalg.norm(
        coordinates[:, None, :] - coordinates[None, :, :],
        axis=-1)
coordinates = np.random.rand(1000, 3)
%timeit get_distances3(coordinates)

上面的函数进行了 10 次循环,最好是 3 次循环:每次循环 35.4 毫秒。在 numpy 库中还有一个 np.vectorize 选项可以做到这一点。

def get_distances4(coordinates):
  return np.vectorize(coordinates[:, None, :] - coordinates[None, :, :],axis=-1)

%timeit get_distances4(coordinates)

我尝试使用下面的 np.vectorize,但最终出现以下错误。

TypeError: __init__() 得到了一个意外的关键字参数 'axis'

如何在 get_distances4 中找到矢量化?我应该如何编辑 lsat 代码以避免错误?我从未使用过 np.vectorize,所以我可能会遗漏一些东西。

您没有正确调用 np.vectorize()。我建议参考 the documentation.

Vectorize 将一个函数作为其参数,该函数被编写为对标量值进行操作,并将其转换为一个可以根据 Numpy 广播规则对数组中的值进行矢量化。它基本上就像 Numpy 数组的奇特 map()

即如您所知,Numpy 已经内置了许多常用函数的矢量化版本,但是如果您有一些自定义函数,例如 "my_special_function(x)" 并且您希望能够在 Numpy 数组上调用它,您可以使用 my_special_function_ufunc = np.vectorize(my_special_function) .

在您上面的示例中,您可能 "vectorize" 您的距离函数如下:

>>> norm = np.linalg.norm
>>> get_distance4 = np.vectorize(lambda a, b: norm(a - b))
>>> get_distance4(coordinates[:, None, :], coordinates[None, :, :])

但是,您会发现这非常慢:

>>> %timeit get_distance4(coordinates[:, None, :], coordinates[None, :, :])
1 loop, best of 3: 10.8 s per loop

这是因为您的第一个示例 get_distance3 已经在使用 Numpy 的内置快速实现这些操作,而 np.vectorize 版本需要调用 Python 函数我定义了一些 3000次。

事实上根据文档:

The vectorize function is provided primarily for convenience, not for performance. The implementation is essentially a for loop.

如果你想要一个可能更快的函数来转换向量之间的距离,你可以使用 scipy.spacial.distance.pdist:

>>> %timeit get_distances3(coordinates)
10 loops, best of 3: 24.2 ms per loop
>>> %timeit distance.pdist(coordinates)
1000 loops, best of 3: 1.77 ms per loop

值得注意的是,这有一个不同的 return 阵型。它不是 1000x1000 数组,而是使用压缩格式,不包括 i = j 条目和 i > j 条目。如果您愿意,可以使用 scipy.spatial.distance.squareform 转换回方阵格式。