Fun with Learning Technology
LearnCoursesQuestionsTracksToolsNewsExplorePractice
Fun with Learning Technology

A new problem, explained clearly, every day.

Subscribe
Learn
  • Lessons
  • Topics
  • News
  • Tools
  • Courses
  • Career tracks
  • Everything
Site
  • About
  • Contact
  • Support
  • Privacy
  • Terms
Get the daily one

One email per new problem. No spam.

Request a tutorial

Requests shape what gets made next.

© 2026 Fun with Learning TechnologyRSS
Home›Courses›NumPy›Reshaping and Transposing

Manipulation

Reshaping and Transposing

Reshaping and transposing are fundamental operations that change the structure of arrays without modifying their underlying data. These techniques allow developers to align array dimensions with the requirements of mathematical algorithms and machine learning models. You should use them whenever the logical layout of your data needs to be adjusted for efficient computation or broadcasting compatibility.

Understanding the Contiguous Memory Layout

To master reshaping, one must first understand that a NumPy array is essentially a contiguous block of memory coupled with a 'strides' metadata object. When you perform a reshape, NumPy does not necessarily create a copy of the data in memory; instead, it creates a new view by updating the strides. The strides determine how many bytes to skip in memory to move to the next element along a specific axis. Because the total number of elements must remain constant, reshaping is restricted by the product of the dimensions. If you change the shape of an array, you are simply telling NumPy to traverse the same raw memory block using different step sizes. This 'zero-copy' design makes reshaping an extremely cheap operation, allowing you to manipulate complex multi-dimensional data structures without incurring the overhead of memory allocation or data duplication, provided the operation remains within the constraints of the original data layout.

import numpy as np

# Create a flat array of 12 elements
data = np.arange(12)
# Reshape into a 3x4 matrix
# This creates a view, not a copy
matrix = data.reshape((3, 4))
print(f"New shape: {matrix.shape}")
print(f"Strides: {matrix.strides}")

The Logic of the 'Reshape' Method

The reshape method acts as a structural transformation tool that re-interprets existing data under a new dimensionality. The core rule governing reshape is that the total count of elements, known as the size, must be preserved. If you have a one-dimensional array of twelve items, you can reshape it into a 2x6, 3x4, or 4x3 matrix because these dimensions are factors of twelve. NumPy provides a special convenience feature where you can use '-1' as a placeholder for one dimension. When you specify -1, NumPy automatically calculates the required size for that dimension by dividing the total number of elements by the product of the other specified dimensions. This is particularly useful when you have a known number of rows or columns but want to allow the array size to fluctuate slightly, ensuring your code remains robust and adaptable to varying input sizes without manual arithmetic.

import numpy as np

# Convert a flat array into 2 columns, inferring rows
# Using -1 tells numpy to figure out the correct size
auto_reshaped = np.arange(20).reshape(-1, 2)
print(f"Inferred rows: {auto_reshaped.shape[0]}")
print(auto_reshaped)

Transposing and Axis Swapping

Transposing is a special type of reshaping where the axes of the array are swapped. For a two-dimensional matrix, the transpose operation swaps the rows and columns, effectively mirroring the matrix across its diagonal. The fundamental reason this works is the alteration of the strides attribute: if an array has dimensions (M, N), its transpose has dimensions (N, M), and the strides for the first and second dimensions are swapped. This operation is again a view-based operation, meaning it is highly memory efficient. Transposing is critical when performing matrix multiplication, as the inner dimensions of two arrays must align for the operation to succeed. By understanding that transposition is merely a change in how we interpret the coordinate system of the data, you can easily perform complex rotations or alignment tasks, ensuring your data is always oriented correctly for mathematical operations such as dot products.

import numpy as np

# A 2x3 matrix
matrix = np.array([[1, 2, 3], [4, 5, 6]])
# Transpose using the .T attribute
transposed = matrix.T
print(f"Original shape: {matrix.shape}")
print(f"Transposed shape: {transposed.shape}")

Expanding and Squeezing Dimensions

Often, you will encounter situations where your data dimensions do not align with the expectations of an algorithm, such as when a model expects a batch dimension. You can add a new axis using np.newaxis or the np.expand_dims function. Adding an axis does not change the number of elements; it simply increases the rank of the array by inserting a dimension of size one. Conversely, the squeeze function is used to remove all axes of size one, effectively reducing the array's dimensionality. This is incredibly common when performing operations where singleton dimensions have been created, such as after slicing or indexing. By mastering the art of 'expanding' and 'squeezing', you ensure that your data structure perfectly conforms to the requirements of various vectorized functions, preventing errors that occur due to shape mismatches during broadcasted operations.

