NumPy配列にはshapeというプロパティがあり、これは各次元の要素数を表したものです。例えば、2次元配列なら(行数、列数)で表すことができます。

NumPyのndarrayのインスタンス変数shapeの意味 /features/numpy-shape.html

今回は、NumPyの配列のshapeの形状変換をする関数np.reshapeと、似たような機能を持つnp.resizeについて解説します。

形状変換は、あらゆる場面でよく目にする使用頻度の高い機能です。この記事を通して使い方を学ぶと参考になるはずです。

np.reshape

まずは、一般的にもよく使用されるnp.reshapeから解説します。APIドキュメントは以下のようになっています。

numpy.reshape(a, newshape, order=’C’)

params:

パラメータ名 概要
a ndarray 変換元の配列
newshape intもしくは
intのタプル
orリスト
変換後の配列の形状を指定します。intの場合、指定した要素数分の1次元配列になります。タプルの場合は、変換後のshapeを指定します。
order ‘C’,’F’,’A’の
いずれか
(省略可能)初期値’C’
指定したモードでインデックスを読み込み、shapeを再整形します。

returns:

形状変換後のndarrayが返されます。

reshapeの引数には、第一引数に変換元になるndarray、第二引数に変換後のarrayの形状(shape)を指定します。最後の3つ目の引数はFortranのような順序の指定をする場合に使われるものであまり使用されません。

ポイントとしては、配列のshapeを指定する際に (n, -1) のように-1を指定すると要素数に合わせてn × mの2次元配列となります。このmはもとの配列の要素数に応じて変化する値で、変形後の要素数と変形前の要素数が変化しないような値になります。

以下のコードで使い方を確認してみます。

In [1]: import numpy as np

In [2]: a = np.arange(12) # 1つ1次元配列を生成。

In [3]: a
Out[3]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

In [4]: b = np.reshape(a, (3, 4)) # 3×4の2次元配列に変形。

In [5]: b  # しっかり変形ができているか確認。
Out[5]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

元々12個の要素を持つndarrayを第一引数として、第二引数のnewshapeに(3, 4)を指定すると、3 × 4の多次元配列に変換されました。

reshape前のndarrayの要素は、reshape後のndarrayと共有されているので、変換後のある値を変化すると変換前の値も変更になります。

In [6]: b[0,1] = 0  # 1つだけ要素を変更する。

In [7]: b
Out[7]:
array([[ 0,  0,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

In [8]: a    # aにも変更が反映されている。
Out[8]: array([ 0,  0,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

続いて第三引数のorderの使い方を見ていきます。

In [9]: c = np.arange(12) # もう一度同じ配列を生成。

In [10]: d = np.reshape(c, (3,4), order = 'C') # orderを設定することで、並べ替え方を設定できる。

In [11]: d  # 'C'はデフォルトで設定されているので、特に変化はない。
Out[11]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

In [12]: d = np.reshape(c, (3,4), order = 'F') # ここを'F'にすると高い次元のindexがまず変化していくように変形される。

In [13]: d
Out[13]:
array([[ 0,  3,  6,  9],
       [ 1,  4,  7, 10],
       [ 2,  5,  8, 11]])

変換前の要素数と、変換後の要素数が一致しない場合はValueErrorの例外が発生します。また、-1を使用すると、元の要素数に合わせて自動で適切な値が設定されます。

In [14]: np.reshape(c, (3,5)) # 変形後の配列の`shape`が要素数に合わないとエラーが返ってくる。
---------------------------------------------------------------------------
      (エラーメッセージがここに表示される)

       ValueError: cannot reshape array of size 12 into shape (3,5)  

In [15]: a = np.arange(12) # もう一度配列を生成。

In [16]: np.reshape(a, (3,-1))   # (n, -1)と`shape`を指定するとn×m (mは配列の要素数に合わせた値)の配列を返す。
Out[16]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])



In [17]: np.reshape(a, (-1, 6)) # 違う値でもやってみる。
Out[17]:
array([[ 0,  1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10, 11]])

ndarray.reshape

ndarrayは、np.reshapeと同様の機能のメソッドを持っています。

以下のコードで確認してみます。

In [1]: import numpy as np

In [2]: a = np.arange(12).reshape((3, 4))

In [3]: a
Out[3]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

In [4]: b = np.arange(12).reshape((3,-1))  # -1も使える。

In [5]: b
Out[5]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

In [6]: c = np.arange(15).reshape((3,4)) # 要素数と出力する配列が異なると、エラーが返る。
---------------------------------------------------------------------------
エラーメッセージがここに表示される

ValueError: cannot reshape array of size 15 into shape (3,4)

resize

続いて、reshapeと同様の機能を持つreshapeを紹介します。APIドキュメントは以下の通りです。

numpy.resize(a, new_shape)

params:

パラメータ名 概要
a ndarray 変換元のndarray
new_shape intもしくは
intのタプルorリスト
変換後の配列のshapeを指定します。intの場合、指定した要素数分の1次元配列になります。タプルの場合は、変換後のshapeを指定します。

returns:

形状変換後のndarrayが返されます。

ほとんどreshapeと相違点はありませんが、こちらは引数にorderがありません。

また、変形後の配列が元の配列の要素数に合致しない時の挙動が異なります。 reshapeは元の配列の要素数と合致しないとエラーを返しますが、resizeはそのような処理でもエラーを返さずに強制的に実行します。

どのような結果になるのかを確かめるために、以下のコードで確認してみましょう。

In [1]: import numpy as np

In [2]: a = np.arange(12)

In [3]: np.reshape(a, (3,4)) # まずは3×3の2次元配列を生成する。
Out[3]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

In [4]: np.resize(a, (3,5)) # 配列のサイズが要素数より大きいと繰り返される。
Out[4]:
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11,  0,  1,  2]])

In [5]: np.resize(a, (3,2)) # 逆に配列のサイズが小さいと、元のデータが使用されない。
Out[5]:
array([[0, 1],
       [2, 3],
       [4, 5]])

さらに、reshapeの時には、変換後と変換前の要素は共有されていましたが、resizeは共有されません。処理を実行したあとの配列に値の変更を施しても変換前の配列の要素には変更が反映されません。

In [6]: b = np.resize(a, (3,4))

In [7]: b[0, 1] = 0  # 配列の要素を変更してみる。

In [8]: b
Out[8]:
array([[ 0,  0,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

In [9]: a  # オリジナルの配列を確かめると、変更が反映されていない。
Out[9]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

ndarray.resize

resizendarrayのメソッドとして使用されることが多いので、メソッドとしての使い方を紹介します。APIドキュメントは以下の通りです。

ndarray.resize(new_shape, refcheck=True)

params:

パラメータ名 概要
new_shape int/intのタプルorリスト int、intのタプルorリスト - 変換後のarrayの形状を指定します。intの場合、指定した要素数分の1次元配列になります。タプルの場合は、変換後のshapeを指定します。
refcheck bool値 (省略可能)初期値True
Falseなら、参照カウントはチェックされません。

returns:

形状変換後のndarrayが返されます。

numpy.resizeの場合は、変換前と変換後の要素数が違っても強制的に形状変換を試みましたが、こちらはresizeと同様にValueError例外を発生させます。

In [1]: import numpy as np

In [2]: a = np.arange(12) # 元となる配列を1つ生成。

In [3]: a.resize((3,4))   # 変形。

In [4]: a
Out[4]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])


In [5]: a.resize((3,5)) #先程までのresizeとは異なり、 要素数と出力される配列の形と合致しないと、エラーが返ってくる。
---------------------------------------------------------------------------
エラーメッセージ

ValueError: cannot resize an array that references or is referenced
by another array in this way.  Use the resize function

また、こちらはrefcheckオプションが引数に追加されています。refcheckFalseを指定すると、先程まで扱っていたresizeと同様に、組み替える前の配列の要素数に関係なく、新しいshapeの配列を出力します。

In [6]]: a.resize((3,5), refcheck = False)  # 引数であるrefcheckをFalseにしておくと、配列の形に要素を合わせてくれる。ただし、入る値は0。

In [7]: a
Out[7]:
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11,  0,  0,  0]])
In [8]: b = np.arange(12) # また1つ新たに配列を生成。
In [9]: c = b    # cにbを代入。

In [10]: c.resize((3,4)) # cだけ形を変える。

In [11]: c
Out[11]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

In [12]: b # bにもcの変更が反映されている。
Out[12]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

reshaperesizeの違いまとめ

最後に、reshaperesizeとの違いをまとめた表を以下に掲載しておきます。

関数名 元と変更後の配列の要素数が
合致しないときの挙動
引数orderの
有無
要素変更の
反映
reshape エラーを返す。
ndarray.reshape エラーを返す。
resize 変更後の配列のshapeに合わせて出力。
変更後の要素数が超過している場合は
最初からの要素を繰り返していく。
ndarray.resize refcheck = True(default)なら、
エラーを返す。
refcheck = Falseなら変更後の
shapeに合わせて出力。
変更後の要素数が超過している場合は
0が要素として入っていく。