Python:多维数组的元素差异

时间:2017-11-05 21:23:22

标签: python numpy

我试图在两组粒子之间找到minimum image separation。我在每组中有大约40个粒子,它们的位置向量(三维)存储在两个维度(40, 3)的数组中。在应用最小图像标准后,我必须计算一组中粒子的每个之间的欧几里德距离,以及另一组中粒子的每个之间的欧几里德距离。为了使其更清晰,对于两个列表pos1pos2,其坐标为[func(i-j) for i in pos1 for j in pos2],其中func = lambda x: x - np.rint(x/width)*width是一个适用的函数最低标准。

在三个维度中,欧几里德距离为numpy.sqrt(dx**2 + dy**2 + dx**2),其中dxdydzfunc为每个维度返回。

(函数func只是为了演示如何应用最小图像标准。我不使用相同的精确程序结构。)

我正在寻找一种有效的方法,因为我必须在分析多个数据集时执行相同的操作,每个数据集的时间步长大约为 20000 ,每个步骤包含3个每组40个粒子,即每个时间步长计算的 6 组合组合。

谷歌搜索引导我scipy.spatial.distance.cdist,但我在优化计算时间方面遇到了麻烦。内置的距离例程(Euclidean,Minkowski,Manhattan,Chebyshev等)经过优化并运行得非常快(在我下面的测试中高达三个数量级),与作为参数给出的显式函数定义相比较:

In [1]: import numpy as np

In [2]: from scipy.spatial.distance import cdist, euclidean

In [3]: %%timeit
   ...: pos1 = np.random.rand(40, 3)
   ...: pos2 = np.random.rand(40, 3)
   ...: cdist(pos1, pos2, metric='euclidean')
   ...:
The slowest run took 12.46 times longer than the fastest. 
This could mean that an intermediate result is being cached
10000 loops, best of 3: 39.3 µs per loop

In [4]: %%timeit
   ...: pos1 = np.random.rand(40, 3)
   ...: pos2 = np.random.rand(40, 3)
   ...: cdist(pos1, pos2, metric=euclidean)
   ...:
10 loops, best of 3: 43 ms per loop

In [5]: %%timeit
   ...: pos1 = np.random.rand(40, 3)
   ...: pos2 = np.random.rand(40, 3)
   ...: cdist(pos1, pos2, lambda u, v: np.sqrt(((u-v)**2).sum()) )
   ...:
100 loops, best of 3: 15.5 ms per loop

In [6]: width = 1.0

In [7]: func = lambda x: x - np.rint(x/width)*width

In [8]: %%timeit
   ...: pos1 = np.random.rand(40, 3)
   ...: pos2 = np.random.rand(40, 3)
   ...: cdist(pos1, pos2, lambda u, v: np.sqrt(((func(u)-func(v))**2).sum()) )
   ...:
10 loops, best of 3: 31.2 ms per loop

以下是我考虑的选项:

  • 显式循环数组元素并构建所需的数组(可能效率最低)
  • 将数组分成三个x, y, x组件,应用最小图像标准,并使用cdist单独计算每个组件的欧氏距离(因为numpy.sqrt(dx**2) == dx等等),reconstruct {{ 1}}来自组件数组的数组,并重复(40, 3)以计算3D中的距离

计算等效cdist的有效方法是什么?

问题:

是否有任何内置的NumPy函数可以提供等效的cdist(pos1, pos2, lambda u, v: np.sqrt(((func(u)-func(v))**2).sum()) ),但是对于两个数组的指定轴?

我打算实现的示例表示:

[(i-j) for i in pos1 for j in pos2]

(所有值均为 [ a 0 0 ] [ x 0 0 ] A = [ b 0 0 ] ; B = [ y 0 0 ] [ c 0 0 ] [ z 0 0 ] [ a-x 0 0 ] [ a-y 0 0 ] [ a-z 0 0 ] [ b-x 0 0 ] Result = [ b-y 0 0 ] [ b-z 0 0 ] [ c-x 0 0 ] [ c-y 0 0 ] [ c-z 0 0 ] ,并且将对所有列执行操作。)

1 个答案:

答案 0 :(得分:1)

我不确定我是否完全理解你想做什么......如果我有,你可以使用广播做元素差异,见下文

In [24]: a = np.random.random((5,3))
In [25]: b = np.random.random((5,3))
In [26]: c = a[:,None,:]-b
In [27]: c[3,4]
Out[27]: array([ 0.55732535,  0.30270483,  0.48249629])
In [28]: a[3]-b[4]
Out[28]: array([ 0.55732535,  0.30270483,  0.48249629])
In [29]: c[0,3]
Out[29]: array([ 0.28562698,  0.33227255,  0.35890964])
In [30]: a[0]-b[3]
Out[30]: array([ 0.28562698,  0.33227255,  0.35890964])
In [31]: