NumPy: Concatenate arrays with np.concatenate, np.stack, etc.
This article explains how to concatenate multiple NumPy arrays (ndarray
) using functions such as np.concatenate()
and np.stack()
.
np.concatenate()
concatenates along an existing axis, whereas np.stack()
concatenates along a new axis. For example, np.concatenate()
can concatenate 2D arrays vertically or horizontally, and np.stack()
can stack 2D arrays to create a 3D array.
Although np.concatenate()
and np.stack()
are versatile for a wide range of applications, it is also beneficial to be familiar with np.block()
, np.vstack()
, np.hstack()
, and np.dstack()
, particularly when working with 2D arrays.
np.concatenate()
concatenates arrays along an existing axisnp.stack()
concatenates arrays along a new axisnp.block()
concatenates arrays according to specified arrangementnp.vstack()
concatenates arrays verticallynp.hstack()
concatenates arrays horizontallynp.dstack()
concatenates arrays in depth direction
Other methods, such as np.r_[]
and np.c_[]
, are also available but are not covered in this article. For more details, refer to the official documentation:
See the following articles on how to split an ndarray
or add values to an ndarray
.
- NumPy: Split an array with np.split, np.vsplit, np.hsplit, etc.
- NumPy: append() to add values to an array
- NumPy: Insert elements, rows, and columns into an array with np.insert()
The NumPy version used in this article is as follows. Note that functionality may vary between versions.
import numpy as np
print(np.__version__)
# 1.26.1
np.concatenate()
concatenates arrays along an existing axis
np.concatenate()
concatenates arrays along an existing axis.
Specify the list of arrays to concatenate
Consider the following arrays as an example.
a1 = np.ones((2, 3), int)
print(a1)
# [[1 1 1]
# [1 1 1]]
a2 = np.full((2, 3), 2)
print(a2)
# [[2 2 2]
# [2 2 2]]
Refer to the following article for np.ones()
and np.full()
.
Specify the list of arrays as the first argument. You can also use a tuple instead of a list.
print(np.concatenate([a1, a2]))
# [[1 1 1]
# [1 1 1]
# [2 2 2]
# [2 2 2]]
For more than three arrays, simply increase the number of elements in the list or tuple specified as the first argument.
a3 = np.full((2, 3), 3)
print(a3)
# [[3 3 3]
# [3 3 3]]
print(np.concatenate([a1, a2, a3]))
# [[1 1 1]
# [1 1 1]
# [2 2 2]
# [2 2 2]
# [3 3 3]
# [3 3 3]]
Specify the axis to concatenate: axis
Specify the axis to concatenate as the second argument, axis
. The default is axis=0
.
For 2D arrays, axis=0
concatenates vertically, and axis=1
concatenates horizontally.
a1 = np.ones((2, 3), int)
print(a1)
# [[1 1 1]
# [1 1 1]]
a2 = np.full((2, 3), 2)
print(a2)
# [[2 2 2]
# [2 2 2]]
print(np.concatenate([a1, a2], 0))
# [[1 1 1]
# [1 1 1]
# [2 2 2]
# [2 2 2]]
print(np.concatenate([a1, a2], 1))
# [[1 1 1 2 2 2]
# [1 1 1 2 2 2]]
Specifying a non-existent axis will result in an error. To concatenate along a new axis, such as when stacking 2D arrays to create a 3D array, use np.stack()
or other similar functions that will be discussed later.
# print(np.concatenate([a1, a2], 2))
# AxisError: axis 2 is out of bounds for array of dimension 2
An error occurs if the sizes of the axes other than the concatenation axis do not match. Missing parts are not filled with NaN
.
a2_ = np.full((3, 3), 2)
print(a2_)
# [[2 2 2]
# [2 2 2]
# [2 2 2]]
print(np.concatenate([a1, a2_], 0))
# [[1 1 1]
# [1 1 1]
# [2 2 2]
# [2 2 2]
# [2 2 2]]
# print(np.concatenate([a1, a2_], 1))
# ValueError: all the input array dimensions except for the concatenation axis must match exactly, but along dimension 0, the array at index 0 has size 2 and the array at index 1 has size 3
The same applies to arrays of dimensions other than two: specify the concatenation axis with the second argument axis
, noting that concatenation cannot be performed on non-existent axes.
a1 = np.ones(3, int)
print(a1)
# [1 1 1]
a2 = np.full(3, 2)
print(a2)
# [2 2 2]
print(np.concatenate([a1, a2], 0))
# [1 1 1 2 2 2]
# print(np.concatenate([a1, a2], 1))
# AxisError: axis 1 is out of bounds for array of dimension 1
An error occurs if the input arrays have different numbers of dimensions.
a1 = np.ones((2, 3), int)
print(a1)
# [[1 1 1]
# [1 1 1]]
a2 = np.full(3, 2)
print(a2)
# [2 2 2]
# print(np.concatenate([a1, a2], 0))
# ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 2 dimension(s) and the array at index 1 has 1 dimension(s)
It is possible to vertically concatenate 1D and 2D arrays using np.block()
or np.vstack()
as described later.
np.stack()
concatenates arrays along a new axis
Unlike np.concatenate()
, which concatenates arrays along an existing axis, np.stack()
stacks arrays along a new axis.
In np.stack()
, the first argument is the list of arrays, and the second argument, axis
, specifies the concatenation axis in the resulting array.
For 1D arrays
Consider the following 1D arrays as examples.
a1 = np.ones(3, int)
print(a1)
# [1 1 1]
a2 = np.full(3, 2)
print(a2)
# [2 2 2]
Since np.stack()
concatenates arrays along a new axis, the result is a 2D array, one dimension higher than the input.
The default is axis=0
. Specifying an axis that does not exist in the resulting array will result in an error.
print(np.stack([a1, a2]))
# [[1 1 1]
# [2 2 2]]
print(np.stack([a1, a2], 0))
# [[1 1 1]
# [2 2 2]]
print(np.stack([a1, a2], 1))
# [[1 2]
# [1 2]
# [1 2]]
# print(np.stack([a1, a2], 2))
# AxisError: axis 2 is out of bounds for array of dimension 2
Setting axis=-1
specifies the last axis, equivalent to axis=1
in this example.
print(np.stack([a1, a2], -1))
# [[1 2]
# [1 2]
# [1 2]]
An error occurs if the input arrays have different shapes.
a2_ = np.full(4, 2)
print(a2_)
# [2 2 2 2]
# print(np.stack([a1, a2_]))
# ValueError: all input arrays must have the same shape
For 2D arrays
Next, consider the following 2D arrays as examples.
a1 = np.ones((3, 4), int)
print(a1)
# [[1 1 1 1]
# [1 1 1 1]
# [1 1 1 1]]
a2 = np.full((3, 4), 2)
print(a2)
# [[2 2 2 2]
# [2 2 2 2]
# [2 2 2 2]]
Similar to the operation on 1D arrays, using 2D arrays as input results in a 3D array, one dimension higher than the input. Understanding the resulting array's shape is key to comprehending this concept.
print(np.stack([a1, a2]))
# [[[1 1 1 1]
# [1 1 1 1]
# [1 1 1 1]]
#
# [[2 2 2 2]
# [2 2 2 2]
# [2 2 2 2]]]
print(np.stack([a1, a2], 0))
# [[[1 1 1 1]
# [1 1 1 1]
# [1 1 1 1]]
#
# [[2 2 2 2]
# [2 2 2 2]
# [2 2 2 2]]]
print(np.stack([a1, a2], 0).shape)
# (2, 3, 4)
print(np.stack([a1, a2], 1))
# [[[1 1 1 1]
# [2 2 2 2]]
#
# [[1 1 1 1]
# [2 2 2 2]]
#
# [[1 1 1 1]
# [2 2 2 2]]]
print(np.stack([a1, a2], 1).shape)
# (3, 2, 4)
print(np.stack([a1, a2], 1)[:, 0, :])
# [[1 1 1 1]
# [1 1 1 1]
# [1 1 1 1]]
print(np.stack([a1, a2], 1)[:, 1, :])
# [[2 2 2 2]
# [2 2 2 2]
# [2 2 2 2]]
print(np.stack([a1, a2], 2))
# [[[1 2]
# [1 2]
# [1 2]
# [1 2]]
#
# [[1 2]
# [1 2]
# [1 2]
# [1 2]]
#
# [[1 2]
# [1 2]
# [1 2]
# [1 2]]]
print(np.stack([a1, a2], 2).shape)
# (3, 4, 2)
print(np.stack([a1, a2], 2)[:, :, 0])
# [[1 1 1 1]
# [1 1 1 1]
# [1 1 1 1]]
print(np.stack([a1, a2], 2)[:, :, 1])
# [[2 2 2 2]
# [2 2 2 2]
# [2 2 2 2]]
Specifying an axis that does not exist in the resulting array will result in an error.
# print(np.stack([a1, a2], 3))
# AxisError: axis 3 is out of bounds for array of dimension 3
Setting axis=-1
specifies the last axis, equivalent to axis=2
in this example.
print(np.stack([a1, a2], -1))
# [[[1 2]
# [1 2]
# [1 2]
# [1 2]]
#
# [[1 2]
# [1 2]
# [1 2]
# [1 2]]
#
# [[1 2]
# [1 2]
# [1 2]
# [1 2]]]
print(np.stack([a1, a2], -1).shape)
# (3, 4, 2)
An error occurs if the input arrays have different shapes.
a2_ = np.full((2, 3), 2)
print(a2_)
# [[2 2 2]
# [2 2 2]]
# print(np.stack([a1, a2_]))
# ValueError: all input arrays must have the same shape
The same concept applies to even more multi-dimensional cases.
np.block()
concatenates arrays according to specified arrangement
np.block()
allows you to concatenate arrays more intuitively.
Specify a list indicating how the original arrays are arranged.
For example, specifying a list of arrays to be placed side by side results in horizontal concatenation according to the order.
a1 = np.ones((2, 3), int)
print(a1)
# [[1 1 1]
# [1 1 1]]
a2 = np.full((2, 3), 2)
print(a2)
# [[2 2 2]
# [2 2 2]]
print(np.block([a1, a2]))
# [[1 1 1 2 2 2]
# [1 1 1 2 2 2]]
A 2D list (nested list) allows for specifying vertical arrangements as well.
print(np.block([[a1], [a2]]))
# [[1 1 1]
# [1 1 1]
# [2 2 2]
# [2 2 2]]
print(np.block([[a1, a2], [a2, a1]]))
# [[1 1 1 2 2 2]
# [1 1 1 2 2 2]
# [2 2 2 1 1 1]
# [2 2 2 1 1 1]]
Specifying a 3D list results in a 3D outcome.
print(np.block([[[a1]], [[a2]]]))
# [[[1 1 1]
# [1 1 1]]
#
# [[2 2 2]
# [2 2 2]]]
print(np.block([[[a1]], [[a2]]]).shape)
# (2, 2, 3)
It is also possible to combine 1D and 2D arrays; however, to avoid errors, the nesting depth must be consistent, even if combining only one array, as demonstrated by [a3]
in the following example.
a3 = np.full(6, 3)
print(a3)
# [3 3 3 3 3 3]
print(np.block([[a1, a2], [a3]]))
# [[1 1 1 2 2 2]
# [1 1 1 2 2 2]
# [3 3 3 3 3 3]]
# print(np.block([[a1, a2], a3]))
# ValueError: List depths are mismatched. First element was at depth 2, but there is an element at depth 1 (arrays[1])
An error occurs if there is a mismatch in the number of elements.
# print(np.block([[a1, a2, a3]]))
# ValueError: all the input array dimensions except for the concatenation axis must match exactly, but along dimension 0, the array at index 0 has size 2 and the array at index 2 has size 1
np.vstack()
concatenates arrays vertically
np.vstack()
concatenates arrays vertically, essentially equivalent to np.concatenate()
with axis=0
.
a1 = np.ones((2, 3), int)
print(a1)
# [[1 1 1]
# [1 1 1]]
a2 = np.full((2, 3), 2)
print(a2)
# [[2 2 2]
# [2 2 2]]
print(np.vstack([a1, a2]))
# [[1 1 1]
# [1 1 1]
# [2 2 2]
# [2 2 2]]
print(np.concatenate([a1, a2], 0))
# [[1 1 1]
# [1 1 1]
# [2 2 2]
# [2 2 2]]
However, np.vstack()
expands 1D input arrays to 2D (shape (N, )
into (1, N)
), allowing for the concatenation of 1D arrays into a 2D array or the concatenation of 1D and 2D arrays.
a1 = np.ones(3, int)
print(a1)
# [1 1 1]
a2 = np.full(3, 2)
print(a2)
# [2 2 2]
print(np.vstack([a1, a2]))
# [[1 1 1]
# [2 2 2]]
print(np.concatenate([a1.reshape(1, -1), a2.reshape(1, -1)], 0))
# [[1 1 1]
# [2 2 2]]
a2_2d = np.full((2, 3), 2)
print(a2_2d)
# [[2 2 2]
# [2 2 2]]
print(np.vstack([a1, a2_2d]))
# [[1 1 1]
# [2 2 2]
# [2 2 2]]
print(np.concatenate([a1.reshape(1, -1), a2_2d], 0))
# [[1 1 1]
# [2 2 2]
# [2 2 2]]
np.hstack()
concatenates arrays horizontally
np.hstack()
concatenates arrays horizontally, essentially equivalent to np.concatenate()
with axis=1
.
a1 = np.ones((2, 3), int)
print(a1)
# [[1 1 1]
# [1 1 1]]
a2 = np.full((2, 3), 2)
print(a2)
# [[2 2 2]
# [2 2 2]]
print(np.hstack([a1, a2]))
# [[1 1 1 2 2 2]
# [1 1 1 2 2 2]]
print(np.concatenate([a1, a2], 1))
# [[1 1 1 2 2 2]
# [1 1 1 2 2 2]]
However, for 1D arrays, it calls np.concatenate()
with axis=0
.
a1 = np.ones(3, int)
print(a1)
# [1 1 1]
a2 = np.full(3, 2)
print(a2)
# [2 2 2]
print(np.hstack([a1, a2]))
# [1 1 1 2 2 2]
print(np.concatenate([a1, a2], 0))
# [1 1 1 2 2 2]
Unlike np.vstack()
, 1D arrays are not expanded into 2D, so 1D and 2D arrays cannot be concatenated.
a1 = np.ones((2, 3), int)
print(a1)
# [[1 1 1]
# [1 1 1]]
a2 = np.full(2, 2)
print(a2)
# [2 2]
# print(np.hstack([a1, a2]))
# ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 2 dimension(s) and the array at index 1 has 1 dimension(s)
np.dstack()
concatenates arrays in depth direction
np.dstack()
concatenates arrays in depth direction.
It is essentially equivalent to np.concatenate()
with axis=2
, but arrays of 2D or fewer are expanded to 3D before concatenation.
2D arrays are transformed from shape (M, N)
to (M, N, 1)
.
a1 = np.ones((3, 4), int)
print(a1)
# [[1 1 1 1]
# [1 1 1 1]
# [1 1 1 1]]
a2 = np.full((3, 4), 2)
print(a2)
# [[2 2 2 2]
# [2 2 2 2]
# [2 2 2 2]]
print(np.dstack([a1, a2]))
# [[[1 2]
# [1 2]
# [1 2]
# [1 2]]
#
# [[1 2]
# [1 2]
# [1 2]
# [1 2]]
#
# [[1 2]
# [1 2]
# [1 2]
# [1 2]]]
print(np.dstack([a1, a2]).shape)
# (3, 4, 2)
print(np.dstack([a1, a2])[:, :, 0])
# [[1 1 1 1]
# [1 1 1 1]
# [1 1 1 1]]
print(np.dstack([a1, a2])[:, :, 1])
# [[2 2 2 2]
# [2 2 2 2]
# [2 2 2 2]]
Equivalent to the following np.concatenate()
.
print(np.concatenate([a1.reshape(3, 4, 1), a2.reshape(3, 4, 1)], 2))
# [[[1 2]
# [1 2]
# [1 2]
# [1 2]]
#
# [[1 2]
# [1 2]
# [1 2]
# [1 2]]
#
# [[1 2]
# [1 2]
# [1 2]
# [1 2]]]
1D arrays are also expanded to 3D from shape (N, )
to (1, N, 1)
.
a1 = np.ones(3, int)
print(a1)
# [1 1 1]
a2 = np.full(3, 2)
print(a2)
# [2 2 2]
print(np.dstack([a1, a2]))
# [[[1 2]
# [1 2]
# [1 2]]]
print(np.dstack([a1, a2]).shape)
# (1, 3, 2)
print(np.dstack([a1, a2])[:, :, 0])
# [[1 1 1]]
print(np.dstack([a1, a2])[:, :, 1])
# [[2 2 2]]
Equivalent to the following np.concatenate()
.
print(np.concatenate([a1.reshape(1, -1, 1), a2.reshape(1, -1, 1)], 2))
# [[[1 2]
# [1 2]
# [1 2]]]