Python 使用numpy获取三维空间中所有对象相对于彼此的位置

Python 使用numpy获取三维空间中所有对象相对于彼此的位置,python,arrays,numpy,vector,array-broadcasting,Python,Arrays,Numpy,Vector,Array Broadcasting,我想得到numpy数组中向量对的所有排列之间的差异 在我的特定用例中,这些向量是对象列表的3D位置向量 因此,如果我有一个数组r=[r1,r2,r3],其中r1,r2和r3是三维向量,我想要以下内容: [[r1-r1 r1-r2 r1-r3] [r2-r1 r2-r2 r2-r3] [r3-r1 r3-r2 r3-r3]] 其中,-op按元素应用于向量 基本上,向量等价于: >>> scalars = np.arange(3) >>> print(sca

我想得到numpy数组中向量对的所有排列之间的差异

在我的特定用例中,这些向量是对象列表的3D位置向量

因此,如果我有一个数组
r=[r1,r2,r3]
,其中
r1
r2
r3
是三维向量,我想要以下内容:

[[r1-r1 r1-r2 r1-r3]
 [r2-r1 r2-r2 r2-r3]
 [r3-r1 r3-r2 r3-r3]]
其中,
-
op按元素应用于向量

基本上,向量等价于:

>>> scalars = np.arange(3)
>>> print(scalars)
[0 1 2]

>>> result = np.subtract.outer(scalars, scalars)
>>> print(result)
[[ 0 -1 -2]
 [ 1  0 -1]
 [ 2  1  0]]
然而,
outer
函数似乎在减法之前将向量数组展平,然后对其进行整形。例如:

>>> vectors = np.arange(6).reshape(2, 3) # Two 3-dimensional vectors
>>> print(vectors)
[[0 1 2]
 [3 4 5]]

>>> results = np.subtract.outer(vectors, vectors)
>>> print(results.shape)
(2, 3, 2, 3)
我期待的结果是:

>>> print(result)
[[[ 0  0  0]
  [-3 -3 -3]]
 [[ 3  3  3]
  [ 0  0  0]]]

>>> print(result.shape)
(2, 2, 3)

我能在不迭代数组的情况下实现上述功能吗?

简短回答:

对向量
r
执行“成对外部减法”的(几乎)纯Python方法如下:

np.array(map(operator.sub,*zip(*product(r,r)))。重塑((2,2,-1))
因此,您基本上可以使用
product
函数获取所有可能的列表项对,取消
zip
它们以获得两个单独的列表,并
将它们映射到减法
操作符
。最后,您可以像往常一样重塑它

一步一步:

下面是一个分步示例,包含所有必需的库和中间结果的输出:

import numpy as np
from itertools import product
import operator

r = np.arange(6).reshape(2, 3)

print "Vectors:\n", r
print "Product:\n", list(product(r, r))
print "Zipped:\n", zip(*product(r, r))
print "Mapped:\n", map(operator.sub, *zip(*product(r, r)))
print "Reshaped:\n", np.array(map(operator.sub, *zip(*product(r, r)))).reshape((2, 2, -1))
输出:

Vectors:
[[0 1 2]
 [3 4 5]]
Product:
[(array([0, 1, 2]), array([0, 1, 2])), (array([0, 1, 2]), array([3, 4, 5])), (array([3, 4, 5]), array([0, 1, 2])), (array([3, 4, 5]), array([3, 4, 5]))]
Zipped:
[(array([0, 1, 2]), array([0, 1, 2]), array([3, 4, 5]), array([3, 4, 5])), (array([0, 1, 2]), array([3, 4, 5]), array([0, 1, 2]), array([3, 4, 5]))]
Mapped:
[array([0, 0, 0]), array([-3, -3, -3]), array([3, 3, 3]), array([0, 0, 0])]
Reshaped:
[[[ 0  0  0]
  [-3 -3 -3]]

 [[ 3  3  3]
  [ 0  0  0]]]
(注意,为了创建示例数组,我需要切换维度
2
3

(在这里回答我自己的问题)

下面是一种使用Numpy的方法:

import numpy as np

N = 2
r = np.arange(N * 3).reshape(N, 3)

left = np.tile(r, N).reshape(N, N, 3)
right = np.transpose(left, axes=[1, 0, 2])

result = left - right
print result

这似乎适用于任何内部尺寸为3的2D阵列,但我主要是通过反复试验来实现的,所以我不能100%确定。

答案几乎总是:


索引中的
None
np.newaxis
相同,并将大小为1的维度添加到数组的形状中。因此,您从一个形状
(2,1,3)
数组中减去一个形状
(2,3)
的数组,该数组通过广播转换为
(1,2,3)
,最终结果是所需的
(2,2,3)
数组。虽然广播在概念上类似于使用
np.tile
np.repeat
,但它效率更高,因为它可以避免创建原始阵列的扩展副本。

谢谢,我修复了代码中的2和3。我希望能有更“裸体”的东西。我意识到这可能是过早的优化,但在这种情况下,numpy这样的数字库也应该具有可读性更强的代码的优势。你的阵法fu比我的阵法fu强得多-你能建议对我刚才添加的答案进行改进吗?哦,这是一个很好的方法。不知何故,我试图避免努比,但我不知道为什么!我只想把这一行写得更一般一点,如
left=np.tile(r,len(r))。重塑(len(r),len(r),-1)
。(
-1
告诉
重塑
以计算该维度本身。)非常好。我希望看到正确使用广播的东西。我仍然在为广播n维阵列绞尽脑汁。如果这只是一个需要学习的问题,请忘记下面的评论。但如果您确实需要有效地计算所有可能的距离,并且可以使用scipy,请签出
pdist
>>> r = np.arange(6).reshape(2, 3)
>>> r[:, None] - r
array([[[ 0,  0,  0],
        [-3, -3, -3]],

       [[ 3,  3,  3],
        [ 0,  0,  0]]])