NumPy·Lesson 12·11 min·0/4 exercises

Joining and splitting arrays

concatenate extends an axis; stack creates one. Everything else is shorthand.

np.concatenatenp.stacknp.vstacknp.hstacknp.splitnp.tilenp.repeat

Watch it happen

Play it through, or step back and forth yourself.

p
1
2
3
4
shape (2, 2)
q
5
6
7
8
shape (2, 2)

Two (2, 2) arrays. There are two genuinely different things you might mean by "put them together", and NumPy gives you a separate function for each.

The idea

There are two genuinely different things "put these arrays together" can mean, and getting them straight saves a lot of confusion.

concatenate extends an existing axis

np.concatenate([p, q], axis=0)   # (2,2) + (2,2) -> (4,2)
np.concatenate([p, q], axis=1)   # (2,2) + (2,2) -> (2,4)

The rank stays the same — one axis just gets longer. Every other axis has to match exactly, which is what the error message means when it complains that "all the input array dimensions except for the concatenation axis must match".

stack creates a new axis

np.stack([p, q])           # (2,2) + (2,2) -> (2, 2, 2)
np.stack([p, q], axis=-1)  # -> (2, 2, 2), but interleaved differently

Here the rank goes up. All the inputs must have the same shape, since they're being laid side by side along a brand-new axis. This is how a list of images becomes a batch, and how a list of columns becomes a table.

That's the whole distinction: concatenate makes an axis longer, stack adds one. If you're ever unsure which you want, ask whether the answer should have more dimensions than the inputs.

The shorthands

np.vstack([p, q])         # like concatenate(axis=0)
np.hstack([p, q])         # like concatenate(axis=1) — but axis=0 for 1-D input
np.column_stack([x, y])   # two 1-D arrays become two columns

These read nicely and occasionally surprise you: hstack on 1-D arrays joins end-to-end rather than making columns, because 1-D arrays only have one axis to join along. When the input rank might vary, prefer concatenate or stack with an explicit axis=. It's longer and it's never ambiguous.

Splitting

np.split(arr, 3)          # into 3 equal parts — raises if it doesn't divide
np.split(arr, [2, 5])     # split before index 2 and before index 5
np.array_split(arr, 3)    # allows uneven parts
np.vsplit / np.hsplit     # the axis-specific shorthands

All of these return a list of arrays, not an array — a common surprise when you try to do arithmetic on the result.

tile versus repeat

The classic mix-up, and worth ten seconds to get right:

x = np.array([1, 2, 3])
np.tile(x, 2)      # [1 2 3 1 2 3]  — the whole array, again
np.repeat(x, 2)    # [1 1 2 2 3 3]  — each element, again

tile lays the pattern down repeatedly, like floor tiles. repeat duplicates each element where it stands. Both take an axis on higher-dimensional input.

One last note: joining always copies. There's no way to make two separately allocated arrays contiguous without moving bytes. So building an array by concatenating in a loop is quadratic and slow — collect into a Python list and concatenate once at the end, or pre-allocate with np.empty and fill it.

Practice

Write it yourself. The answer is there when you want it.

Putting the kettle on…

Starting up…

Write it yourself

not graded

Concatenate p and q along axis=0 and axis=1, printing each. Then print the shape np.stack gives instead — a new axis, not a longer one. Compare np.tile with np.repeat on [1, 2, 3]. Finish by splitting np.arange(6) into three.

Write something and press Run — the output appears here.

Your turn

4 exercises. Write the code yourself, then press Check — a nudge and the answer are there if you want them.

Join p and q so the result is (4, 2) — one on top of the other.

your answer

Now join them side by side, so the result is (2, 4).

your answer

Stack p and q along a new axis so the result is (2, 2, 2).

your answer

From np.array([1, 2, 3]), produce [1, 1, 2, 2, 3, 3] — each element doubled in place.

your answer