NumPy:配列の形状を変更する(reshape, flatten, ravel)

NumPy の配列は、要素数を変えずに形状だけを変更できます。reshapeflattenravel の3つの方法を紹介します。

reshape:任意の形状に変形

reshape() は、配列を指定した形状に変形します。要素の総数が一致していれば、どんな形にでも変えられます。

import numpy as np

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

# 3行4列に変形
b = a.reshape(3, 4)
print(b)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

# 2行6列に変形
c = a.reshape(2, 6)
print(c)
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]]

形状のうち1つの次元を -1 にすると、自動的に計算してくれます。

a = np.arange(12)

# 列数だけ指定、行数は自動計算
b = a.reshape(-1, 4)  # 3行4列になる
print(b.shape)  # (3, 4)

# 行数だけ指定、列数は自動計算
c = a.reshape(3, -1)  # 3行4列になる
print(c.shape)  # (3, 4)

要素数が合わないとエラーになります。

a = np.arange(12)
# a.reshape(5, 3)  # ValueError: 12個を5×3=15個にはできない

flatten:1次元配列に変換(コピー)

flatten() は、多次元配列を1次元に平坦化します。元の配列のコピーが返されるため、変更しても元に影響しません。

a = np.array([[1, 2, 3],
              [4, 5, 6]])

b = a.flatten()
print(b)  # [1 2 3 4 5 6]

# bを変更してもaは変わらない
b[0] = 99
print(a[0, 0])  # 1(元のまま)

ravel:1次元配列に変換(ビュー)

ravel() も配列を1次元に平坦化しますが、可能な限りビュー(元データへの参照)を返します。そのため、変更すると元の配列にも影響します。

a = np.array([[1, 2, 3],
              [4, 5, 6]])

b = a.ravel()
print(b)  # [1 2 3 4 5 6]

# bを変更するとaも変わる
b[0] = 99
print(a[0, 0])  # 99(元も変更される)

flatten と ravel の違い

flatten

コピーを返す。安全だがメモリを消費する。元の配列は変更されない

ravel

ビューを返す。高速でメモリ効率が良い。元の配列も変更される可能性がある

読み取り専用で使うなら ravel が効率的です。元の配列を壊したくないなら flatten を選びましょう。

reshape(-1) との関係

reshape(-1) も1次元化に使えます。ravel() と同様にビューを返します。

a = np.array([[1, 2], [3, 4]])

print(a.reshape(-1))  # [1 2 3 4]
print(a.ravel())      # [1 2 3 4]

どちらも同じ結果ですが、「平坦化する」という意図を明確にしたいなら ravel()flatten() を使うほうが読みやすいコードになります。