3

Consider, for reference:

>>> x, y = np.ones((2, 2, 2)), np.zeros((2, 2, 2))
>>> np.concatenate((x, y, x, y), axis=2)
array([[[ 1.,  1.,  0.,  0.,  1.,  1.,  0.,  0.],
        [ 1.,  1.,  0.,  0.,  1.,  1.,  0.,  0.]],

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

We have stacked the arrays along the innermost dimension, merging it - the resulting shape is (2, 2, 8). But suppose I wanted those innermost elements to lie side-by-side instead (this would only work because every dimension of the source arrays is the same, including the one I want to 'stack' in), producing a result with shape (2, 2, 4, 2) as follows?

array([[[[ 1.,  1.],
         [ 0.,  0.],
         [ 1.,  1.],
         [ 0.,  0.]],

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


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

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

The best approach I have is to reshape each source array first, to add a 1-length dimension right before the last:

def pad(npa):
    return npa.reshape(npa.shape[:-1] + (1, npa.shape[-1]))

np.concatenate((pad(x), pad(y), pad(x), pad(y)), axis=2) # does what I want
# np.hstack might be better? I always want the second-last dimension, now

But I feel like I am reinventing a wheel. Have I overlooked something that will do this more directly?

1 Answer 1

4

You can do it as follows:

>>> xx = x[..., None, :]
>>> yy = y[..., None, :]
>>> np.concatenate((xx, yy, xx, yy), axis=2).shape
(2, 2, 4, 2)
>>> np.concatenate((xx, yy, xx, yy), axis=2)
array([[[[ 1.,  1.],
         [ 0.,  0.],
         [ 1.,  1.],
         [ 0.,  0.]],

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


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

        [[ 1.,  1.],
         [ 0.,  0.],
         [ 1.,  1.],
         [ 0.,  0.]]]])
>>> 

What this example does is change the shape (no data is copied) of the arrays. Slicing with None or equivalently np.newaxis adds an axis:

>>> xx.shape
(2, 2, 1, 2)
>>> xx
array([[[[ 1.,  1.]],

        [[ 1.,  1.]]],


       [[[ 1.,  1.]],

        [[ 1.,  1.]]]])
>>> 
Sign up to request clarification or add additional context in comments.

4 Comments

There is no broadcasting here, you're just adding a dimension using newaxis.
I'd recommend removing any reference to adding axes using None. It is bad practice. np.newaxis is the way to go. The maxime is be explicit: naming is everything, or at least a lot. Take a look at this magic line
@eickenberg it's in the docs too: docs.scipy.org/doc/numpy/reference/… Bi Rico you are right I was on autopilot, editing
@BiRico it's clearly a simpler way to add the dimension than what I clumsily put together, though. :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.