28

I have the following 2D-array:

a = array([[ 1,  2,  3],
           [ 4,  5,  6],
           [ 7,  8,  9],
           [10, 11, 12],
           [13, 14, 15]])

and another 1D-array:

b = array([ 1,  2,  3,  4,  5])

then I want to calculate something like

c = a - b

with the intent of getting:

c = array([[0, 1,  2],
           [2, 3,  4],
           [4, 5,  6],
           [6, 7,  8],
           [8, 9, 10]])

but instead I get the error message:

Traceback (most recent call last):
  Python Shell, prompt 79, line 1
ValueError: operands could not be broadcast together with shapes (5,3) (5,)

I read the broadcasting rules but didn´t get any wiser. I could do a workaround with for-loops or similar but there should be a direct way. Thanks

leofields
  • 659
  • 1
  • 7
  • 12

2 Answers2

33

You need to convert array b to a (2, 1) shape array, use None or numpy.newaxis in the index tuple. Here is the Indexing of Numpy array.

You can do it Like:

import numpy

a = numpy.array([[ 1,  2,  3],
           [ 4,  5,  6],
           [ 7,  8,  9],
           [10, 11, 12],
           [13, 14, 15]])

b = numpy.array([ 1,  2,  3,  4,  5])
c=a - b[:,None]
print c

Output:

Out[2]: 
array([[ 0,  1,  2],
       [ 2,  3,  4],
       [ 4,  5,  6],
       [ 6,  7,  8],
       [ 8,  9, 10]])
Sakib Ahammed
  • 2,452
  • 2
  • 25
  • 29
  • @Sakib, I am able to do this without any conversion and it's confusing me. I have `A.shape = (100,1)` and `B.shape = (100)` and when I do `A-B` I get `C` of shape `(100,100`. What is going on? – mLstudent33 Aug 10 '19 at 11:35
3

As Divakar specified in the comments, just add a new axis to b.

I suggest you read more about broadcasting which is very often useful to vectorize computations in numpy: interestingly enough, a.transpose() - b wouldn't have raised an error (you'd need to transpose the result again to obtain your desired output).

In this computaion, the first array's shape is (3, 5), and b.shape is (5,). So the shape of b corresponds to the tail of the shape of a, and broadcasting can happen. This is not the case when the shape of the first array is (5, 3), hence the error you obtained.

Here are some runtime tests to compare the speeds of the suggested answers, with your values for a and b : you can see that the differences are not really significant

In [9]: %timeit (a.T - b).T
Out[9]: 1000000 loops, best of 3: 1.32 µs per loop

In [10]: %timeit a - b[:,None]
Out[10]: 1000000 loops, best of 3: 1.25 µs per loop

In [11]: %timeit a - b[None].T
Out[11]: 1000000 loops, best of 3: 1.3 µs per loop
P. Camilleri
  • 12,664
  • 7
  • 41
  • 76
  • `a.transpose() - b` would require another transpose to get the desired output, right? – Divakar Oct 23 '15 at 13:38
  • @Divakar Yes, yes, I'm not proposing a solution, I'm explicitly telling to use yours. Since your solution was a comment, I added the reason why broadcasting didn't work. If you'd posted an answer, I'd have commented it. – P. Camilleri Oct 23 '15 at 13:40
  • I was stating for the purpose of completeness of this post on how to get to the desired output and shape :) – Divakar Oct 23 '15 at 13:44
  • Or another way would be `a - b[None].T`? Quick runtime tests show this to be marginal better than `[:,None]` and I wasn't expecting this. But make sure to test it out at your end if you are incorporating runtime tests, but definitely worth checking out! – Divakar Oct 23 '15 at 14:02
  • Actually that "marginal" thing is really marginal and goes either way across many runs, but nevertheless those runtime tests might be of some interest somewhere. – Divakar Oct 23 '15 at 14:08
  • It's not interestingly... it's sadly indeed. Numpy is using som idoitic assumptions and notations about vectors and that's probabaly to gain some performance. If anyone has ever worked with Matlab and implements plenty of linear algebra in their work would realize how awkward numpy's notations and assumptions are. – Ash Apr 13 '23 at 03:13