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
转换回方阵格式。
我试图通过应用矢量化来理解 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
转换回方阵格式。