Transpose, swapaxes, newaxis, expand_dims and squeeze
The functions in this lesson do not change any values. They change how the axes of an array are arranged: swapping rows and columns, or adding and removing dimensions of size 1. You need this all the time to make shapes fit together, especially for broadcasting (lesson 10) and when working with images.
How to run the examples
Create a new file named transpose_dimensions.py in your NumpyTutorials folder (see the setup in lesson 01). Any name works; this one just matches the topic. Start the file with these lines:
import numpy as np
Then copy the examples of this page into the same file, one after another, in the order shown, and run it with python transpose_dimensions.py (with your virtual environment active). Some examples use variables created in earlier ones, so keep everything in the one file. Each Output box shows what that example prints.
1. .T on a 2D array
Transposing turns rows into columns and columns into rows.
marks = np.array([[78, 85, 92], # student 0: Maths, Science, English
[88, 79, 95]]) # student 1
print("marks (students x subjects) shape", marks.shape, ":\n", marks)
print("marks.T (subjects x students) shape", marks.T.shape, ":\n", marks.T)
print("np.transpose(marks) is the same:", np.array_equal(np.transpose(marks), marks.T))
row = np.array([1, 2, 3])
print("1D .T does nothing:", row.T, row.T.shape)
marksis students x subjects, shape(2, 3).marks.Tis subjects x students, shape(3, 2).np.transpose(marks)is the function form ofmarks.T.- A 1D array has only one axis, so
.Tdoes nothing. To turn a 1D row into a column, add a dimension (section 5).
2. .T is a view
t = marks.T
t[0, 0] = 0
print("changed marks.T[0, 0] -> marks:\n", marks)
Transposing does not copy anything; it reads the same data in a different order. So changing t[0, 0] changed marks[0, 0]. If you need an independent transposed array, use marks.T.copy().
3. transpose(axes) on a 3D array
With 3 or more dimensions, .T reverses all axes. To choose your own order, pass the axis numbers to transpose().
# 2 stores x 3 months x 4 products
data = np.arange(24).reshape(2, 3, 4)
print("data.shape :", data.shape)
print("data.T.shape (reverse all) :", data.T.shape)
print("transpose(1, 0, 2).shape :", data.transpose(1, 0, 2).shape, "(months x stores x products)")
print("month 0, both stores:\n", data.transpose(1, 0, 2)[0])
data has axes (0 = stores, 1 = months, 2 = products). transpose(1, 0, 2) means "the new axis 0 is the old axis 1": the result is months x stores x products. Now [0] gives month 0 for both stores in one table.
4. swapaxes
When you only want to exchange two axes, swapaxes is simpler than writing out every axis:
print("swapaxes(0, 2).shape:", data.swapaxes(0, 2).shape)
print("swapaxes(1, 2).shape:", data.swapaxes(1, 2).shape)
print("2D swapaxes(0, 1) equals .T:", np.array_equal(marks.swapaxes(0, 1), marks.T))
For a 2D array, swapping axes 0 and 1 is exactly the transpose.
5. np.newaxis: add a dimension
np.newaxis inside the brackets inserts a new axis of size 1 at that position.
prices = np.array([10, 20, 30])
print("prices shape", prices.shape, ":", prices)
print("prices[np.newaxis, :] shape", prices[np.newaxis, :].shape, "(row vector):\n", prices[np.newaxis, :])
print("prices[:, np.newaxis] shape", prices[:, np.newaxis].shape, "(column vector):\n", prices[:, np.newaxis])
print("np.newaxis is None:", np.newaxis is None, "-> prices[:, None] works too")
| Expression | Shape | Looks like |
|---|---|---|
prices | (3,) | plain 1D array |
prices[np.newaxis, :] | (1, 3) | a row vector: 1 row, 3 columns |
prices[:, np.newaxis] | (3, 1) | a column vector: 3 rows, 1 column |
np.newaxis is just another name for None, so prices[:, None] is the same thing. You will see both in real code.
6. Why add a dimension? Column x row = table
quantities = np.array([1, 2, 3, 4])
print("price table (rows = quantity, columns = item):\n", quantities[:, np.newaxis] * prices)
A column of shape (4, 1) times a row of shape (3,) gives a full (4, 3) table: every quantity times every price. This is broadcasting, and adding an axis is how you control it. Lesson 10 explains the rules.
7. np.expand_dims
np.expand_dims(arr, axis) does the same as np.newaxis, written as a function. Some people find it easier to read.
print("expand_dims(prices, axis=0).shape :", np.expand_dims(prices, axis=0).shape)
print("expand_dims(prices, axis=1).shape :", np.expand_dims(prices, axis=1).shape)
print("expand_dims(marks, axis=0).shape :", np.expand_dims(marks, axis=0).shape, "(a batch of 1 table)")
A common use is turning one item into a "batch of 1", for example one table (2, 3) into (1, 2, 3), because many machine-learning libraries expect a batch axis first.
8. np.squeeze: remove dimensions of size 1
squeeze is the opposite: it removes axes of size 1.
boxed = np.array([[[5], [6], [7]]])
print("boxed.shape :", boxed.shape)
print("squeeze(boxed) :", np.squeeze(boxed), np.squeeze(boxed).shape)
print("squeeze(boxed, axis=0).shape:", np.squeeze(boxed, axis=0).shape)
try:
np.squeeze(boxed, axis=1) # axis 1 has size 3, not 1
except ValueError as error:
print("Error:", error)
- Without
axis, every size-1 axis is removed:(1, 3, 1)becomes(3,). - With
axis=0, only that axis is removed:(3, 1). - You cannot squeeze an axis whose size is not 1. NumPy refuses rather than losing data.
9. Real example: marks compared to each student's average
marks = np.array([[78, 85, 92],
[88, 79, 95],
[65, 90, 81]])
average = marks.mean(axis=1) # shape (3,)
print("average per student :", average.round(1))
print("difference from own average:\n", (marks - average[:, np.newaxis]).round(1))
average has shape (3,), one value per student. To subtract each student's own average from their row, we need it as a column: average[:, np.newaxis] has shape (3, 1). Now every row gets its own average subtracted. Positive numbers mean "better than this student's average".
Exercises
Try these exercises on your own before moving on:
- Make a 2x5 array and print its transpose and both shapes.
- An image array has shape (height, width, channels) = (4, 6, 3). Use transpose to make it (channels, height, width).
- Turn np.array([1, 2, 3, 4]) into shape (4, 1) in three ways (newaxis, expand_dims, reshape).
- Squeeze an array of shape (1, 3, 1, 2). What is the new shape?
Summary
.Tswaps rows and columns; it is a view, not a copy.transpose(1, 0, 2)puts the axes in any order;swapaxes(a, b)exchanges two.arr[:, np.newaxis]makes a column,arr[np.newaxis, :]makes a row;Noneworks the same.np.expand_dimsadds an axis;np.squeezeremoves size-1 axes.- Adding an axis is how you make shapes fit for broadcasting.