note.nkmk.me

NumPy: How to use reshape() and the meaning of -1

Posted: 2019-11-21 / Modified: 2020-09-24 / Tags: Python, NumPy

To convert the shape of a NumPy array ndarray, use the reshape() method of ndarray or the numpy.reshape() function.

This article describes the following contents.

  • How to use ndarray.reshape() method
  • How to use numpy.reshape() function
  • Conversion order: order
  • The meaning of -1 in reshape()
  • reshape() returns the view

If you want to check the shape or the number of dimensions of ndarray, see the following article.

You can use reshape() to convert to any shape, but there may be alternatives available for convenience in certain shape conversions.

In addition, in the operation between NumPy arrays (ndarray), each shape is automatically converted to be the same by broadcasting.

Sponsored Link

How to use ndarray.reshape() method

Take the following one-dimensional NumPy array ndarray as an example.

import numpy as np

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 shape as a list or tuple in the first argument of the reshape() method of numpy.ndarray.

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

If the shape does not match the number of elements in the original array, ValueError occurs.

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

You can specify each dimension value in turn, not a list or tuple.

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 numpy.reshape() function

In the numpy.reshape() function, specify the original numpy.ndarray as the first argument and the shape to the second argument as a list or tuple. If the shape does not match the number of elements in the original array, ValueError occurs.

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)

The second argument of the numpy.reshape() function must be a list or tuple. If you specify the value of each dimension in turn like the reshape() method of numpy.ndarray, ValueError occurs.

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(np.reshape(a, 4, 6))
# ValueError: cannot reshape array of size 24 into shape (4,)

Conversion order: order

The conversion order can be specified with the argument order. order='C'(default) means C-like index order, order='F' means Fortran-like index order.

The results are different as follows.

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]]]

Same for numpy.reshape() function:

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]]

The reshape() method of numpy.ndarray allows you to specify the shape of each dimension in turn as described above, so if you specify the argument order, you must use the keyword.

In the numpy.reshape() function, the third argument is always order, so the keyword can be omitted.

# 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]]
Sponsored Link

The meaning of -1 in reshape()

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

Take the reshape() method of numpy.ndarray as an example, but the same is true for the numpy.reshape() function.

The length of the dimension set to -1 is automatically determined by inferring from the specified values of other dimensions. This is useful when converting a large array shape.

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]]]

You can use -1 for only one dimension. If used for more than one dimension, ValueError occurs.

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

Also, if there is no value that satisfies the condition, ValueError occurs.

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

reshape() returns the view

Note that both reshape() method of numpy.ndarray and numpy.reshape() function return a view instead of a copy whenever possible. Since it is "as much as possible", a copy may be returned instead of a view depending on the memory layout.

See the following article for views and copies in NumPy.

The following example uses the reshape() method of numpy.ndarray, but the same applies to numpy.reshape() function.

reshape() returns a view and shares memory with the original numpy.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 changes the view object returned by reshape() as follows:

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 object returned by reshape() changes 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]

If you want to get a copy, use the copy() method. 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]

The following is an example where reshape() returns a copy instead of a view:

If the stride in memory is not constant as a result of transforming a step-specified slice, a copy is returned.

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

a_step = a[:, ::2]
print(a_step)
# [[0 2]
#  [3 5]]

print(a_step.reshape(-1))
# [0 2 3 5]

print(np.shares_memory(a_step, a_step.reshape(-1)))
# False

For a step-specified slice, if stride is constant, a view is returned.

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

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

print(a_step.reshape(-1))
# [0 2 4 6]

print(np.shares_memory(a_step, a_step.reshape(-1)))
# True
Sponsored Link
Share

Related Categories

Related Articles