使用 'None' 进行成对操作的 numpy 索引

numpy indexing using 'None' for pairwise operations

如果我有两个像这样的 numpy 数组

a = np.array([1, 2])
b = np.array([3, 4])

我想添加所有成对组合,我可以轻松做到

c = a + b[:, None]
c
array([[4, 5],
       [5, 6]])

得到1+32+31+4[=28=的结果], 2+4

为什么这样做? 'None' 在做什么?我可以打印出来

b[:, None]
[[3]
 [4]]

但我不确定为什么这会告诉 numpy 进行成对组合。我也很好奇,与 itertools.combinations.

相比,它是否在幕后有效实施

您正在做的是添加一个新轴:"column" 轴。 b 以前没有,所以现在它是一个列向量,将按列添加;它基本上就像在列中重复,并且 a 在行中重复一样:

a+b[:, None] = [1,2] + [[3], = [[1,2], + [[3],[3],
                        [4]]    [1,2]]    [4],[4]]

这里是 how/why:

首先要做的事情是:numpy 默认情况下进行元素加法和乘法。这意味着如果 a=np.array([1,2]) 那么 a+2=np.array([1+2,2+2])=np.array([3,5]).

import numpy as np
A = np.array([[1, 2],
              [3, 4]])
B = np.array([[1,1],
              [0,0]])

这里 A+B 是元素明智的,我们会得到

A+B = [[1+1,2+1], = [[2,3],
       [3+0,4+0]] =  [3,4]]

如果我们转置矩阵 B(使用 B.T

现在 B.T 将具有值

B.T= np.array([[1,0],
               [1,0]])

如果我们这次按元素来做,我们会得到:

A+B.T=[[1, 2]  + [[1,0]  =  [[2,2],
       [3, 4]]    [1,0]]     [4,4]]

另外要注意的是(B 不是转置)

a = np.array([1,2])
B+a = [[1,2], + [[2, 3],
       [1,2]]    [1, 2]]

它也是按元素排列的,但是在两行上!也就是说 a 实际上是 "repeated" 有两行,并且按元素添加到 B.

此外,Numpy docs表示None,在切片中,是另一种写法np.newaxis。在您的情况下,切片中的 None 选项基本上是在添加之前转置 b-向量!

可以获得完全相同的结果
import numpy as np
a = np.array([1, 2])
b = np.array([3, 4])

c=a+b.reshape(2,1)
d=a+b.reshape(-1,1)
e=a+b[:, np.newaxis]

此处cde的值相同!

要回答您问题的第一部分,b[:, None] 是一种特殊类型的切片,其行为与 b[:, np.newaxis] 相同,因为它将长度为 1 的轴添加到您的数组中。

>>> b.shape
(2,)
>>> b[:, None].shape
(2, 1)

此行为记录在 numpy docs [1] 中,强调我的:

The newaxis object can be used in all slicing operations to create an axis of length one. newaxis is an alias for None, and None can be used in place of this with the same result.

所以现在我们有两个数组:

array([1, 2]) + array([[3],
                       [4]])

将这两个数组相加得到:

array([[4, 5],
       [5, 6]])

这背后的 "magic" numpy broadcasting[2]. This article [3] 是开始理解该主题的极好资源。


文章的主要内容如下:

numpy 操作通常逐个元素地完成,这需要两个数组具有完全相同的形状。但是,如果两个数组具有相同的尾轴 或者其中一个尾轴等于一个 (这是在你的案例中表现出的行为)。

在您的例子中,发生了广播,因此该操作等效于对以下 2x2 数组求和:

array([[1, 2],    +  array([[3, 3],
       [1, 2]])            [4, 4]])

由于 numpy 操作是逐个元素完成的,因此将产生所需的输出:

array([[4, 5],
       [5, 6]])

[1]https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#numpy.newaxis

[2]https://docs.scipy.org/doc/numpy-1.13.0/user/basics.broadcasting.html

[3]http://scipy.github.io/old-wiki/pages/EricsBroadcastingDoc