Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

numpy indexing using 'None' for pairwise operations

If I had two numpy arrays that looked like this

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.

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. I'm also curious about if it's efficiently implemented under the hood compared to, say, itertools.combinations.

like image 820
Alex Gao Avatar asked Aug 07 '26 21:08

Alex Gao


1 Answers

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.shape
(2,)
>>> b[:, None].shape
(2, 1)

This behavior is documented in the numpy docs [1], emphasis mine:

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.

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]. This article [3] is an excellent resource for beginning to understand the topic.


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. 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:

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:

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

like image 142
user3483203 Avatar answered Aug 09 '26 12:08

user3483203



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!