NumPy: Shape Operations
Last updated: 2026-08-26
Shape Operations
1. What You'll Learn
- ❶ reshape doesn't copy data — it only changes metadata
- ❷
-1auto-infers dimension size - ❸ flatten vs ravel: copy vs view
- ❹ transpose / .T transposition
- ❺ newaxis for adding dimensions, squeeze for removing them
2. A Developer's True Story
(1) The Problem
Bob reshapes 12 data points from 3×4 to 4×3, thinking he's "rearranging memory" — but every reshape was copying data, killing his memory and speed.
(2) The Solution
Alice shows him a Mermaid diagram: "reshape only changes metadata — not a single byte of data moves. That's the secret to NumPy's speed." As long as an operation returns a view, no data is copied.
(3) The Payoff
Once Bob understood "view vs copy," his shape operation code used an order of magnitude less memory and ran several times faster. Only flatten truly copies; everything else — reshape, ravel, transpose, swapaxes — is a view.
3. Shape Operations in Detail
(1) How reshape Works
reshape changes the array's shape but does not copy data. It only modifies the array's metadata (shape and strides); the raw data in memory stays put.
import numpy as np
a = np.arange(12)
b = a.reshape(3, 4)
print(a.shape) # (12,)
print(b.shape) # (3, 4)
print(b.base is a) # True — b is a view of a
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
# reshape does NOT copy data
b[0, 0] = 999
print(a[0]) # 999 — modifying b changes a!
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
reshape Memory Diagram
graph LR
A["Original Array<br/>shape=(12,)"] -->|"reshape(3,4)"| B["View<br/>shape=(3,4)"]
A -->|"reshape(4,3)"| C["View<br/>shape=(4,3)"]
A -->|"reshape(2,6)"| D["View<br/>shape=(2,6)"]
style A fill:#4CAF50,color:#fff
style B fill:#2196F3,color:#fff
style C fill:#FF9800,color:#fff
style D fill:#9C27B0,color:#fff
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
Key point: A, B, C, and D all share the same memory — they just "interpret" it differently.
(2) -1 Auto-Inference
Use -1 in reshape to let NumPy automatically compute that dimension's size.
a = np.arange(12)
# NumPy infers: 12 / 3 = 4
b = a.reshape(3, -1) # shape = (3, 4)
c = a.reshape(2, -1) # shape = (2, 6)
d = a.reshape(-1, 6) # shape = (2, 6)
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
(3) flatten vs ravel
| Method | Returns | Copies? | Memory |
|---|---|---|---|
ndarray.flatten() |
1D array | Always copies | New memory |
ndarray.ravel() |
1D array | View when possible | Usually shared |
import numpy as np
a = np.arange(12).reshape(3, 4)
f = a.flatten() # always a copy
r = a.ravel() # usually a view
f[0] = 999
print(a[0, 0]) # 0 — f is a copy, a unchanged
r[0] = 999
print(a[0, 0]) # 999 — r is a view, a changed
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
(4) transpose and .T
import numpy as np
a = np.arange(12).reshape(3, 4)
print(a.shape) # (3, 4)
b = a.T # transpose — view, no copy
print(b.shape) # (4, 3)
# For multi-dimensional arrays, transpose accepts an axis order
c = a.transpose(1, 0)
print(c.shape) # (4, 3)
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
(5) newaxis and squeeze
import numpy as np
a = np.array([1, 2, 3]) # shape (3,)
# newaxis adds a dimension
b = a[np.newaxis, :] # shape (1, 3)
c = a[:, np.newaxis] # shape (3, 1)
d = a[np.newaxis, :, np.newaxis] # shape (1, 3, 1)
# squeeze removes dimensions of size 1
e = np.squeeze(d) # shape (3,) — back to original
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
▶ Example
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
: reshape with -1 auto-inference (Difficulty ⭐)
import numpy as np
a = np.arange(24)
# Use -1 for auto-inference
b = a.reshape(2, -1) # 2 x 12
c = a.reshape(3, -1) # 3 x 8
d = a.reshape(4, -1) # 4 x 6
e = a.reshape(6, -1) # 6 x 4
print(f"a.shape={a.shape}")
print(f"b.shape={b.shape}") # (2, 12)
print(f"c.shape={c.shape}") # (3, 8)
print(f"d.shape={d.shape}") # (4, 6)
print(f"e.shape={e.shape}") # (6, 4)
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
▶ Example
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
: flatten vs ravel — copy vs view (Difficulty ⭐⭐)
import numpy as np
a = np.arange(12).reshape(3, 4)
# flatten always copies
flat = a.flatten()
flat[0] = 999
print("After flat[0]=999, a[0,0]=", a[0,0]) # 0 (unchanged)
# ravel usually returns a view
rav = a.ravel()
rav[0] = 999
print("After rav[0]=999, a[0,0]=", a[0,0]) # 999 (changed!)
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
▶ Example
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
: transpose and newaxis (Difficulty ⭐⭐)
import numpy as np
a = np.arange(12).reshape(3, 4)
# Transpose
print("Original shape:", a.shape) # (3, 4)
print("Transposed shape:", a.T.shape) # (4, 3)
# newaxis: add dimensions
row = np.array([1, 2, 3])
print("row shape:", row.shape) # (3,)
print("row[np.newaxis,:] shape:", row[np.newaxis, :].shape) # (1, 3)
print("row[:,np.newaxis] shape:", row[:, np.newaxis].shape) # (3, 1)
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
4. Comparison Tables
(1) Shape Operations Summary
| Operation | Returns | Copies Data? | Use Case |
|---|---|---|---|
reshape |
View | No | Change shape |
flatten |
Copy | Yes | Safe 1D conversion |
ravel |
View (usually) | Rarely | Fast 1D |
T / transpose |
View | No | Axis reordering |
newaxis |
View | No | Add dimension |
squeeze |
View | No | Remove size-1 dims |
swapaxes |
View | No | Swap two axes |
(2) View vs Copy
| Feature | View | Copy |
|---|---|---|
| Memory | Shared | New allocation |
| Modification | Affects original | Independent |
| Speed | O(1) | O(n) |
base attribute |
Points to original | None |
| When to use | Read-only or intentional sharing | Safe modification |
5. Principle Diagram
graph TB
A["Original (12,)"] -->|reshape/flatten/ravel| B["New shape"]
A --> C["data buffer: [0 1 2 ... 11]"]
B --> C
B -->|flatten| D["copy of data buffer"]
B -->|ravel| C
B -->|transpose| C
B -->|newaxis| C
style A fill:#4CAF50,color:#fff
style C fill:#FF9800,color:#fff
style D fill:#E91E63,color:#fff
❓ FAQ
np.ascontiguousarray() first if needed..T is a shortcut for reversing all axes (equivalent to .transpose() with reversed order). For 2D arrays they're identical. For 3D+, .T reverses all axes, while .transpose(1,0,2) lets you specify the order.total_size / product_of_other_dims.📖 Summary
- reshape only changes shape/strides metadata — no data copy, O(1) operation
-1auto-infers dimension size from the total element count- flatten always copies; ravel usually returns a view (check
.base) - transpose/T/swapaxes return views with modified strides, no data movement
- newaxis adds a dimension of size 1; squeeze removes size-1 dimensions
- Understanding view vs copy is key to writing memory-efficient NumPy code
📝 Exercises
-
Beginner (Difficulty ⭐): Create an array of 20 elements, reshape it to (4,5), (5,4), (2,10), and (10,2) using
-1. Verify all shapes are correct. -
Intermediate (Difficulty ⭐⭐): Create a 3x4 array, transpose it, then try to reshape the transposed result. Does reshape still avoid copying? Check with
.base. -
Advanced (Difficulty ⭐⭐⭐): Create a 3D array with shape (2,3,4). Use
transpose(2,0,1)to reorder axes. Explain what each dimension represents in the result. Then useswapaxesto achieve the same result.