import numpy as np

# Add a dimension to make it (1, 5)
arr = np.array([1, 2, 3, 4, 5])
expanded = arr[np.newaxis, :]
# Remove the dimension back to (5,)
squeezed = np.squeeze(expanded)
print(f"Expanded shape: {expanded.shape}")

Flattening and Raveling for Data Normalization

Flattening is the inverse of reshaping into higher dimensions; it collapses an N-dimensional array into a single contiguous one-dimensional vector. While both flatten() and ravel() achieve this, there is a nuanced difference: flatten() always returns a copy of the data, whereas ravel() returns a view whenever possible. When performance is critical and you are working with large datasets, choosing the correct method is vital to avoid unnecessary memory allocation. The logic here follows standard row-major (C-style) traversal by default, though you can specify column-major (Fortran-style) ordering if needed. Flattening is a necessary step when moving from multi-dimensional feature representation back into a linear sequence, which is often required before feeding data into a flat classifier or an input layer that does not support multi-dimensional structure.

import numpy as np

# Multi-dimensional grid
grid = np.array([[1, 2], [3, 4]])
# Convert to 1D vector
flat_view = grid.ravel()
# Modify view affects original
flat_view[0] = 99
print(f"Original modified: {grid[0, 0]}")

Key points

  • Reshaping relies on modifying array strides rather than copying data whenever possible.
  • The total number of elements must remain consistent when changing the shape of an array.
  • Using -1 in a reshape command allows NumPy to infer one dimension based on the total element count.
  • Transposition effectively swaps the rows and columns by reordering the internal axis strides.
  • Expanding dimensions via newaxis is essential for preparing arrays for broadcasting against others.
  • Squeezing removes unnecessary singleton dimensions that can complicate array arithmetic.
  • The ravel method is typically faster than flatten because it returns a view instead of a copy.
  • Understanding memory layout is the key to predicting how reshape and transpose operations will behave.

Common mistakes

  • Mistake: Expecting reshape() to modify the array in-place. Why it's wrong: reshape() returns a new view of the original array; it does not change the original object. Fix: Assign the result to a new variable or use resize() for in-place modification.
  • Mistake: Confusing the behavior of .T with transpose(). Why it's wrong: While .T is a convenient shorthand for 2D arrays, users often forget it only handles 1D/2D; transpose() allows axis permutation for n-dimensional arrays. Fix: Use transpose() or swapaxes() for higher-dimensional arrays.
  • Mistake: Miscalculating the product of dimensions when reshaping. Why it's wrong: The total number of elements must remain constant; otherwise, NumPy raises a ValueError. Fix: Calculate total elements or use -1 as a placeholder for one dimension.
  • Mistake: Thinking reshape(-1, 1) and reshape(1, -1) produce the same array. Why it's wrong: The first produces a column vector (n x 1), while the second produces a row vector (1 x n). Fix: Be explicit about dimension order when using the -1 placeholder.
  • Mistake: Neglecting the memory layout during complex reshaping. Why it's wrong: Reshaping might return a non-contiguous view if the original array's memory layout isn't compatible. Fix: Use .copy() if you need to ensure the new array is stored in a contiguous memory block.

Interview questions

What is the primary difference between using reshape() and resize() in NumPy?

The primary difference lies in how they handle the original array and memory. The reshape() method returns a new view of the original array with a modified shape without changing the actual data in memory, provided the total number of elements remains identical. In contrast, the resize() method modifies the array in-place and can actually change the total number of elements by either padding with zeros or truncating the data, which makes it far more destructive and less predictable than the non-destructive reshaping approach.

How does the transpose() method or the .T attribute change the internal structure of a NumPy array?

When you use transpose() or the .T attribute, NumPy does not actually move the data around in physical memory. Instead, it returns a new view of the array with the dimensions swapped by modifying the strides. Strides represent the number of bytes to step in memory to reach the next element in a specific dimension. By simply updating these stride values, NumPy can interpret the data in a new order efficiently, which makes transposition an extremely fast operation regardless of the size of the array.

Explain the role of the -1 argument when using the reshape() function.

The -1 argument acts as a placeholder for an unknown dimension. When you call reshape(rows, -1), you are instructing NumPy to calculate the size of that dimension automatically based on the total number of elements present in the array. This is incredibly useful because it prevents manual calculation errors. For example, if you have an array of 100 elements and call reshape(2, -1), NumPy determines the second dimension must be 50, ensuring that the total count remains consistent with the original data volume.

Compare using flatten() versus ravel() in terms of memory efficiency and performance.

The key difference is that flatten() always returns a new, independent copy of the array data, whereas ravel() returns a view whenever possible. Because ravel() avoids copying data unless absolutely necessary—such as when the memory is non-contiguous—it is generally faster and significantly more memory-efficient for large datasets. If you intend to modify the output and want to ensure the original array remains untouched, use flatten(); otherwise, always choose ravel() to save system resources and speed up execution.

How can you use swapaxes() to manipulate multidimensional arrays compared to using moveaxis()?

The swapaxes() function is designed to interchange exactly two axes of an array, which is ideal for simple orientation adjustments like swapping rows and columns in a 2D matrix. However, moveaxis() is more versatile because it allows you to move an axis to a new position while shifting the other axes accordingly. If you need to perform complex reorganization of a high-dimensional tensor where multiple axes must be shifted, moveaxis() provides much better control and readability than attempting multiple consecutive swapaxes() calls.

How do you add a new dimension to a NumPy array using np.newaxis or expand_dims(), and why is this commonly required?

You can add a new dimension by indexing with np.newaxis or using the expand_dims() function, which inserts a new axis of size 1 at the specified position. This is commonly required for broadcasting operations, where NumPy requires array shapes to be compatible. For instance, if you have a 1D array of shape (N,) and need to add it to a 2D matrix of shape (M, N), you must expand the 1D array to (1, N) to allow NumPy to broadcast the addition across all rows of the matrix effectively.

All NumPy interview questions →

Check yourself

1. You have a 1D array of shape (12,). Which operation effectively transforms it into a 3x4 matrix?

  • A.arr.reshape(3, 4)
  • B.arr.transpose(3, 4)
  • C.arr.resize(3, 4)
  • D.arr.swapaxes(3, 4)
Show answer

A. arr.reshape(3, 4)
reshape(3, 4) creates a new view with the requested dimensions. Transpose only swaps existing axes, resize is for in-place modification without returning a new view, and swapaxes expects axis indices, not new dimensions.

2. What is the result of using -1 in a reshape command: arr.reshape(-1, 2)?

  • A.It throws an error because -1 is an invalid dimension.
  • B.It sets the first dimension to 1 by default.
  • C.It automatically calculates the first dimension based on the total array size and the specified second dimension.
  • D.It removes the first dimension entirely.
Show answer

C. It automatically calculates the first dimension based on the total array size and the specified second dimension.
-1 tells NumPy to infer the size of that dimension based on the remaining elements. The other options are incorrect as NumPy is designed to handle this inference for convenience, and -1 is a valid placeholder, not an error.

3. If 'a' is a 3D array of shape (2, 3, 4), what is the shape of 'a.T'?

  • A.(4, 3, 2)
  • B.(2, 3, 4)
  • C.(3, 4, 2)
  • D.(4, 2, 3)
Show answer

A. (4, 3, 2)
The .T attribute reverses the order of dimensions for an array. For (2, 3, 4), reversing yields (4, 3, 2). The other options represent incorrect permutations.

4. Which method is specifically used to swap two axes of an array?

  • A.reshape()
  • B.flatten()
  • C.swapaxes()
  • D.ravel()
Show answer

C. swapaxes()
swapaxes() is designed to interchange two specified axes. reshape and ravel change the shape/dimensionality, while flatten returns a copy of the array collapsed into one dimension.

5. How does ravel() differ from flatten()?

  • A.ravel() returns a copy, while flatten() returns a view.
  • B.ravel() returns a view whenever possible, while flatten() always returns a copy.
  • C.ravel() only works on 1D arrays, while flatten() works on nD arrays.
  • D.There is no difference; they are aliases for the same function.
Show answer

B. ravel() returns a view whenever possible, while flatten() always returns a copy.
ravel() returns a view of the original array if possible, making it more memory-efficient. flatten() guarantees a new copy. The other statements incorrectly describe their return types or dimensionality constraints.

Take the full NumPy quiz →

← PreviousComparison and Logical OperationsNext →Stacking — vstack, hstack, concatenate

NumPy

26 lessons, free to read.

All lessons →

Track your progress

Sign in to mark lessons done, score quizzes and keep notes.

Open in the app