Skip to content
Happy Programming Guide
Start learning
Python

Exploring np.stack() in NumPy and Python

np.stack() joins arrays along a brand-new axis. Here is what that means, how it differs from concatenate, vstack and hstack, and when to reach for each.

A laptop with a cup of coffee beside it

np.stack() joins a sequence of arrays along a new axis. That single word — new — is the whole difference between stack and its neighbours like concatenate, and it is where most of the confusion comes from. If you stack two arrays of shape (3,), you get one array of shape (2, 3). Concatenating them would have given you (6,).

The simplest possible example#

Python
import numpy as np

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

print(np.stack([a, b]))
print(np.stack([a, b]).shape)
Output
[[1 2 3]
 [4 5 6]]
(2, 3)

Both inputs were one-dimensional with shape (3,). The result is two-dimensional. NumPy created a new axis of length 2 — one slot per input array — and put it at the front.

Compare that with concatenate, which reuses the existing axis:

Python
print(np.concatenate([a, b]))        # [1 2 3 4 5 6]
print(np.concatenate([a, b]).shape)  # (6,)

Rule of thumb: stack adds a dimension, concatenate extends one.

The axis argument decides where the new dimension goes#

axis=0 is the default and puts the new axis first. axis=1 puts it second, and so on.

Python
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

print(np.stack([a, b], axis=0).shape)   # (2, 3)
print(np.stack([a, b], axis=1).shape)   # (3, 2)
print(np.stack([a, b], axis=-1).shape)  # (3, 2)
Python
print(np.stack([a, b], axis=1))
Output
[[1 4]
 [2 5]
 [3 6]]

With axis=1, the arrays are interleaved into columns instead of being laid out as rows. This is the pattern you want when you have separate lists of x values and y values and need coordinate pairs:

Python
xs = np.array([0.0, 1.0, 2.0])
ys = np.array([3.5, 4.5, 5.5])

points = np.stack([xs, ys], axis=-1)
print(points)
Output
[[0.  3.5]
 [1.  4.5]
 [2.  5.5]]

Using axis=-1 rather than axis=1 means “the last axis”, which keeps working if the inputs later gain dimensions.

Stacking two-dimensional arrays#

The rule does not change when the inputs get bigger. Two arrays of shape (2, 3) stack into something with a 2 inserted somewhere:

Python
m1 = np.array([[1, 2, 3], [4, 5, 6]])
m2 = np.array([[7, 8, 9], [10, 11, 12]])

print(np.stack([m1, m2], axis=0).shape)  # (2, 2, 3)
print(np.stack([m1, m2], axis=1).shape)  # (2, 2, 3)
print(np.stack([m1, m2], axis=2).shape)  # (2, 3, 2)

Read it as: the new axis of length 2 is inserted at position axis, and the original shape (2, 3) fills in around it.

A practical use: three greyscale images of the same size stacked into one array you can index by image number.

Python
frames = [np.zeros((64, 64)) for _ in range(3)]
video = np.stack(frames, axis=0)
print(video.shape)     # (3, 64, 64)
print(video[1].shape)  # (64, 64) - the second frame

The error you will hit#

Python
a = np.array([1, 2, 3])
b = np.array([4, 5])

np.stack([a, b])
Output
ValueError: all input arrays must have the same shape

This is stricter than concatenate. Concatenation only requires the arrays to match on every axis except the one being joined. Stacking creates a rectangular block, so every input must be identical in shape — no exceptions.

stack, vstack, hstack and dstack compared#

The named helpers are older and behave slightly differently. This table is the shortest useful summary:

Function Adds an axis? Joins along Two (3,) inputs give
np.stack Yes a new axis you choose (2, 3)
np.concatenate No an existing axis (6,)
np.vstack Only for 1-D input rows (axis 0) (2, 3)
np.hstack No columns, or axis 0 for 1-D (6,)
np.dstack Yes, up to 3-D depth (axis 2) (1, 3, 2)

The awkward part is that vstack and hstack change behaviour depending on how many dimensions the input has. vstack on 1-D arrays behaves like stack; on 2-D arrays it behaves like concatenate(axis=0). That inconsistency is exactly why np.stack was added — it always does the same thing.

Undoing a stack#

The portable way is simply to index or unpack:

Python
stacked = np.stack([a, b])   # shape (2, 3)

first, second = stacked      # unpacks along axis 0
print(first)                 # [1 2 3]

# or explicitly
parts = [stacked[i] for i in range(stacked.shape[0])]

For splitting along a different axis, np.split or np.moveaxis followed by unpacking will do it.

Questions people ask#

Is np.stack slow for large arrays?

It allocates a new array and copies the data, so it costs memory proportional to the total size. Stacking a long list of arrays one at a time in a loop is far slower than collecting them and calling np.stack once at the end.

Can I stack arrays of different dtypes?

Yes. NumPy promotes to a common type, so stacking an int array with a float array gives you a float result. If you need a specific type, pass dtype= or call .astype() afterwards.

What is the difference between np.stack and np.array on a list of arrays?

For equally shaped arrays they produce the same result. np.stack is clearer about intent, gives a better error message when shapes differ, and lets you choose the axis. np.array on ragged input either raises an error or builds an object array, which is rarely what you want.

How do I stack along a new axis in the middle of a big array?

Pass the position you want: np.stack(arrays, axis=2) inserts the new dimension as the third axis. Negative values count from the end.

Where to go next#

Python lists explained, with the operations you will actually useRead next

Keep reading

Keep going — pick your next guide

The fastest way to improve is to read one guide, then build the thing it describes. Start with the basics, or jump straight to a project.

Ask a question or share what worked

Your email address will not be published. Required fields are marked *