【NumPy入門 np.reshape】配列の形を変える方法 flattenの代用にも!

行列計算では、配列のshape(形)が非常に重要になります。numpy.array(配列)のshapeを変える方法はいろいろありますが、np.reshapeが最も柔軟で簡単な関数です。

この記事では、そんなnp.reshapeの使い方を解説します。

np.reshapeの引数と返り値

np.reshapeの主な引数と返り値の解説です。

参考:SciPy.org

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

データ(配列の要素)は変更せずに、配列を新しい形状にします。

Parameters:
a : array_like

形を変えたい配列

newshape : int or tuple of ints

配列の新しい形状、int型かtuple型で指定します。

order : {‘C’, ‘F’, ‘A’}, optional
Returns:
reshaped_array : ndarray

可能であれば新しいview object、無理ならば配列のコピー。

使い方

ここから先のサンプルコードは、全てJupyterの上で試しています。

In以下のコードはJupyterのセルに書くコードで、Out以下は直前のInに書かれたコードの出力結果です。

まずはnumpyをimportします。

In [1]:

import numpy as np

そして配列の情報を確認するための関数を用意します。

In [2]:
def array_info(x):
    print("配列のshape", x.shape)
    print("配列の要素のデータ型", x.dtype)
    print("配列の中身n",x)

ではまず、reshape対象の配列を用意しましょう。

In [3]:
x = np.arange(0,12) 
array_info(x)

Out:

配列のshape (12,)
配列の要素のデータ型 int64
配列の中身
 [ 0  1  2  3  4  5  6  7  8  9 10 11]

基本的な使い方

np.reshapeの第二引数として使えるshape(配列の形)は、新しいshapeの積が元のshapeの積と同じ値になるように指定します。

例えば、ここで、xを別の形に変えようと思った時、

前の配列のshapeの積 = 新しい配列のshapeの積
(12,) = (3, 4)
12 = 3 × 4

となっていればOKです。

In [4]:

x2 = np.reshape(x, (3,4))
array_info(x2)

Out:
配列のshape (3, 4)
配列の要素のデータ型 int64
配列の中身
 [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

In [5]:

x3 = np.reshape(x2, (2,2,3))
array_info(x3)

Out:
配列のshape (2, 2, 3)
配列の要素のデータ型 int64
配列の中身
 [[[ 0  1  2]
  [ 3  4  5]]

 [[ 6  7  8]
  [ 9 10 11]]]

flatten関数のように、多次元配列を一次元配列に展開することもできます。

In [6]:
size = np.prod(x3.shape)
x4 = np.reshape(x3, size)

print(x3.shape, "->", size)
array_info(x4)

Out:

(2, 2, 3) -> 12
配列のshape (12,)
配列の要素のデータ型 int64
配列の中身
 [ 0  1  2  3  4  5  6  7  8  9 10 11]

flatten, ravelとの速度比較

flattenやravelという関数は、多次元配列を一次元配列に展開する機能を持ちます。

これらとreshapeとの速度比較をしてみましょうjupyterではcellの先頭に%%timeitをつけることで計算時間を計測できます。

In [7]:
%%timeit

size = np.prod(x3.shape)
x4 = np.reshape(x3, size)
[計算時間]
5.67 µs ± 46.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [8]:
%%timeit

x4 = np.reshape(x3, size)
[計算時間]
1.11 µs ± 15.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [9]:
%%timeit

x4 = x3.flatten()
[計算時間]
555 ns ± 11.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [10]:
%%timeit

x4 = x3.ravel()
[計算時間]
165 ns ± 2.21 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

残念ながらreshapeが一番遅く、次にflatten、一番早いのがravelになります。

ravelは元の配列への参照を返しているので、形を変えた方の配列の要素を変更すると、元の配列の方も変更されてしまうので注意が必要です。

reshape(-1)で配列のshapeを自動設定

np.reshapeのshapeの計算、楽をすることもできます。

例えば、(12,)を(2, 6)にしたい時。変更後の配列の形、片方を設定して上げれば残りは-1と書くだけで勝手にshapeを最適なものにしてくれます。実際に見てみましょう。

In [11]:

x5 = np.reshape(x3, (2,-1))
array_info(x5)

Out:

配列のshape (2, 6)
配列の要素のデータ型 int64
配列の中身
 [[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]]

まとめ

この記事では、numpy.arrayのshapeを変える(配列の形を変える)関数、np.reshapeについて紹介しました。ニューラルネットワークなどの計算では、配列の形が揃っていないと計算ができないといったことがあります。

そんなときにnp.reshapeは非常に有用な関数です。この記事でnp.reshapeの使い方を覚えて、是非科学計算や機械学習の実装に役立ててください!

今回の記事は下記の記事を参考にしています。
参考記事:

第一言語はPythonです。
皆さんRustやりましょう。

あなたの目的に合わせた
SAMURAI ENGINEERの運営サービス

SAMURAI ENGINEER Pro

未経験でも挫折しないプログラミングスクール

詳細はこちら

SAMURAI ENGINEER Plus

日本最大級のサブスク型オンラインITスクール

詳細はこちら

SAMURAI ENGINEER Freelance

「一人で稼げる」スキルを身につける

詳細はこちら