Suhail Gupta
Suhail Gupta

Reputation: 23276

Broadcasting using numpy's sum function

I was reading about broadcasting and was trying to understand it using numpy's sum function.

I created two matrices :

m1 = np.array([[1,2,3],[4,5,6]]) # 3X2
m2 = np.array([[1],[2]]) # 2X1

When I add the above two as :

m1 + m2

broadcasting is done as the column vector [1],[2] replicates itself equal to the number of columns inside m1 matrix. Is it also possible to see broadcasting using np.sum(m1,m2) ? I assume there is no difference between m1 + m2 and np.sum(m1,m2). But currently np.sum(m1,m2) throws an error TypeError: only integer scalar arrays can be converted to a scalar index.

Can't I have numpy to perform broadcasting if I use its sum function?

Upvotes: 0

Views: 5163

Answers (2)

Paul Panzer
Paul Panzer

Reputation: 53079

You actually kind of can make sum broadcast:

>>> import numpy as np
>>> 
>>> a, b, c = np.ogrid[:2, :3, :4]
>>> d = b*c
>>> list(map(np.shape, (a, b, c, d)))
[(2, 1, 1), (1, 3, 1), (1, 1, 4), (1, 3, 4)]
>>> 
>>> a+b+c+d
array([[[ 0,  1,  2,  3],
        [ 1,  3,  5,  7],
        [ 2,  5,  8, 11]],

       [[ 1,  2,  3,  4],
        [ 2,  4,  6,  8],
        [ 3,  6,  9, 12]]])
>>> np.sum([a, b, c, d])
array([[[ 0,  1,  2,  3],
        [ 1,  3,  5,  7],
        [ 2,  5,  8, 11]],

       [[ 1,  2,  3,  4],
        [ 2,  4,  6,  8],
        [ 3,  6,  9, 12]]])

I suspect this creates a 4-element array of dtype object and then delegates the actual summing to the element arrays.

Unfortunately, the array factory can at times be capricious with this kind of array-of-arrays:

And, indeed, we can use an example known to defeat np.array to trip up np.sum, even though the actual error doesn't appear to happen in np.array:

>>> np.sum([np.arange(3), 1]) # fine
array([1, 2, 3])
>>> np.sum([1, np.arange(3)]) # ouch!
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/paul/lib/python3.6/site-packages/numpy/core/fromnumeric.py", line 1882, in sum
    out=out, **kwargs)
  File "/home/paul/lib/python3.6/site-packages/numpy/core/_methods.py", line 32, in _sum
    return umr_sum(a, axis, dtype, out, keepdims)
ValueError: setting an array element with a sequence.

So, on balance, it is probably better to go with the builtin Python sum:

>>> sum([a, b, c, d])
array([[[ 0,  1,  2,  3],
        [ 1,  3,  5,  7],
        [ 2,  5,  8, 11]],

       [[ 1,  2,  3,  4],
        [ 2,  4,  6,  8],
        [ 3,  6,  9, 12]]])
>>> sum([1, np.arange(3)])
array([1, 2, 3])
>>> sum([np.arange(3), 1])
array([1, 2, 3])

Upvotes: 0

Graipher
Graipher

Reputation: 7186

numpy.sum does not add two arrays, it computes the sum over one (or multiple, or, by default, all) axis of an array. The second argument is which axis to sum over and a multi-dimensional array does not work for that.

These are examples of how numpy.sum works:

m1 = np.arange(12).reshape((3,4))
# sum all entries
np.sum(m1) # 66
# sum along the first axis, getting a result for each column
np.sum(m1, 0) # array([12, 15, 18, 21])

m2 = np.arange(12).reshape((2,3,2))
# sum along two of the three axes
m2.sum((1,2)) # array([15, 51])

What you might be looking for is numpy.add. This adds together two arrays (just like +) but allows adding some constraints (when giving it an out array you can mask certain fields so they will not get filled with the result of the addition). Otherwise it behaves how you would expect it to behave if you know the numpy broadcasting rules:

m1 = np.array([[1,2,3],[4,5,6]]) # 3X2
m2 = np.array([[1],[2]]) # 2X1
m1 + m2
# array([[2, 3, 4],
#        [6, 7, 8]])

np.add(m1, m2)
# array([[2, 3, 4],
#        [6, 7, 8]])

And here an example of the more fancy usage:

m1 = m1.astype(float)
m1[1, 1] = np.inf
m1
# array([[  1.,   2.,   3.],
#        [  4.,  inf,   6.]])
out = np.zeros_like(m1)
where = np.ones_like(m1, dtype=bool)
where[1, 1] = False # don't want that infinity in the sum
np.add(m1, m2, out, where=where)
# array([[ 2.,  3.,  4.],
#        [ 6.,  0.,  8.]])

Upvotes: 4

Related Questions