How to Stack Arrays in NumPy
Array stacking is the process of combining multiple arrays into a single, larger array. If you're working with data from multiple sources, building feature matrices for machine learning, or...
Key Insights
- NumPy provides specialized stacking functions (
vstack,hstack,dstack) for common use cases, plus a generalstack()function that gives you complete control over the stacking axis. - The critical difference between stacking and concatenation: stacking creates a new axis, while concatenation joins arrays along an existing axis.
- Shape compatibility is the most common source of stacking errors—arrays must match in all dimensions except the one being stacked along.
Introduction to Array Stacking
Array stacking is the process of combining multiple arrays into a single, larger array. If you’re working with data from multiple sources, building feature matrices for machine learning, or assembling image channels, you’ll need to stack arrays constantly.
NumPy offers several functions for this task, each optimized for specific use cases. Understanding when to use each one will save you debugging time and make your code more readable. Let’s work through each method systematically.
import numpy as np
Vertical Stacking with np.vstack()
Vertical stacking places arrays on top of each other, adding rows. Think of it as stacking papers in a pile. The arrays are joined along axis 0 (the row axis).
For 1D arrays, vstack() first converts them to 2D row vectors, then stacks them:
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
result = np.vstack((a, b))
print(result)
# [[1 2 3]
# [4 5 6]]
print(result.shape) # (2, 3)
Two 1D arrays with 3 elements each become a 2×3 matrix. Each original array becomes a row.
For 2D arrays, the behavior is straightforward—rows from the second array are appended below the first:
matrix1 = np.array([[1, 2],
[3, 4]])
matrix2 = np.array([[5, 6],
[7, 8]])
stacked = np.vstack((matrix1, matrix2))
print(stacked)
# [[1 2]
# [3 4]
# [5 6]
# [7 8]]
print(stacked.shape) # (4, 2)
The requirement: arrays must have the same number of columns. Row counts can differ.
Horizontal Stacking with np.hstack()
Horizontal stacking places arrays side by side, adding columns. Arrays are joined along axis 1 (the column axis).
For 1D arrays, hstack() simply concatenates them end-to-end:
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
result = np.hstack((a, b))
print(result) # [1 2 3 4 5 6]
print(result.shape) # (6,)
Notice that the result is still 1D. This is different from vstack(), which promoted the arrays to 2D.
For 2D arrays, columns are appended to the right:
matrix1 = np.array([[1, 2],
[3, 4]])
matrix2 = np.array([[5, 6],
[7, 8]])
stacked = np.hstack((matrix1, matrix2))
print(stacked)
# [[1 2 5 6]
# [3 4 7 8]]
print(stacked.shape) # (2, 4)
The requirement: arrays must have the same number of rows. Column counts can differ.
Depth Stacking with np.dstack()
Depth stacking combines arrays along the third axis. This is particularly useful for image processing, where you might need to combine separate color channels into an RGB image.
# Simulate separate R, G, B channels (2x2 pixel image)
red_channel = np.array([[255, 0],
[128, 64]])
green_channel = np.array([[0, 255],
[64, 128]])
blue_channel = np.array([[0, 0],
[255, 255]])
rgb_image = np.dstack((red_channel, green_channel, blue_channel))
print(rgb_image.shape) # (2, 2, 3)
# Access the RGB values for pixel at position (0, 0)
print(rgb_image[0, 0]) # [255 0 0] - pure red
For 1D arrays, dstack() first promotes them to shape (1, N), then stacks along the third axis:
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
result = np.dstack((a, b))
print(result.shape) # (1, 3, 2)
print(result)
# [[[1 4]
# [2 5]
# [3 6]]]
This behavior can be confusing. For most 1D use cases, vstack() or hstack() are more intuitive choices.
General Stacking with np.stack()
The np.stack() function provides complete control through its axis parameter. Unlike the specialized functions, stack() always creates a new axis at the specified position.
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
# Stack along axis 0 (similar to vstack for this case)
result_axis0 = np.stack((a, b), axis=0)
print(f"axis=0: {result_axis0.shape}") # (2, 3)
print(result_axis0)
# [[1 2 3]
# [4 5 6]]
# Stack along axis 1
result_axis1 = np.stack((a, b), axis=1)
print(f"axis=1: {result_axis1.shape}") # (3, 2)
print(result_axis1)
# [[1 4]
# [2 5]
# [3 6]]
With 2D arrays, you can stack along three possible axes:
matrix1 = np.array([[1, 2],
[3, 4]])
matrix2 = np.array([[5, 6],
[7, 8]])
# Axis 0: stack "in front" of each other
stacked_0 = np.stack((matrix1, matrix2), axis=0)
print(f"axis=0: {stacked_0.shape}") # (2, 2, 2)
# Axis 1: stack along the row dimension
stacked_1 = np.stack((matrix1, matrix2), axis=1)
print(f"axis=1: {stacked_1.shape}") # (2, 2, 2)
# Axis 2: stack along the column dimension
stacked_2 = np.stack((matrix1, matrix2), axis=2)
print(f"axis=2: {stacked_2.shape}") # (2, 2, 2)
# The shapes are the same, but the arrangement differs
print("axis=0, first slice:\n", stacked_0[0]) # matrix1
print("axis=1, first slice:\n", stacked_1[:, 0, :]) # matrix1
print("axis=2, first slice:\n", stacked_2[:, :, 0]) # matrix1
Use np.stack() when you need precise control or when the specialized functions don’t fit your use case.
Concatenation with np.concatenate()
Here’s the key distinction: stacking creates a new axis, concatenation joins along an existing axis.
a = np.array([[1, 2],
[3, 4]])
b = np.array([[5, 6],
[7, 8]])
# Concatenate along axis 0 (equivalent to vstack for 2D)
concat_0 = np.concatenate((a, b), axis=0)
print(f"concatenate axis=0: {concat_0.shape}") # (4, 2)
# Concatenate along axis 1 (equivalent to hstack for 2D)
concat_1 = np.concatenate((a, b), axis=1)
print(f"concatenate axis=1: {concat_1.shape}") # (2, 4)
# Compare with stack - note the extra dimension
stack_0 = np.stack((a, b), axis=0)
print(f"stack axis=0: {stack_0.shape}") # (2, 2, 2)
The relationship between the specialized functions and concatenate():
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
# These pairs are equivalent for 2D arrays:
assert np.array_equal(np.vstack((a, b)), np.concatenate((a, b), axis=0))
assert np.array_equal(np.hstack((a, b)), np.concatenate((a, b), axis=1))
Use concatenate() when you want to extend an array along an existing dimension without adding new axes.
Common Errors and Shape Requirements
The most frequent stacking error is a shape mismatch. Each function has specific requirements:
vstack requires matching column counts:
a = np.array([[1, 2, 3]]) # Shape: (1, 3)
b = np.array([[4, 5]]) # Shape: (1, 2)
try:
np.vstack((a, b))
except ValueError as e:
print(f"Error: {e}")
# Error: all the input array dimensions except for the concatenation axis must match exactly
hstack requires matching row counts:
a = np.array([[1], [2], [3]]) # Shape: (3, 1)
b = np.array([[4], [5]]) # Shape: (2, 1)
try:
np.hstack((a, b))
except ValueError as e:
print(f"Error: {e}")
stack requires identical shapes:
a = np.array([1, 2, 3]) # Shape: (3,)
b = np.array([4, 5]) # Shape: (2,)
try:
np.stack((a, b))
except ValueError as e:
print(f"Error: {e}")
# Error: all input arrays must have the same shape
Fixing shape mismatches with reshape:
# Scenario: You have a 1D array and a 2D row vector
a = np.array([1, 2, 3]) # Shape: (3,)
b = np.array([[4, 5, 6]]) # Shape: (1, 3)
# Option 1: Reshape a to match b
a_reshaped = a.reshape(1, -1) # Shape: (1, 3)
result = np.vstack((a_reshaped, b))
print(result.shape) # (2, 3)
# Option 2: Use np.atleast_2d() for cleaner code
result = np.vstack((np.atleast_2d(a), b))
print(result.shape) # (2, 3)
Padding arrays to match dimensions:
# When arrays have different sizes, pad the smaller one
a = np.array([1, 2, 3])
b = np.array([4, 5])
# Pad b with zeros to match a's length
b_padded = np.pad(b, (0, len(a) - len(b)), constant_values=0)
print(b_padded) # [4 5 0]
result = np.vstack((a, b_padded))
print(result)
# [[1 2 3]
# [4 5 0]]
When debugging stacking errors, always check shapes first with the .shape attribute. The error messages tell you which dimension caused the problem, but seeing the actual shapes makes the fix obvious.