Reshaping Arrays¶
NumPy makes it cheap to re-view the same data with different shapes — without copying memory.
.reshape() — change the shape¶
The total number of elements must stay the same.
import numpy as np
a = np.arange(12)
print("Original:", a, "shape:", a.shape)
# 3 rows × 4 cols
b = a.reshape(3, 4)
print(b)
print("shape:", b.shape)
# 2 layers × 2 rows × 3 cols (3D)
c = a.reshape(2, 2, 3)
print(c)
print("shape:", c.shape)
-1 — "figure it out"¶
Let NumPy compute one dimension from the rest:
import numpy as np
a = np.arange(12)
print(a.reshape(3, -1).shape) # (3, 4) — second dim inferred
print(a.reshape(-1, 4).shape) # (3, 4) — first dim inferred
print(a.reshape(2, -1, 3).shape) # (2, 2, 3)
You can only use -1 once.
.flatten() and .ravel() — 1D again¶
Both turn any shape into a 1D array. Difference:
.flatten()returns a copy..ravel()returns a view when possible (faster, but changes propagate).
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]])
print(a.flatten()) # copy
print(a.ravel()) # view
For most cases, use ravel. Use flatten when you'll modify the result and want the original safe.
.T — transpose¶
Swap axes.
import numpy as np
a = np.array([
[1, 2, 3],
[4, 5, 6],
])
print("Original:")
print(a)
print("shape:", a.shape)
print("\nTransposed:")
print(a.T)
print("shape:", a.T.shape)
.T for 1D does nothing — there's only one axis. To "transpose" a 1D vector into a column:
import numpy as np
a = np.array([1, 2, 3])
print("a :", a.shape) # (3,)
print("a[:,None]:", a[:, None].shape) # (3, 1)
print("a[None,:]:", a[None, :].shape) # (1, 3)
np.transpose() and .swapaxes()¶
For arrays with > 2 dimensions:
import numpy as np
a = np.zeros((2, 3, 4)) # shape (2, 3, 4)
# Reverse all axes
print(a.T.shape) # (4, 3, 2)
# Custom — make axis 2 the first, axis 0 the second, axis 1 the third
print(np.transpose(a, (2, 0, 1)).shape) # (4, 2, 3)
# Just swap two axes
print(a.swapaxes(0, 2).shape) # (4, 3, 2)
Used a lot in deep learning: PyTorch tensors are (batch, channels, h, w), image libraries use (batch, h, w, channels). transpose converts between them.
Adding / removing dimensions¶
import numpy as np
a = np.array([1, 2, 3])
print(a.shape) # (3,)
# Add a dimension at the front
b = a[np.newaxis, :]
print(b.shape, b) # (1, 3)
# Add a dimension at the end
c = a[:, np.newaxis]
print(c.shape, c) # (3, 1)
# np.expand_dims is the explicit version
d = np.expand_dims(a, axis=0)
print(d.shape) # (1, 3)
# Remove dimensions of size 1
e = np.zeros((1, 3, 1, 5))
print(e.shape, "→", np.squeeze(e).shape)
Reshaping rules — what's actually happening¶
NumPy stores arrays as a flat buffer in memory. Reshape just gives the same buffer a different "interpretation":
[1, 2, 3, 4, 5, 6] (flat buffer of length 6)
reshape(2, 3): reshape(3, 2):
[[1, 2, 3], [[1, 2],
[4, 5, 6]] [3, 4],
[5, 6]]
Order: row-by-row (C-order, the default). To use column-major (Fortran-order):
import numpy as np
a = np.arange(6)
print(a.reshape(2, 3, order="C")) # row-major (default)
print(a.reshape(2, 3, order="F")) # column-major
A common pattern — preparing data for ML¶
import numpy as np
# Imagine 100 grayscale 8x8 images
images = np.random.default_rng(0).random((100, 8, 8))
print("images shape:", images.shape)
# Flatten each image to a feature vector
flat = images.reshape(100, -1)
print("flat shape: ", flat.shape) # (100, 64) — 64 features per image
This is exactly what sklearn expects: rows = samples, columns = features.
Mini-exercise — reverse a 2D image vertically¶
import numpy as np
img = np.array([
[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3],
[4, 4, 4, 4],
])
# Flip vertically
print(np.flip(img, axis=0))
# Flip horizontally
print(np.flip(img, axis=1))
# 90-degree rotation
print(np.rot90(img))
Reshape quick-reference¶
| Goal | Method |
|---|---|
| Change shape | arr.reshape(new_shape) |
| Let NumPy infer one dim | arr.reshape(2, -1) |
| Flatten (copy) | arr.flatten() |
| Flatten (view, fast) | arr.ravel() |
| Swap rows and cols | arr.T |
| Custom axis swap | np.transpose(arr, (2,0,1)) |
| Add a dimension | arr[None, :] or np.expand_dims(arr, axis=0) |
| Remove size-1 dims | np.squeeze(arr) |
| Flip an axis | np.flip(arr, axis=...) |
| Rotate 90° | np.rot90(arr) |
Common pitfalls¶
- ❗ Wrong number of elements —
reshaperaisesValueErrorif the new shape doesn't fit. 12 elements can be reshaped to (3, 4) but not (4, 4). - ❗ Reshape returns a view, not a copy — modifying the result modifies the original. Use
.copy()if you need independence. - ❗
-1only once — you can't reshape to(-1, -1). Only one dimension can be inferred. - ❗
.Tdoes nothing on 1D — surprising. Use[:, None]to make a column. - ❗ Order matters for non-contiguous arrays — sometimes reshape can't return a view and silently makes a copy. For perf-critical code, check
arr.flags.c_contiguous.
Practice¶
What does this print?
Expected: (2, 3)
Make a and b independent (mutating b shouldn't affect a)
Expected: [1 2 3 4 5 6]
Quiz — Quick check¶
What you remember
Q1. What does -1 mean in arr.reshape(2, -1)?
- Reverse the array
- Drop the last element
- "Figure out this dimension automatically from the size"
- Use the default shape
Why:
-1is a placeholder NumPy fills in based on the total element count.arr.reshape(2, -1)for 12 elements gives shape(2, 6).
Q2. Difference between .flatten() and .ravel()?
- No difference
-
.flatten()returns a copy;.ravel()returns a view when possible -
.flatten()is faster -
.ravel()is deprecated
Why:
.ravel()is more memory-efficient (view) but modifying its result can affect the original. Use.flatten()when you need independence.
Q3. How do you convert a 1D array of shape (5,) into a column vector (5, 1)?
-
a.T -
a.reshape(5) -
a[:, None](ora.reshape(-1, 1)) -
a.transpose()
Why:
.Tdoes nothing on 1D arrays. To add a column dimension, usea[:, None](which inserts a new axis of size 1) ora.reshape(-1, 1).
Common doubts¶
Does reshape always return a view?
Usually yes — when the new shape is compatible with the underlying memory layout. For non-contiguous arrays (e.g. after slicing oddly), reshape may silently return a copy. Check arr.flags.owndata or result.base is arr if it matters.
When should I use np.transpose(a, axes) vs a.T?
For 2D, .T is the shortcut. For 3D+ where you need to swap specific axes (e.g. PyTorch's (N, C, H, W) vs (N, H, W, C) image layout), use np.transpose(a, (0, 2, 3, 1)) to specify the new order explicitly.
Why do I get -1 errors like 'cannot reshape array of size 10 into shape (3, -1)'?
Because 10 doesn't divide evenly by 3. The -1 slot still has to be an integer. Pick a first dimension that divides the total size (e.g. 5 or 2).