"outer" in python 类似于 Mathematica

"outer" in python similar to Mathematica

我有一些粒子的二维位置 (x,y) 数组。在 Mathematica 中,我可以使用 Outer[Subtract, pos, pos, 1] 如果 pos 是形状为 (n,2) 的数组,其中 n 是粒子数,则上述 Mathematia 代码的结果是 n x n x 2 数组,每个 [i,j]该矩阵的元素是 (x_i - x_j, y_i - y_j) 运算的结果。

例如

pos = {{x1, y1}, {x2, y2}, {x3, y3}};
Outer[Subtract, pos, pos, 1]

给予

{
 {{0, 0}, {x1 - x2, y1 - y2}, {x1 - x3, y1 - y3}}
 ,
 {{-x1 + x2, -y1 + y2}, {0, 0}, {x2 - x3, y2 - y3}}
 ,
 {{-x1 + x3, -y1 + y3}, {-x2 + x3, -y2 + y3}, {0, 0}}
}

这是一个 3x3x2 数组。但是,在 python 中我无法得到类似的结果:

import numpy as np
pos = [[1, 2], [5, 6], [8, 9]]
print (np.subtract.outer(pos, pos).shape)

给出(3, 2, 3, 2),而np.subtract.outer(pos, pos)

array([[[[ 0, -1],
     [-4, -5],
     [-7, -8]],

    [[ 1,  0],
     [-3, -4],
     [-6, -7]]],


   [[[ 4,  3],
     [ 0, -1],
     [-3, -4]],

    [[ 5,  4],
     [ 1,  0],
     [-2, -3]]],


   [[[ 7,  6],
     [ 3,  2],
     [ 0, -1]],

    [[ 8,  7],
     [ 4,  3],
     [ 1,  0]]]])

而对于类似的值,Mathemtica 代码给出了我所需要的,即

{
{{0, 0}, {-4, -4}, {-7, -7}}
,
{{4, 4}, {0, 0}, {-3, -3}}
, 
{{7, 7}, {3, 3}, {0, 0}}
}

numpy.ufunc.outer(a,b) 将使用 a 中的一个元素和 b 中的另一个元素计算每个可能的组合。一种选择是分别计算 x 和 y 坐标,然后重新合并 result:

pos = np.array([[1, 2], [5, 7], [8, 13]])
dx = np.subtract.outer(pos[:,0],pos[:,0])
dy = np.subtract.outer(pos[:,1],pos[:,1])
result=np.transpose([dx,dy], axes=(1,2,0))

(我更改了 pos 中的值,使结果不那么对称。)

编辑:与通过对整个数组执行 subtract.outer 然后在之后使用 squeeze 来计算和存储无用的 x_i-y_j 相比,此解决方案对于大型数组更有效。

您正在寻找:

pos = np.array(pos)

pos[:,None]-pos

您也可以通过以下方式实现同​​样的效果:

np.squeeze([i-pos for i in pos]) 

编辑:

为了归一化,你可以这样做:

ss = np.linalg.norm(pos_diff,axis = 2,keepdims = True)
ss[ss==0] = 1

pos_diff/ss