-2

I'm missing something here. I have a 1-D array that I want to broadcast to an N-D 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)
Jason S
  • 184,598
  • 164
  • 608
  • 970

4 Answers4

3

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
Martin
  • 3,333
  • 2
  • 18
  • 39
1

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]]])
hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • I dont like Two things. That you answer quite late, copying exactly @Divakar 's answer. And secondly your 'Broadcasting steps' and ' have to explicitly add trailing dimensions'... You dont have to at all. My answer proves it and this command that returns true too: np.all(np.broadcast_to(np.arange(12)[:,None,None], (12,2,2)) == np.broadcast_to(np.arange(12),(2,2,12)).T) – Martin Feb 11 '19 at 19:03
  • @Martin, there are no rules against an answer providing the same information as a comment. That happens all the time. Divakar and I aren't in a competition for points (he's way ahead of me!). I'm just trying to provide a clear explanation of broadcasting.. I'll upvote your answer :) – hpaulj Feb 11 '19 at 19:06
  • there are no such rules, you are right. But there are unwritten rules and I believe you are breaking them. Moreover I dont like tone of your answer which looks like your solution is the cookbook(while it looks like you studied answers here and composed something from it). For example adding the trailing dimensions looks more hacky then just doing transpose on matrix. – Martin Feb 11 '19 at 19:14
  • No big feelings... Maybe I am quite wrong. But I just dont feel right about it – Martin Feb 11 '19 at 19:18
  • @hpaulj -- I'd recommend citing Divakar's comment to give him credit; otherwise I don't have a problem with your answer, as you explain more in depth. – Jason S Feb 11 '19 at 19:31
-1

When you broadcast to N-D, 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.

TyD
  • 13
  • 5
  • I understand why it is doing what it's doing; what I don't understand is how to fix it. I want my 1-D array to be broadcast along the 0th dimension of the final array. – Jason S Feb 11 '19 at 17:22
  • 1
    Broadcasting to `(12,12,12)` obscures where the replication occurs. You need to look at the values, not just the shape. – hpaulj Feb 11 '19 at 19:01
-1

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.

vishal ms
  • 44
  • 3