关于numpy:Python:多维数组的元素差异

Python: Elementwise difference for multidimensional array

我试图找到两组粒子之间的最小图像分离。每个集合中大约有40个粒子,它们的位置向量(三维)存储在两个一维数组中。在应用了最小图像准则之后,我必须计算一组中每个粒子和另一组中每个粒子之间的欧几里得距离。为了更清楚地说明这一点,对于坐标为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组组合。

googling让我找到了scipy.spatial.distance.cdist,但我无法优化计算时间。与作为参数给出的显式函数定义相比,用于距离的内置例程(欧几里得、明可夫斯基、曼哈顿、切比雪夫等)进行了优化并运行得相当快(在下面的测试中,最多达到三个数量级):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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等),从分量阵列中重建(40, 3)阵列,并重复cdist。用于计算三维距离
  • 小精灵

    计算cdist(pos1, pos2, lambda u, v: np.sqrt(((func(u)-func(v))**2).sum()) )等价物的有效方法是什么?

    问题:

    除了两个数组的指定轴之外,是否有任何内置的numpy函数可以给出等效的[(i-j) for i in pos1 for j in pos2]

    我想要达到的目标的一个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        [ 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 ]

    (所有值都是float,所有列都要进行操作。)


    我不确定我完全理解你想做什么…如果有的话,你可以用广播来做元素上的区别,见下面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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]: