NumPy: reshape() to change the shape of an array

Modified: | Tags: Python, NumPy

In NumPy, to change the shape of an array (ndarray), use the reshape() method of ndarray or the np.reshape() function.

To check the shape and the number of dimensions of ndarray, refer to the following article.

reshape() can convert to any shape, but other methods exist for specific transformations.

Additionally, during binary operations like arithmetic, arrays automatically align shapes through broadcasting.

The NumPy version used in this article is as follows. Note that functionality may vary between versions.

import numpy as np

print(np.__version__)
# 1.26.1

How to use the reshape() method of ndarray

Consider the following one-dimensional NumPy array (ndarray) as an example.

a = np.arange(24)
print(a)
# [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]

print(a.shape)
# (24,)

print(a.ndim)
# 1

Specify the new shape with a list or tuple as the first argument.

a_4_6 = a.reshape([4, 6])
print(a_4_6)
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]
#  [12 13 14 15 16 17]
#  [18 19 20 21 22 23]]

print(a_4_6.shape)
# (4, 6)

print(a_4_6.ndim)
# 2
a_2_3_4 = a.reshape((2, 3, 4))
print(a_2_3_4)
# [[[ 0  1  2  3]
#   [ 4  5  6  7]
#   [ 8  9 10 11]]
# 
#  [[12 13 14 15]
#   [16 17 18 19]
#   [20 21 22 23]]]

print(a_2_3_4.shape)
# (2, 3, 4)

print(a_2_3_4.ndim)
# 3

A ValueError occurs if the shape does not match the number of elements in the original array.

# a_5_6 = a.reshape([5, 6])
# ValueError: cannot reshape array of size 24 into shape (5,6)

Instead of a list or tuple, you can also specify the values of each dimension in sequence.

print(a.reshape(4, 6))
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]
#  [12 13 14 15 16 17]
#  [18 19 20 21 22 23]]

print(a.reshape(2, 3, 4))
# [[[ 0  1  2  3]
#   [ 4  5  6  7]
#   [ 8  9 10 11]]
# 
#  [[12 13 14 15]
#   [16 17 18 19]
#   [20 21 22 23]]]

How to use the np.reshape() function

In the np.reshape() function, specify the original ndarray as the first argument and the new shape with a list or tuple as the second argument. A ValueError occurs if the shape does not match the number of elements in the original array.

a = np.arange(24)

print(np.reshape(a, [4, 6]))
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]
#  [12 13 14 15 16 17]
#  [18 19 20 21 22 23]]

print(np.reshape(a, (2, 3, 4)))
# [[[ 0  1  2  3]
#   [ 4  5  6  7]
#   [ 8  9 10 11]]
# 
#  [[12 13 14 15]
#   [16 17 18 19]
#   [20 21 22 23]]]

# print(np.reshape(a, [5, 6]))
# ValueError: cannot reshape array of size 24 into shape (5,6)

For np.reshape(), the second argument must be a list or tuple; providing dimensions sequentially, as with the ndarray.reshape() method, triggers a TypeError.

# print(np.reshape(a, 4, 6))
# TypeError: order must be str, not int

# print(np.reshape(a, 2, 3, 4))
# TypeError: reshape() takes from 2 to 3 positional arguments but 4 were given

Specify the conversion order: order

The conversion order can be specified with the order argument. order='C' (default) is for C language style and order='F' is for FORTRAN style.

The results differ as follows.

a = np.arange(24)

print(a.reshape([4, 6], order='C'))
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]
#  [12 13 14 15 16 17]
#  [18 19 20 21 22 23]]

print(a.reshape([4, 6], order='F'))
# [[ 0  4  8 12 16 20]
#  [ 1  5  9 13 17 21]
#  [ 2  6 10 14 18 22]
#  [ 3  7 11 15 19 23]]

print(a.reshape([2, 3, 4], order='C'))
# [[[ 0  1  2  3]
#   [ 4  5  6  7]
#   [ 8  9 10 11]]
# 
#  [[12 13 14 15]
#   [16 17 18 19]
#   [20 21 22 23]]]

print(a.reshape([2, 3, 4], order='F'))
# [[[ 0  6 12 18]
#   [ 2  8 14 20]
#   [ 4 10 16 22]]
# 
#  [[ 1  7 13 19]
#   [ 3  9 15 21]
#   [ 5 11 17 23]]]

The np.reshape() function also allows specifying the order in the same way.

print(np.reshape(a, [4, 6], order='F'))
# [[ 0  4  8 12 16 20]
#  [ 1  5  9 13 17 21]
#  [ 2  6 10 14 18 22]
#  [ 3  7 11 15 19 23]]

You need to specify order as a keyword in the ndarray.reshape() method to avoid TypeError, since this method supports sequential dimension specification.

In the np.reshape() function, order is accepted as the third positional argument, allowing you to specify it without the keyword.

# print(a.reshape([4, 6], 'F'))
# TypeError: 'list' object cannot be interpreted as an integer

print(np.reshape(a, [4, 6], 'F'))
# [[ 0  4  8 12 16 20]
#  [ 1  5  9 13 17 21]
#  [ 2  6 10 14 18 22]
#  [ 3  7 11 15 19 23]]

The meaning of -1 in reshape()

You can use -1 to specify the shape in reshape().

The following examples use the ndarray.reshape() method, but it is the same for the np.reshape() function.

The length of the dimension specified as -1 is automatically determined based on the values of the other dimensions. This is convenient when transforming the shape of large arrays.

a = np.arange(24)

print(a.reshape([4, -1]))
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]
#  [12 13 14 15 16 17]
#  [18 19 20 21 22 23]]

print(a.reshape([2, -1, 4]))
# [[[ 0  1  2  3]
#   [ 4  5  6  7]
#   [ 8  9 10 11]]
# 
#  [[12 13 14 15]
#   [16 17 18 19]
#   [20 21 22 23]]]

Only one dimension can be specified as -1. Specifying it for more than one dimension results in a ValueError.

# print(a.reshape([2, -1, -1]))
# ValueError: can only specify one unknown dimension

If no value satisfies the condition, it results in a ValueError.

# print(a.reshape([2, -1, 5]))
# ValueError: cannot reshape array of size 24 into shape (2,newaxis,5)

While not explicitly documented, negative values act like -1, automatically determining dimension length.

print(a.reshape([4, -100]))
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]
#  [12 13 14 15 16 17]
#  [18 19 20 21 22 23]]

reshape() returns a view

Both the ndarray.reshape() method and the np.reshape() function return a view wherever possible, rather than a copy. "Wherever possible" means that a copy is returned instead of a view depending on the memory layout.

For more details on views and copies in NumPy, refer to the following article.

The following examples use the ndarray.reshape() method, but it is the same for the np.reshape() function.

reshape() returns a view and shares memory with the original ndarray.

a = np.arange(8)
print(a)
# [0 1 2 3 4 5 6 7]

a_2_4 = a.reshape([2, 4])
print(a_2_4)
# [[0 1 2 3]
#  [4 5 6 7]]

print(np.shares_memory(a, a_2_4))
# True

Changing the original object affects the view returned by reshape().

a[0] = 100
print(a)
# [100   1   2   3   4   5   6   7]

print(a_2_4)
# [[100   1   2   3]
#  [  4   5   6   7]]

The same applies to the reverse case. Changing the view returned by reshape() also affects the original object.

a_2_4[0, 0] = 0
print(a_2_4)
# [[0 1 2 3]
#  [4 5 6 7]]

print(a)
# [0 1 2 3 4 5 6 7]

Use copy() to create a copy. In this case, changing each object does not affect the other object.

a_2_4_copy = a.reshape([2, 4]).copy()
print(a_2_4_copy)
# [[0 1 2 3]
#  [4 5 6 7]]

print(np.shares_memory(a, a_2_4_copy))
# False

a[0] = 100
print(a)
# [100   1   2   3   4   5   6   7]

print(a_2_4_copy)
# [[0 1 2 3]
#  [4 5 6 7]]

a_2_4_copy[0, 0] = 200
print(a_2_4_copy)
# [[200   1   2   3]
#  [  4   5   6   7]]

print(a)
# [100   1   2   3   4   5   6   7]

For example, when reshape() is applied to slices with steps, and this leads to irregular memory strides, a copy is returned instead of a view.

a = np.arange(8).reshape(2, 4)
print(a)
# [[0 1 2 3]
#  [4 5 6 7]]

a_step3 = a[:, ::3]
print(a_step3)
# [[0 3]
#  [4 7]]

a_step3_reshape = a_step3.reshape(-1)
print(a_step3_reshape)
# [0 3 4 7]

print(np.shares_memory(a_step3, a_step3_reshape))
# False

If the strides remain constant even with slices with step, a view is returned.

a_step2 = a[:, ::2]
print(a_step2)
# [[0 2]
#  [4 6]]

a_step2_reshape = a_step2.reshape(-1)
print(a_step2_reshape)
# [0 2 4 6]

print(np.shares_memory(a_step2, a_step2_reshape))
# True

Related Categories

Related Articles