3

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

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

因此,如果我有一个数组r = [r1, r2, r3]wherer1和是 3 维向量,我想要以下内容r2r3

[[r1-r1 r1-r2 r1-r3]
 [r2-r1 r2-r2 r2-r3]
 [r3-r1 r3-r2 r3-r3]]

-操作按元素应用于向量的位置。

基本上,这个向量等价于:

>>> 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)

我可以在不迭代数组的情况下实现上述目标吗?

4

3 回答 3

3

简短的回答:

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

np.array(map(operator.sub, *zip(*product(r, r)))).reshape((2, 2, -1))

因此,您基本上可以使用该product函数来获取所有可能的列表项对,将zip它们分开以获得两个单独map的列表并将它们用于减法operator。最后你可以reshape像往常一样。

一步步:

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

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]]]

(请注意,我需要切换维度23创建示例数组。)

于 2014-08-23T09:40:44.773 回答
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 的任何二维数组,但我主要是通过反复试验来完成的,所以我不能 100% 确定。

于 2014-08-23T11:21:31.267 回答
3

答案几乎总是广播

>>> r = np.arange(6).reshape(2, 3)
>>> r[:, None] - r
array([[[ 0,  0,  0],
        [-3, -3, -3]],

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

索引中的那个None与 相同np.newaxis,并且在数组的形状上添加一个大小为 1 的维度。因此,您从一个 shape(2, 1, 3)数组中减去一个 shape 数组,该数组(2, 3)通过广播转换为(1, 2, 3),最终结果就是您想要的(2, 2, 3)数组。虽然广播在概念上类似于使用np.tileor np.repeat,但它更有效,因为它避免了创建原始数组的扩展副本。

于 2014-08-23T13:17:24.137 回答