30

I have two numpy arrays with three dimensions (3 x 4 x 5) and I want to concatenate them so the result has four dimensions (3 x 4 x 5 x 2). In Matlab, this can be done with cat(4, a, b), but not in Numpy.

For example:

a = ones((3,4,5))
b = ones((3,4,5))
c = concatenate((a,b), axis=3) # error!

To clarify, I wish c[:,:,:,0] and c[:,:,:,1] to correspond to the original two arrays.

Marijn van Vliet
  • 5,239
  • 2
  • 33
  • 45

6 Answers6

32

What about

c = np.stack((a,b), axis=3)
Daniel
  • 514
  • 5
  • 9
29

Here you go:

import numpy as np
a = np.ones((3,4,5))
b = np.ones((3,4,5))
c = np.concatenate((a[...,np.newaxis],b[...,np.newaxis]),axis=3)
JoshAdel
  • 66,734
  • 27
  • 141
  • 140
  • 4
    Accepting this one for being slightly more readable. Plus it releaved me of my ignorance of the `...` operator. – Marijn van Vliet Jan 17 '12 at 17:11
  • 7
    If you have a sequence of arrays that you want to stack this way you can use: `c = np.concatenate([aux[..., np.newaxis] for aux in sequence_of_arrays], axis=3)` – Tom Pohl Feb 13 '14 at 09:08
  • 7
    More generally, you can use `axis=-1` regardless of the number of dimensions in the original array. – 1'' Mar 11 '15 at 03:25
13

How about the following:

c = concatenate((a[:,:,:,None],b[:,:,:,None]), axis=3)

This gives a (3 x 4 x 5 x 2) array, which I believe is laid out in the manner you require.

Here, None is synonymous to np.newaxis: Numpy: Should I use newaxis or None?

edit As suggested by @Joe Kington, the code could be cleaned up a little bit by using an ellipsis:

c = concatenate((a[...,None],b[...,None]), axis=3)
Community
  • 1
  • 1
NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • beat me by a couple of seconds. . .dammit :-) I'll blame it on typing out `np.newaxis`, instead of `None` +1 to you – JoshAdel Jan 17 '12 at 17:08
  • @JoshAdel: LOL, but you've saved on not having to type all those annoying colons! :-) – NPE Jan 17 '12 at 17:09
8

The accepted answer above is great. But I'll add the following because I'm a math dork and it's a nice use of the fact that a.shape is a.T.shape[::-1]...i.e. taking a transpose reverses the order of the indices of a numpy array. So if you have your building blocks in an array called blocks, then the solution above is:

new = np.concatenate([block[..., np.newaxis] for block in blocks],
                     axis=len(blocks[0].shape))

but you could also do

new2 = np.array([block.T for block in blocks]).T

which I think reads more cleanly. It's worth noting that the already-accepted answer runs more quickly:

%%timeit
new = np.concatenate([block[..., np.newaxis] for block in blocks],
                     axis=len(blocks[0].shape))
1000 loops, best of 3: 321 µs per loop

while

%%timeit
new2 = np.array([block.T for block in blocks]).T
1000 loops, best of 3: 407 µs per loop
8one6
  • 13,078
  • 12
  • 62
  • 84
1

This works for me:

 c = numpy.array([a,b])

Though it would be nice if it worked your way, too.

Sideshow Bob
  • 4,566
  • 5
  • 42
  • 79
0

It's not necessarily the most elegant, but I've used variations of

c = rollaxis(array([a,b]), 0, 4)

in the past.

DSM
  • 342,061
  • 65
  • 592
  • 494