Home > Back-end >  different dimension numpy array broadcasting issue with ' =' operator
different dimension numpy array broadcasting issue with ' =' operator

Time:08-25

I'm new to numpy, and I have an interesting observation on the broadcasting. When I'm adding a 3x5 array directly to a 3x1 array, and update the original 3x1 array with the result, there is no broadcasting issue.

import numpy as np
total = np.random.uniform(-1,1, size=(3))[:,np.newaxis]
print(f'init = \n {total}')

for i in range(3):
    total = total   np.ones(shape=(3,5))
    print(f'total_{i} = \n {total}')

However, if i'm using ' =' operator to increment the 3x1 array with the value of 3x5 array, there is a broadcasting issue. May I know which rule of numpy broadcasting did I violate in the latter case?

total = np.random.uniform(-1,1, size=(3))[:,np.newaxis]
print(f'init = \n {total}')

for i in range(3):
    total  = np.ones(shape=(3,5))
    print(f'total_{i} = \n {total}')

Thank you! hawkoli1987

CodePudding user response:

according to add function overridden in numpy array,

def add(x1, x2, *args, **kwargs): # real signature unknown; NOTE: unreliably restored from __doc__ 
    """
    add(x1, x2, /, out=None, *, where=True, casting='same_kind', order='K', dtype=None, subok=True[, signature, extobj])
    
    Add arguments element-wise.
    
    Parameters
    ----------
    x1, x2 : array_like
        The arrays to be added.
        If ``x1.shape != x2.shape``, they must be broadcastable to a common
        shape (which becomes the shape of the output).
    out : ndarray, None, or tuple of ndarray and None, optional
        A location into which the result is stored. If provided, it must have
        a shape that the inputs broadcast to. If not provided or None,
        a freshly-allocated array is returned. A tuple (possible only as a
        keyword argument) must have length equal to the number of outputs.

add function returns a freshly-allocated array when dimensions of arrays are different.

In python, a=a b and a =b aren't absolutly same. calls __add__ function and = calls __iadd__.

a = np.array([1, 2])
b = np.array([3, 4])
first_id = id(a)
a = a   b
second_id = id(a)
assert first_id == second_id  # False

a = np.array([1, 2])
b = np.array([3, 4])
first_id = id(a)
a  = b
second_id = id(a)
assert first_id == second_id  # True

= function does not create new objects and updates the value to the same address.

numpy add function updates an existing instance when adding an array of the same dimensions, but returns a new object when adding arrays of different dimensions. So when use = functions, the two functions must have the same dimension because the results of the add function must be updated on the same object.

For example,

a = np.array()
total = np.random.uniform(-1,1, size=(3))[:,np.newaxis]
print(id(total))

for i in range(3):
    total  = np.ones(shape=(3,1))
    print(id(total))

id(total) are all same because add function just updates the instance in same address because dimmension of two arrays are same.

CodePudding user response:

In [29]: arr = np.zeros((1,3))

The actual error message is:

In [30]: arr  = np.ones((2,3))
Traceback (most recent call last):
  Input In [30] in <cell line: 1>
    arr  = np.ones((2,3))
ValueError: non-broadcastable output operand with shape (1,3) doesn't match the broadcast shape (2,3)

I read that as say that arr on the left is "non-broadcastable", where as arr np.ones((2,3)) is the result of broadcasting. The wording may be awkward; it's probably produced in some deep compiled function where it makes more sense.

We get a variant on this when we try to assign an array to a slice of an array:

In [31]: temp = arr   np.ones((2,3))
In [32]: temp.shape
Out[32]: (2, 3)
In [33]: arr[:] = temp
Traceback (most recent call last):
  Input In [33] in <cell line: 1>
    arr[:] = temp
ValueError: could not broadcast input array from shape (2,3) into shape (1,3)

This is clearer, saying that the RHS (2,3) cannot be put into the LHS (1,3) slot.

Or trying to put the (2,3) into one "row" of arr:

In [35]: arr[0] = temp
Traceback (most recent call last):
  Input In [35] in <cell line: 1>
    arr[0] = temp
ValueError: could not broadcast input array from shape (2,3) into shape (3,)

arr[0] = arr works because it tries to put a (1,3) into a (3,) shape - that's a workable broadcasting combination.

arr[0] = arr.T tries to put a (3,1) into a (3,), and fails.

  • Related