简体   繁体   English

使用'None'进行成对运算的numpy索引

[英]numpy indexing using 'None' for pairwise operations

If I had two numpy arrays that looked like this 如果我有两个看起来像这样的numpy数组

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

and I wanted to add all pairwise combinations, I could easily do 我想添加所有成对组合,我可以轻松地做到

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

to get the result of 1+3 , 2+3 and 1+4 , 2+4 . 得到1 + 3,2 + 31 + 4,2 + 4的结果

Why does this work? 为什么这样做? What is 'None' doing? “无”在做什么? I can print out 我可以打印出来

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

But I'm not sure why that tells numpy to do pairwise combos. 但是我不确定为什么告诉numpy做成对组合。 I'm also curious about if it's efficiently implemented under the hood compared to, say, itertools.combinations. 与itertools.combinations相比,我也很好奇它是否在后台有效地实现。

To answer the first part of your question, b[:, None] is a special type of slicing that has identical behavior to b[:, np.newaxis] , in that it adds an axis of length 1 to your array. 为了回答问题的第一部分, b[:, None]是一种特殊的切片方式,其行为与b[:, np.newaxis] ,因为它向数组添加了长度为1的轴。

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

This behavior is documented in the numpy docs [1] , emphasis mine: 此行为记录在numpy docs [1]中 ,重点是:

The newaxis object can be used in all slicing operations to create an axis of length one. newaxis对象可用于所有切片操作中,以创建长度为一的轴。 newaxis is an alias for None , and None can be used in place of this with the same result. newaxisNone的别名,可以使用None代替它,结果相同。

So now we have two arrays: 所以现在我们有两个数组:

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

Summing these two arrays results in: 对这两个数组求和将得出:

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

The "magic" behind this is numpy broadcasting [2] . 其背后的“魔术”是numpy广播[2] This article [3] is an excellent resource for beginning to understand the topic. 本文[3]是开始理解该主题的绝佳资源。


The main takeaways from the article are as follows: 本文的主要内容如下:

numpy operations are usually done element-by-element which requires two arrays to have exactly the same shape. numpy操作通常逐个元素地进行,这需要两个数组具有完全相同的形状。 However, this constraint is relaxed if both arrays have the same trailing axis, or if one of the trailing axes is equal to one (which is the behavior being exhibited in your case). 但是,如果两个数组都具有相同的尾随轴, 或者如果尾随轴之一等于一 (这是您的情况所显示的行为),则可以放宽此约束。

In your case, broadcasting occurs, so the operation is equivalent to summing the following 2x2 arrays: 在您的情况下,发生广播,因此该操作等效于对以下2x2数组求和:

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

Which, since numpy operations are done element-by-element, will produce the desired output of: 由于numpy操作是逐个元素完成的,因此将产生所需的输出:

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

[1] https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#numpy.newaxis [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 [2] https://docs.scipy.org/doc/numpy-1.13.0/user/basics.broadcasting.html

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

What you're doing is adding a new axis: the "column"-axis. 您正在做的是添加一个新轴:“列”轴。 b didn't have that before, so now it's a column vector and would be added column wise; b以前没有,所以现在是列向量,将逐列添加; it will essentially act as if it was repeated in the columns, and a repeated in the rows: 这将从根本上充当如果它是在列重复,并且a在行重复:

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

And here is how/why: 这是如何/为什么:

First things first: numpy does elementwise addition and multiplication by default. 首先, numpy在默认情况下会进行元素加法和乘法。 That means if a=np.array([1,2]) then a+2=np.array([1+2,2+2])=np.array([3,5]) . 这意味着如果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]])

Here A+B would be element wise and we would get 在这里A+B将是元素明智的,我们将得到

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

If we transpose the matrix B (using BT ) 如果我们转置矩阵B (使用BT

now BT would have the value 现在BT将具有价值

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

And if we do it elementwise this time we'd get: 如果这次我们按元素进行操作,则会得到:

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

Another thing to notice is that ( B not transposed) 另一件事要注意的是( B 移调)

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

And it's also elementwise, but on both rows! 而且它也是元素级的,但是在两行上! That is a was practically "repeated" to have two rows, and added elementwise to B . 这是a很实际“重复”有两行,并添加的elementwise到B

Further, Numpy docs says that None , in slicing, is a different way of writing np.newaxis . 此外, Numpy Docs说,切片时None是另一种编写np.newaxis In your case, what the None option in slicing does is basically transposing the b -vector before addition! 在您的情况下,切片中的None选项基本上是在加法之前转置b -vector!

The exact same result could have been obtained by 可以通过以下方法获得完全相同的结果

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]

Here c , d and e have the same values! 这里cde具有相同的值!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM