不同形状数组的Numpy距离计算
Numpy distance calculations of different shaped arrays
不确定我的标题是否合适,但基本上我有一个参考坐标,格式为 (x,y,z),还有大量 list/array 坐标也采用该格式。我需要得到每个之间的欧几里德距离,所以理论上我应该能够使用 numpy 和 scipy 进行如下操作:
import numpy, scipy.spatial.distance
a = numpy.array([1,1,1])
b = numpy.random.rand(20,3)
distances = scipy.spatial.distance.euclidean(b, a)
但是我没有取回数组,而是收到错误消息:ValueError: Input vector should be 1-D.
不确定如何解决这个错误并获得我想要的东西而不必诉诸循环等,这有点违背了使用 Numpy 的目的。
从长远来看,我想使用这些距离来计算真值掩码以计算 bin 中的距离值。
我不确定我只是使用了错误的功能还是使用了错误的功能,我在文档中找不到任何可以更好地工作的内容。
scipy.spatial.distance.euclidean
的 documentation 指出,仅允许一维向量作为输入。因此,您必须像这样遍历数组:
distances = np.empty(b.shape[0])
for i in range(b.shape[0]):
distances[i] = scipy.spatial.distance.euclidean(a, b[i])
如果你想有一个向量化的实现,你需要自己写一个函数。也许使用带有正确签名的 np.vectorize
也可以,但这实际上也只是 for 循环的简写形式,因此具有与简单 for 循环相同的性能。
正如我在对 hannes wittingham 的解决方案的评论中所述,我将 post 一个专注于性能的单行代码:
distances = ((b - a)**2).sum(axis=1)**0.5
写出所有计算可减少单独函数调用的次数,从而减少将中间结果分配给新数组的次数。因此,对于 b.shape == (20, 3)
的阵列形状,它比使用 hannes wittingham 的解决方案快约 22%,对于阵列形状的阵列形状快约 5%
b.shape == (20000, 3)
:
a = np.array([1, 1, 1,])
b = np.random.rand(20, 3)
%timeit ((b - a)**2).sum(axis=1)**0.5
# 5.37 µs ± 140 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit euclidean_distances(a, b)
# 6.89 µs ± 345 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
b = np.random.rand(20000, 3)
%timeit ((b - a)**2).sum(axis=1)**0.5
# 588 µs ± 43.2 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit euclidean_distances(a, b)
# 616 µs ± 36.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
但是您正在失去能够轻松更改为距离计算例程的灵活性。使用scipy.spatial.distance
模块时,只需调用另一个方法即可更改计算路由。
为了进一步提高计算性能,您可以为您的函数使用像 numba
这样的 jit(即时)编译器:
import numba as nb
@nb.njit
def euc(a, b):
return ((b - a)**2).sum(axis=1)**0.5
这将小型阵列的计算时间减少了大约 70%,大型阵列的计算时间减少了大约 60%。不幸的是,np.linalg.norm
的 axis
关键字尚未被 numba
支持。
编写自己的函数来执行此操作实际上并不难 - 这是我的函数,欢迎您使用。
如果您在大量点和速度问题上执行此操作,我猜这个函数将在很长一段时间内击败基于 for-loop 的速度解决方案 - numpy 被设计为在携带时高效out 对整个矩阵的操作。
import numpy
a = numpy.array([1,1,1])
b = numpy.random.rand(20,3)
def euclidean_distances(ref_point, co_ords_array):
diffs = co_ords_array - ref_point
sqrd_diffs = numpy.square(diffs)
sum_sqrd_diffs = numpy.sum(sqrd_diffs, axis = 1)
euc_dists = numpy.sqrt(sum_sqrd_diffs)
return euc_dists
此代码将获得欧几里德范数,它在许多情况下都应该有效,而且速度相当快,而且只需要一行代码。根据需要,其他方法更有效或更灵活,我更喜欢根据正在完成的工作发布的其他一些解决方案。
import numpy
a = numpy.array([1,1,1])
b = numpy.random.rand(20,3)
distances = numpy.linalg.norm(a - b, axis = 1)
注意 a
定义中多出的一组 []
import numpy, scipy.spatial.distance
a = numpy.array([[1,1,1]])
b = numpy.random.rand(20,3)
distances = scipy.spatial.distance.cdist(b, a, metric='euclidean')
不确定我的标题是否合适,但基本上我有一个参考坐标,格式为 (x,y,z),还有大量 list/array 坐标也采用该格式。我需要得到每个之间的欧几里德距离,所以理论上我应该能够使用 numpy 和 scipy 进行如下操作:
import numpy, scipy.spatial.distance
a = numpy.array([1,1,1])
b = numpy.random.rand(20,3)
distances = scipy.spatial.distance.euclidean(b, a)
但是我没有取回数组,而是收到错误消息:ValueError: Input vector should be 1-D.
不确定如何解决这个错误并获得我想要的东西而不必诉诸循环等,这有点违背了使用 Numpy 的目的。
从长远来看,我想使用这些距离来计算真值掩码以计算 bin 中的距离值。
我不确定我只是使用了错误的功能还是使用了错误的功能,我在文档中找不到任何可以更好地工作的内容。
scipy.spatial.distance.euclidean
的 documentation 指出,仅允许一维向量作为输入。因此,您必须像这样遍历数组:
distances = np.empty(b.shape[0])
for i in range(b.shape[0]):
distances[i] = scipy.spatial.distance.euclidean(a, b[i])
如果你想有一个向量化的实现,你需要自己写一个函数。也许使用带有正确签名的 np.vectorize
也可以,但这实际上也只是 for 循环的简写形式,因此具有与简单 for 循环相同的性能。
正如我在对 hannes wittingham 的解决方案的评论中所述,我将 post 一个专注于性能的单行代码:
distances = ((b - a)**2).sum(axis=1)**0.5
写出所有计算可减少单独函数调用的次数,从而减少将中间结果分配给新数组的次数。因此,对于 b.shape == (20, 3)
的阵列形状,它比使用 hannes wittingham 的解决方案快约 22%,对于阵列形状的阵列形状快约 5%
b.shape == (20000, 3)
:
a = np.array([1, 1, 1,])
b = np.random.rand(20, 3)
%timeit ((b - a)**2).sum(axis=1)**0.5
# 5.37 µs ± 140 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit euclidean_distances(a, b)
# 6.89 µs ± 345 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
b = np.random.rand(20000, 3)
%timeit ((b - a)**2).sum(axis=1)**0.5
# 588 µs ± 43.2 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit euclidean_distances(a, b)
# 616 µs ± 36.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
但是您正在失去能够轻松更改为距离计算例程的灵活性。使用scipy.spatial.distance
模块时,只需调用另一个方法即可更改计算路由。
为了进一步提高计算性能,您可以为您的函数使用像 numba
这样的 jit(即时)编译器:
import numba as nb
@nb.njit
def euc(a, b):
return ((b - a)**2).sum(axis=1)**0.5
这将小型阵列的计算时间减少了大约 70%,大型阵列的计算时间减少了大约 60%。不幸的是,np.linalg.norm
的 axis
关键字尚未被 numba
支持。
编写自己的函数来执行此操作实际上并不难 - 这是我的函数,欢迎您使用。
如果您在大量点和速度问题上执行此操作,我猜这个函数将在很长一段时间内击败基于 for-loop 的速度解决方案 - numpy 被设计为在携带时高效out 对整个矩阵的操作。
import numpy
a = numpy.array([1,1,1])
b = numpy.random.rand(20,3)
def euclidean_distances(ref_point, co_ords_array):
diffs = co_ords_array - ref_point
sqrd_diffs = numpy.square(diffs)
sum_sqrd_diffs = numpy.sum(sqrd_diffs, axis = 1)
euc_dists = numpy.sqrt(sum_sqrd_diffs)
return euc_dists
此代码将获得欧几里德范数,它在许多情况下都应该有效,而且速度相当快,而且只需要一行代码。根据需要,其他方法更有效或更灵活,我更喜欢根据正在完成的工作发布的其他一些解决方案。
import numpy
a = numpy.array([1,1,1])
b = numpy.random.rand(20,3)
distances = numpy.linalg.norm(a - b, axis = 1)
注意 a
[]
import numpy, scipy.spatial.distance
a = numpy.array([[1,1,1]])
b = numpy.random.rand(20,3)
distances = scipy.spatial.distance.cdist(b, a, metric='euclidean')