【NumPy】配列の形状変更

【NumPy】配列の形状変更

配列の形状変更

ndarray.reshape()

 ndarray.reshape() を使うと配列の形状を変更できます。

ndarray.reshape(shape, order='C')

 shape には新しい配列の行数 m と列数 n をタプルやリスト、整数で渡します。

 12要素の1次元配列を作成してから、reshape() メソッドで 3×4 の 2 次元配列に形状変更してみます。

# NDARRAY_RESHAPE

# In[1]

import numpy as np

# 12要素の1次元配列を作成
# [1 1 1 1 1 1 1 1 1 1 1 1]
arr = np.ones(12, dtype=np.int32)

# arrを3×4に形状変更
arr_re = arr.reshape((3, 4))

print(arr_re)
[[1 1 1 1]
 [1 1 1 1]
 [1 1 1 1]]

 ndarray.reshape() はほとんどの場合、ビュー を返します。
 実際、arr が変更されていないことを確認しておきましょう。

# In[2]

print(arr)
[1 1 1 1 1 1 1 1 1 1 1 1]

 ndarray.reshape() がビューではなく コピー を返す時もありますが、レアケースなので詳細は割愛します。

 引数には並び替え可能な数値を渡す必要があります。すなわち要素数は m で割り切れて、かつ変更後の配列のインデックスはすべて埋められなければなりません。たとえば、要素数 11 の 1 次元配列を 3×4 の配列に変更しようとしても ValueEroor が発生します。

# In[3]

# 11要素の1次元配列を生成して3×4に形状変更を試みる
arr = np.ones(11, dtype=np.int32).reshape((3, 4))

print(arr)
ValueError: cannot reshape array of size 11 into shape (3,4)

 たとえば、1 次元配列を 2 次元配列に形状変更するとき、行数だけを指定して列数の指定を省略することもできます。その場合、省略したい引数に -1 を渡します。

# In[4]

# 要素数16の配列を2行の配列に形状変更
arr = np.arange(16, dtype=np.int32).reshape((2, -1))

print(arr)
[[ 0  1  2  3  4  5  6  7]
 [ 8  9 10 11 12 13 14 15]]

 In[4] では、要素数 16 の配列を 2 行の 2 次元配列に変更していますが、reshape() の第 2 引数に -1 を指定することで、列数を 8 に自動調整しています。

 多次元配列に対して reshape(-1) を実行すると、配列をフラットに (1 次元配列に形状変更) します。

# In[5]

# 配列をフラットにする
arr = arr.reshape(-1)

print(arr)
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15]

 この手法は機械学習などで多用します。
 

ndarray.resize()

 ndarray.resize() は配列の形状を変更します。

ndarray.resize(new_shape, refcheck=True)

 new_shape には変更後の形状を整数やタプルで渡します。

# NDARRAY_RESIZE

# In[1]

import numpy as np

arr = np.array([[1, 2, 3, 4],
                [5, 6, 7, 8]])

# arrの形状を4×2に変更
arr.resize((4, 2))

print(arr)
[[1 2]
 [3 4]
 [5 6]
 [7 8]]

 refcheck は参照カウントをチェックする引数で、デフォルトでは True に設定されています。デフォルトで要素が増減するような形状変更を試みるとエラーとなります。

# In[2]

# arrの形状を2×2に変更
arr.resize((2, 2))

print(arr)
ValueError: cannot resize an array that references or is referenced by another array in this way.
Use the np.resize function or refcheck=False

 エラーメッセージにあるように、refcheck=False とすると配列の形状を自由に変えられます。たとえば、新しい配列がもとの配列より小さければ、余った要素は捨てられます。

# In[3]

# arrの形状を2×2に変更
arr.resize((2, 2), refcheck=False)

print(arr)
[[1 2]
 [3 4]]

 変更された配列がもとの配列より大きければ、必要なだけ 0 で埋められます。

# In[4]

# arrの形状を2×3に変更
arr.resize((2, 3), refcheck=False)

print(arr)
[[1 2 3]
 [4 0 0]]

 

numpy.reshape()

 numpy.reshape() は配列の形状を変更します。

numpy.reshape(arr, newshape, order='C')

 arr には配列を、newshape には新しい配列の形状を整数、タプル、リストなどで渡します。

# NUMPY_RESHAPE

# In[1]

import numpy as np

# 2×3の配列を定義
arr = np.array([[1, 2, 3],
                [4, 5, 6]])

# arrの形状を3×2に変更
arr_re = np.reshape(arr, (3, 2))

print(arr_re)
[[1 2]
 [3 4]
 [5 6]]

 numpy.reshape() はコピーを返すので、もとの配列 arr は変更されていません。

# In[2]

print(arr)
[[1 2 3]
 [4 5 6]]

 もとの配列と新しい配列の要素数が一致していなければエラーを返します。

# In[3]

# 2×3配列は3×3配列に変更できない
arr_re = np.reshape(arr, (3, 3))
ValueError: cannot reshape array of size 6 into shape (3,3)

 形状を指定する数値に -1 を渡すと形状が自動調整されます。たとえば、numpy.reshape(arr, (3, -1)) は arr を 3 行の行列に形状変更し、列数は arr の要素数を 3 で割った値となります。

# In[4]

# arrを3行の配列に形状変更する
arr_re = np.reshape(arr, (3, -1))

print(arr_re)
[[1 2]
 [3 4]
 [5 6]]

 多次元配列 arr に対して np.reshape(arr, -1) を実行すると、arr をフラットにします。

# In[5]

# arrをフラットにする
arr_re = np.reshape(arr, -1)

print(arr_re)
[1 2 3 4 5 6]

 

numpy.resize()

 numpy.resize() は配列の形状を変更します。

numpy.resize(arr, new_shape)

 新しい配列がもとの配列 arr より大きければ、必要なだけ arr の要素を繰り返して埋めます。

# NUMPY_RESIZE

# In[1]

import numpy as np

# 2×2の配列を定義
arr = np.array([[1, 2],
                [3, 4]])

# arrの形状を3×3に変更
arr_re = np.resize(arr, (3, 3))

print(arr_re)
[[1 2 3]
 [4 1 2]
 [3 4 1]]

 numpy.resize() はコピーを返すので、渡した配列は変更されません。

# In[2]

print(arr)
[[1 2]
 [3 4]]

 新しい配列がもとの配列よりも小さければ、余った要素は捨てられます。

# In[3]

# arrの形状を2×3に変更
arr_re = np.resize(arr_re, (2, 3))

print(arr_re)
[[1 2 3]
 [4 1 2]]

 

numpy.newaxisキーワード

 numpy.newaxis キーワードを使って新しい次元を作成して要素をスライシングすることで、配列の形状を変更することもできます。以下のサンプルコードでは、1 次元配列 [1 2 3] に新しい次元を追加して行ベクトルと列ベクトルとよばれる 2 次元配列を生成します。

# NUMPY_NEWAXIS

# In[1]

import numpy as np

# 1次元配列を定義
x = np.array([1, 2, 3])

# 行ベクトルを作成
y = x[np.newaxis, :]

# 列ベクトルを作成
z = x[:, np.newaxis]

print("行ベクトル\n{}\n".format(y))
print("列ベクトル\n{}".format(z))
行ベクトル
[[1 2 3]]
 
列ベクトル
[[1]
 [2]
 [3]]

 numpy.newaxis は特別なキーワードではなく、None への参照です。すなわち、x[np.newaxis, :] は x[None, :] と書き換えても機能します(つまり要素をもたない次元を追加しています)。