Shape and reshape

NumPy · Essentials · 10 min

Data rarely arrives in the shape an operation needs; reshaping is how you line it up without copying.

An array's shape is just a view of a flat sequence of values. a.reshape(new_shape) reinterprets the same elements with new dimensions, as long as the total size matches. One dimension may be -1, meaning "work it out": a.reshape(3, -1).

Order matters. By default NumPy fills and reads in row-major (C) order: the last axis changes fastest. np.arange(6).reshape(2, 3) gives rows [0 1 2] and [3 4 5].

Related tools:

  • a.ravel() flattens to 1-D, returning a view when possible; a.flatten() always copies.
  • a.T (or np.transpose) reverses the axes; for 2-D that swaps rows and columns.
  • a[:, np.newaxis] or a[:, None] inserts a length-1 axis, turning a shape (3,) vector into a (3, 1) column. np.expand_dims and np.squeeze add and remove such axes by position.

Reshape and transpose usually return views: no data is copied, and writing through the view changes the original. That makes them nearly free, even on huge arrays.

A common confusion: a 1-D array of shape (3,) is neither a row nor a column. Transposing it does nothing. If an operation needs an explicit column, reshape to (3, 1).

Axes are numbered from 0. For a shape (2, 3) array, axis 0 runs down the rows (length 2) and axis 1 across the columns (length 3). That numbering is used everywhere: in aggregations, concatenation and broadcasting.

Example

import numpy as np

a = np.arange(6)
m = a.reshape(2, 3)
print(m)
# [[0 1 2]
#  [3 4 5]]
print(a.reshape(3, -1).shape)    # (3, 2)
print(m.T.shape)                 # (3, 2)
print(m.ravel())                 # [0 1 2 3 4 5]

v = np.array([1, 2, 3])
print(v.T.shape)                 # (3,)  -- 1-D: transpose is a no-op
col = v[:, np.newaxis]
print(col.shape)                 # (3, 1)
print(np.squeeze(col).shape)     # (3,)

m[0, 0] = 99                     # m is a view of a
print(a[0])                      # 99

Remember

  • reshape keeps the data and changes the shape; use -1 for one inferred axis
  • Default ordering is row-major: the last axis varies fastest
  • None/np.newaxis adds a length-1 axis; squeeze removes them
  • Reshape, ravel and .T usually return views, not copies

Watch out for

  • Calling .T on a 1-D array to make a column vector; reshape to (n, 1) instead.

Check yourself

  1. `a = np.arange(12).reshape(3, 4)`. What is `a[1]`?
  2. What shape does `np.zeros(5)[None, :]` have?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: numpy.org/doc/stable/reference/generated/numpy.reshape.html