简体   繁体   中英

How to broadcast a 1d array to an N-D array in Python

I'm missing something here. I have a 1-D array that I want to broadcast to an ND array, and it's not working:

>>> import numpy as np
>>> np.broadcast_to(np.arange(12),(12,2,2))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "c:\app\python\anaconda\2\lib\site-packages\numpy\lib\stride_tricks.py", line 173, in broadcast_to
    return _broadcast_to(array, shape, subok=subok, readonly=True)
  File "c:\app\python\anaconda\2\lib\site-packages\numpy\lib\stride_tricks.py", line 128, in _broadcast_to
    op_flags=[op_flag], itershape=shape, order='C').itviews[0]
ValueError: operands could not be broadcast together with remapped shapes [original->remapped]: (12,) and requested shape (12,2,2)

Solution

You need to have size of last dimension as a size of first argument(arange array). This works. Just put 12 at the end and transpose

import numpy as np
np.broadcast_to(np.arange(12),(2,2,12)).T # so it fits exactly your question, transpose

>>> np.broadcast_to(np.arange(12),(2,2,12)).T.shape
(12, 2, 2)

NOTE

Looking at documentations, it seems you really need to have corresponding shapes at both - array & desired shape. If you have

np.arange(X)

then you can have any desired shape as long as the last dimension has shape X

np.broadcast_to(np.arange(X),(ANY,ANY,ANY,ANY,ANY,X))

you can test it with this funny example

X = 10
np.broadcast_to(np.arange(X),[i for i in range(X+1)]).shape

EDIT:

In relation to @Divakar's comment to OP (adding extra dimensions), it looks there are two possible ways with same results

solution1 = np.broadcast_to(np.arange(12)[:,None,None], (12,2,2)) # Divakar's
solution2 = np.broadcast_to(np.arange(12),(12,2,2)[::-1]).T # without extra dimensions, using Transpose

>>> np.all(solution1 == solution2)
True

Broadcasting has two steps:

  • expand dimensions on the left to match
  • expand all size 1 dimensions to match

With a size (12,) array, the first step can produce (1,1,12), but not (12,1,1). The second step could then expand to (2,2,12). But you want (12,2,2).

So you have to explicitly add the trailing dimensions

In [773]: np.broadcast_to(np.arange(12)[:,None,None], (12,2,2)).shape
Out[773]: (12, 2, 2)

In [775]: np.broadcast_to(np.arange(3)[:,None,None], (3,2,2))
Out[775]: 
array([[[0, 0],
        [0, 0]],

       [[1, 1],
        [1, 1]],

       [[2, 2],
        [2, 2]]])

So by these rules broadcasting to (2,2,12) works, and transpose can change that to (12,2,2)

Broadcasting to (12,12,12) is equivalent to expanding (1,1,12). The arange is the last dimension, not the first. We don't want to slice that last dimension

In [777]: np.broadcast_to(np.arange(3),(3,3,3))[:,:2,:2]
Out[777]: 
array([[[0, 1],
        [0, 1]],

       [[0, 1],
        [0, 1]],

       [[0, 1],
        [0, 1]]])

When you broadcast to ND, the new shape has to match the input of the 1-D array. For example, you could do:

np.broadcast_to(np.arange(12),(12,12))

or

np.broadcast_to(np.arange(12),(12,12,12))

It can't broadcast 12 numbers into a dimension with length 2, from your example.

If you want something subset of the broadcast as you mentioned then you can slice the array.

arr = np.broadcast_to(np.arange(12),(12,12,12))
arr = arr[:,:2,:2]

This gives the required result you wanted.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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