1

I have a very simple question but I just can't figure it out. I would like to stack a bunch of 2D numpy arrays into a 3D array one by one along the third dimension (depth).

I know that I can use np.stack() like this:

d1 = np.arange(9).reshape(3,3)
d2 = np.arange(9,18).reshape(3,3)

foo = np.stack((d1,d2))

and I get

print(foo.shape)
>>> (2, 3, 3)
print(foo)
>>> [[[ 0  1  2]
      [ 3  4  5]
      [ 6  7  8]]

     [[ 9 10 11]
      [12 13 14]
      [15 16 17]]]

Which is pretty much what I want so far. Though, I am a bit confused here that the depth dimension is indexed as the first one here. However, I would like to add new 3x3 array along the first dimension now(?) (this confuses me), like this.

d3 = np.arange(18,27).reshape(3,3)
foo = np.stack((foo,d3))

This does not work. I understand that it has a problem with dimensions of the arrays now, but no vstack, hstack, dstack work here. All I want at this point is pretty much this.

print(foo)
>>> [[[ 0  1  2]
      [ 3  4  5]
      [ 6  7  8]]

     [[ 9 10 11]
      [12 13 14]
      [15 16 17]]

     [[18 19 20]
      [21 22 23]
      [24 25 26]]]

and then just be able to add more arrays like this.

I looked at some questions on this topic, of course, but I still have problem understanding 3D arrays (especially np.dstack()) and don't know how to solve my problem.

1
  • 1
    np.vstack((foo,[d3])). Please note the error message all the input arrays must have same number of dimensions, but the array at index 0 has 3 dimension(s) and the array at index 1 has 2 dimension(s). It's usually a bad idea to stack np.array iteratively. Commented Jun 2, 2022 at 9:39

3 Answers 3

1

Why don't you add directly d1, d2, d3 in a single stack (np.stack((d1, d2, d3)))? This is generally bad practice to repeatedly concatenate arrays.

In any case, you can use:

np.stack((*foo, d3))

or:

np.vstack((foo, d3[None]))

output:

array([[[ 0,  1,  2],
        [ 3,  4,  5],
        [ 6,  7,  8]],

       [[ 9, 10, 11],
        [12, 13, 14],
        [15, 16, 17]],

       [[18, 19, 20],
        [21, 22, 23],
        [24, 25, 26]]])
Sign up to request clarification or add additional context in comments.

5 Comments

In my code, I loop over a certain function which gives me 2D array as a result. Every loop is a trial and I need to collect my data into a 3D array. This works, thank you. Can I ask you how are these commands different from np.stack((foo,d3))? What does the * or [None] do to make it work?
try to run d3[None], this adds an extra leading dimension (of size 1), so that all stacked arrays have the same shape. That said, you still shouldn't repeatedly stack, collect in a list and stack in the end ;)
@jambormike - in these cases it is more efficient to collect the 2D arrays into a list and finally convert the list to np.array
(Edit: Didn't notice the previous comment) Understood, how can I avoid this then? I run somewhat complicated function in which I collect data and the output is 2D array. I need to run this function several times. Each iteration is an experimental trial. For later purposes, I need 3D array where the 3rd dimension (depth) is trials. Is there some coding paradigm I should look at?
the question is, do you need the stacked array for the next iteration or not? If not, collect in a list all your iterations, then stack. If you do need it, then it really depends on the exact operation you're performing…
0

You are looking for np.vstack:

np.vstack((d1,d2,d3)).reshape(3,3,3)

or iteratively

foo = np.vstack((d1, d2))
foo = np.vstack((foo, d3))

1 Comment

sorry I forgot the .reshape(3,3,3) in the last line.
0

Make 2 arrays with distinctive shapes (so it's clear where the 2,3 and 4 come from):

In [123]: d1 = np.arange(12).reshape(3,4)
     ...: d2 = np.arange(12,24).reshape(3,4)

Combining them into a new array - the result is a (2,3,4). Note how [] are nested, as though you had a list of 2 lists, each of which is has 3 lists of length 4.

In [124]: np.array((d1,d2))
Out[124]: 
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]],

       [[12, 13, 14, 15],
        [16, 17, 18, 19],
        [20, 21, 22, 23]]])

stack with the default axis does the same thing - join the (3,4) arrays along a new leading dimension:

In [125]: np.stack((d1,d2))
Out[125]: 
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]],

       [[12, 13, 14, 15],
        [16, 17, 18, 19],
        [20, 21, 22, 23]]])

Making a (3,2,4) array:

In [126]: np.stack((d1,d2), axis=1)
Out[126]: 
array([[[ 0,  1,  2,  3],
        [12, 13, 14, 15]],

       [[ 4,  5,  6,  7],
        [16, 17, 18, 19]],

       [[ 8,  9, 10, 11],
        [20, 21, 22, 23]]])

and a (3,4,2):

In [127]: np.stack((d1,d2), axis=2)
Out[127]: 
array([[[ 0, 12],
        [ 1, 13],
        [ 2, 14],
        [ 3, 15]],

       [[ 4, 16],
        [ 5, 17],
        [ 6, 18],
        [ 7, 19]],

       [[ 8, 20],
        [ 9, 21],
        [10, 22],
        [11, 23]]])

Often depth is the last dimension. That's implied by the d in np.dstack.

vstack joins them on an existing 1st dimension, making a (2*3, 4) array:

In [128]: np.vstack((d1,d2))
Out[128]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15],
       [16, 17, 18, 19],
       [20, 21, 22, 23]])

All these *stack functions tweak the dimensions and then use np.concatenate. The default stack adds a new leading dimension, as in:

In [129]: np.concatenate((d1[None,:,:], d2[None,:,:])).shape
Out[129]: (2, 3, 4)

While vstack can be used repeated in a loop, provided you start with an appropriate array, it is slow. It's better to collect the whole list of arrays, and do just one combination.

An extra problem with stack in a loop is that it adds a dimension each time, and requires matching shapes.

np.stack((foo,d3))  # a (2,3,3) with a (3,3); dimensions don't match
np.stack((foo,foo)) # produces (2,2,3,3)

To add more arrays to foo you have to expand them to (1,3,3) shape

np.concatenate((foo, d3[None,:,:], d4[None,:,:]), axis=0)

This then joins (2,3,3) with (1,3,3) and another (1,3,3) etc; matching dimensions except the first.

When joining arrays with any of these functions, you can't be casual about the dimensions. np.concatenate has very specific rules about that it can combine.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.