Adding Axes: newaxis & expand_dims
Reviewed & published by Brayan K
np.newaxis (and its function form np.expand_dims) inserts a new length-1 dimension into an array, reshaping a flat vector into a row or a column so that broadcasting can combine it with other arrays.
Part of the free NumPy course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
You'll add axes with newaxis and expand_dims, remove size-1 axes with squeeze, and use a column-versus-row vector to build a grid of values entirely through broadcasting.
What You'll Learn in This Lesson
- What np.newaxis (and None) does to a shape
- Make a column vector with arr[:, np.newaxis]
- Make a row vector with arr[np.newaxis, :]
- Insert an axis by number with np.expand_dims
- Remove size-1 axes with np.squeeze
- Combine a column and row to broadcast a grid
1 np.newaxis: Rows and Columns from a Vector
A 1D array of shape (3,) is neither a row nor a column — it is just a flat sequence. Indexing with np.newaxis (which is literally None) inserts a length-1 axis to give it a 2D shape. Put the new axis last for a column (3, 1), or first for a row (1, 3).
import numpy as np
v = np.array([1, 2, 3]) # shape (3,)
v[:, np.newaxis] # shape (3, 1) -> column
# [[1]
# [2]
# [3]]
v[np.newaxis, :] # shape (1, 3) -> row
# [[1 2 3]]import numpy as np
v = np.array([1, 2, 3])
print(v.shape) # (3,)
col = v[:, np.newaxis]
print(col.shape) # (3, 1)
print(col)
# [[1]
# [2]
# [3]]
row = v[np.newaxis, :]
print(row.shape) # (1, 3)
print(row)
# [[1 2 3]]
# ✅ Expected output:
# (3,)
# (3, 1)
# [[1]
# [2]
# [3]]
# (1, 3)
# [[1 2 3]]2 expand_dims to Add, squeeze to Remove
np.expand_dims(arr, axis) does the same job as newaxis but as a function call, which is handy when the axis number is computed. Its inverse is np.squeeze, which deletes every length-1 axis (or just the one you name), collapsing a shape like (1, 3, 1) back down to (3,).
v = np.array([1, 2, 3])
np.expand_dims(v, axis=0).shape # (1, 3)
np.expand_dims(v, axis=1).shape # (3, 1)
a = np.zeros((1, 3, 1))
np.squeeze(a).shape # (3,)
np.squeeze(a, axis=0).shape # (3, 1)import numpy as np
v = np.array([1, 2, 3])
# expand_dims: add a size-1 axis by number
print(np.expand_dims(v, axis=0).shape) # (1, 3)
print(np.expand_dims(v, axis=1).shape) # (3, 1)
# squeeze: remove size-1 axes
a = np.zeros((1, 3, 1))
print(a.shape) # (1, 3, 1)
print(np.squeeze(a).shape) # (3,)
print(np.squeeze(a, axis=2).shape) # (1, 3)
# ✅ Expected output:
# (1, 3)
# (3, 1)
# (1, 3, 1)
# (3,)
# (1, 3)3 The Payoff: Broadcasting a Grid
The main reason to add axes is to unlock broadcasting. Make one vector a column (n, 1) and another a row (1, m); combining them stretches each across the other to produce an (n, m) grid. This is how you build an addition table or an outer product without any loops — a lighter-weight alternative to meshgrid.
a = np.array([1, 2, 3]) # will be the column
b = np.array([10, 20]) # will be the row
a[:, None] + b[None, :] # shape (3, 2)
# [[11 21]
# [12 22]
# [13 23]]import numpy as np
a = np.array([1, 2, 3])
b = np.array([10, 20, 30])
# Column (3, 1) + row (1, 3) -> a full (3, 3) addition table
table = a[:, np.newaxis] + b[np.newaxis, :]
print(table.shape) # (3, 3)
print(table)
# [[11 21 31]
# [12 22 32]
# [13 23 33]]
# Same idea makes a multiplication (outer) product
print(a[:, None] * b[None, :])
# [[10 20 30]
# [20 40 60]
# [30 60 90]]
# ✅ Expected output:
# (3, 3)
# [[11 21 31]
# [12 22 32]
# [13 23 33]]
# [[10 20 30]
# [20 40 60]
# [30 60 90]]🎯 YOUR TURN: Fill in the Blank
Turn v into a column vector of shape (4, 1) by filling in the indexing token.
import numpy as np
v = np.array([5, 6, 7, 8])
# Insert a NEW axis at the end to make a column vector
col = v[:, np.___]
print(col.shape) # (4, 1)
print(col)
# Expected output:
# [[5]
# [6]
# [7]
# [8]]Answer: newaxis (so v[:, np.newaxis]). You could also write v[:, None].
! Common Errors (And How to Fix Them)
❌ Two 1D arrays will not broadcast into a grid
Adding two shape-(3,) arrays just adds them element-wise, not as a table:
a + b # shape (3,), an element-wise sum, NOT a (3, 3) grid✅ Fix: add axes so one is a column and one is a row:
a[:, None] + b[None, :] # shape (3, 3)❌ squeeze removed an axis you wanted to keep
A bare np.squeeze(arr) drops every size-1 axis at once.
✅ Fix: name the axis, e.g. np.squeeze(arr, axis=0), to remove only that one.
❌ Wrong axis position for the new dimension
v[np.newaxis, :] makes a row, v[:, np.newaxis] makes a column — easy to swap.
✅ Fix: print .shape after adding the axis to confirm it is (1, n) or (n, 1).
🎯 Mini Challenge: Pairwise Differences
Use newaxis to compute the difference between every pair of values in a vector — a common step in distance calculations.
import numpy as np
points = np.array([0, 3, 7])
# Subtract every value from every value: column - row
diffs = points[:, np.newaxis] - points[np.newaxis, :]
print(diffs.shape) # (3, 3)
print(diffs)
# [[ 0 -3 -7]
# [ 3 0 -4]
# [ 7 4 0]]
# Absolute pairwise distances
print(np.abs(diffs))
# [[0 3 7]
# [3 0 4]
# [7 4 0]]
# ✅ Expected output:
# (3, 3)
# [[ 0 -3 -7]
# [ 3 0 -4]
# [ 7 4 0]]
# [[0 3 7]
# [3 0 4]
# [7 4 0]]❓ Frequently Asked Questions
Lesson complete — you can reshape with new axes!
You can insert a length-1 dimension with np.newaxis or np.expand_dims, remove one with np.squeeze, and use a column-versus-row pairing to broadcast a full grid.
Practice quiz
What is np.newaxis literally equal to?
- None
- 0
- An empty array
- 1
Answer: None. np.newaxis is just an alias for Python's None, so v[:, None] and v[:, np.newaxis] are identical.
What shape does v[:, np.newaxis] give a shape-(3,) array?
- (1, 3)
- (3, 1)
- (3,)
- (3, 3)
Answer: (3, 1). Putting the new axis last makes a column vector of shape (3, 1).
What shape does v[np.newaxis, :] give a shape-(3,) array?
- (3, 1)
- (3, 3)
- (1, 3)
- (3,)
Answer: (1, 3). Putting the new axis first makes a row vector of shape (1, 3).
Which function inserts a size-1 axis using a number argument?
- np.squeeze
- np.reshape
- np.ravel
- np.expand_dims
Answer: np.expand_dims. np.expand_dims(arr, axis=1) adds a length-1 axis at the given position, the function form of newaxis.
What does np.squeeze do by default?
- Removes every length-1 axis
- Adds a new axis
- Flattens to 1D always
- Transposes the array
Answer: Removes every length-1 axis. Bare np.squeeze drops all size-1 dimensions; name an axis to remove just one.
What shape does np.expand_dims(v, axis=0) produce from shape (3,)?
- (3, 1)
- (1, 3)
- (3,)
- (3, 3)
Answer: (1, 3). axis=0 inserts the new length-1 axis first, giving (1, 3).
To broadcast a column against a row into an (n, m) grid, you need...
- Two 1D arrays of the same length
- One (n, 1) and one (1, m) array
- Two scalars
- A single (n, m) array
Answer: One (n, 1) and one (1, m) array. A column (n, 1) and a row (1, m) broadcast into an (n, m) grid.
Does adding an axis with newaxis move or copy the underlying data?
- It copies all the data
- It sorts the data
- No, only the shape changes
- It deletes elements
Answer: No, only the shape changes. newaxis only changes the shape metadata; the data is never moved.
Which removes only the first axis from shape (1, 3, 1)?
- np.squeeze(a, axis=0)
- np.squeeze(a)
- np.expand_dims(a, 0)
- a.ravel()
Answer: np.squeeze(a, axis=0). Naming axis=0 removes only that size-1 axis, leaving (3, 1).
What does a[:, None] + b[None, :] compute for 1D a and b?
- An element-wise sum
- A scalar
- A broadcast grid of pairwise sums
- An error
Answer: A broadcast grid of pairwise sums. Pairing a column with a row broadcasts into a full 2D grid of pairwise sums.
Continue this course
- Previous: Repeating Arrays: tile & repeat
- Next: Transposing & Swapping Axes — Reorder dimensions with .T, transpose, swapaxes, and moveaxis
- Quick reference: NumPy cheat sheet
Frequently asked questions
What does np.newaxis actually do?
np.newaxis is just an alias for Python's None, and using it inside indexing inserts a new dimension of length 1 at that position. arr[:, np.newaxis] turns a shape (3,) array into shape (3, 1), and arr[np.newaxis, :] turns it into (1, 3). The data is unchanged; only the shape gains a size-1 axis that broadcasting can stretch.
What is the difference between np.newaxis and np.expand_dims?
They do the same thing in two styles. arr[:, np.newaxis] uses indexing syntax, while np.expand_dims(arr, axis=1) is a function call that inserts a size-1 axis at the given position. expand_dims is often clearer in code that computes the axis number, while newaxis is more compact inline.
How do I remove dimensions of length 1?
Use np.squeeze. np.squeeze(arr) drops every axis whose length is 1, turning shape (1, 3, 1) into (3,). Pass an axis argument like np.squeeze(arr, axis=0) to remove only a specific size-1 axis. It is the inverse of adding axes with newaxis or expand_dims.
Why do I need to add an axis to broadcast a column against a row?
To form an outer-product-style grid, one operand must vary down the rows and the other across the columns. A plain 1D array only varies along one axis. By making one a column vector with shape (n, 1) and the other a row vector with shape (1, m), broadcasting expands them into an (n, m) result. newaxis is the tool that creates those size-1 axes.