5

How to create an numpy array with shape [2, 2, 3], where the elements at axis 2 is another array, for example [1, 2, 3]?

So I would like to do something like this invalid code:

a = np.arange(1, 4)
b = np.full((3, 3), a)

Resulting in an array like:

[[[ 1.  2.  3.]
  [ 1.  2.  3.]]
 [[ 1.  2.  3.]
  [ 1.  2.  3.]]]

Could of course make the loop for filling like, but thought there may be a shortcut:

for y in range(b.shape[0]):
    for x in range(b.shape[1]):
        b[y, x, :] = a
kmario23
  • 57,311
  • 13
  • 161
  • 150
EquipDev
  • 5,573
  • 10
  • 37
  • 63
  • 3
    Just use the expected shape with `np.full` : `np.full((2,2,3), a)`? – Divakar Apr 21 '17 at 08:19
  • "where the elements at axis 2 is another array". That should be a `(2,3)` shaped array right? Your suggested `[1,2,3]` is not... – Tom de Geus Apr 21 '17 at 08:23
  • @TomdeGeus: No, the intention in the example is to make an array shaped `[2, 2, 3]`, or what I call a `[2, 2]` array where the elements are an `[3]` array. – EquipDev Apr 21 '17 at 08:30
  • @Divakar: Thanks, that does it. – EquipDev Apr 21 '17 at 08:30
  • `full` can produce unexpected results if the array is object dtype, http://stackoverflow.com/q/43483663. There it behaves like `[[]]*4`. – hpaulj Apr 21 '17 at 10:06

4 Answers4

3

There are multiple ways to achieve this. One is to use np.full in np.full((2,2,3), a) as pointed out by Divakar in the comments. Alternatively, you can use np.tile for this, which allows you to construct an array by repeating an input array a given number of times. To construct your example you could do:

import numpy as np

np.tile(np.arange(1, 4), [2, 2, 1])
jotasi
  • 5,077
  • 2
  • 29
  • 51
2

If your numpy version is >= 1.10 you can use broadcast_to

a = np.arange(1,4)
a.shape = (1,1,3)
b = np.broadcast_to(a,(2,2,3))

This produces a view rather than copying so will be quicker for large arrays. EDIT this looks to be the result you're asking for with your demo.

paddyg
  • 2,153
  • 20
  • 24
  • The output array is as requested, but I think the syntax is less obvious and easy to remember, compare with the answer from jotasi and Divakar. – EquipDev Apr 21 '17 at 08:47
  • Agreed. To some extent! tile() does some automatic prepending of axes if the dimensions of a are less than the output result (broadcast_to does as well actually) so I put the reshape line in to show how to control the process. You could argue that broadcasting to the shape of the result array is clearer. As I mention the virtue of broadcast_to is that it makes a read only view so is very quick. – paddyg Apr 21 '17 at 18:39
2

Based on Divakar comment, an answer can also be:

import numpy as np
np.full([2, 2, 3], np.arange(1, 4))

Yet another possibility is:

import numpy as np
b = np.empty([2, 2, 3])
b[:] = np.arange(1, 4)
EquipDev
  • 5,573
  • 10
  • 37
  • 63
1

Also using np.concatenate or it's wrapper np.vstack

In [26]: a = np.arange(1,4)

In [27]: np.vstack([a[np.newaxis, :]]*4).reshape(2,2, 3)
Out[27]: 
array([[[1, 2, 3],
        [1, 2, 3]],

       [[1, 2, 3],
        [1, 2, 3]]])

In [28]: np.concatenate([a[np.newaxis, :]]*4, axis=0).reshape(2,2, 3)
Out[28]: 
array([[[1, 2, 3],
        [1, 2, 3]],

       [[1, 2, 3],
        [1, 2, 3]]])
kmario23
  • 57,311
  • 13
  • 161
  • 150