numpyの3次元配列に2次元配列の要素を追加する4つの方法

pythonで、3次元のnumpy配列に、2次元のnumpy配列を要素として追加する方法を紹介します。numpy配列では、リスト(list)と同じようにappendしてもうまくいきません。この記事の方法は2次元、3次元だけではなく、4次元以上の多次元の配列にも適用できます。

この記事でできること

numpy配列(ndarray)に要素を追加するときに、リスト(list)と同じようにappend等を使い、うまくいかないケースに直面したことはないでしょうか。

numpy配列(ndarray)では、pythonのリスト(list)と同じように扱ってもうまくいかない場合があり、よく直面するのがappend周りの処理だと思います。

この記事では、numpy配列(ndarray)に対してリスト(list)と同じようにappendを使ってうまくいかないケースをまず紹介します。次に、numpy配列の場合に必要な処理の解説をします。

紹介する方法は、for文等を使って1つずつ取得した2次元配列を3次元配列に格納していきたくケースを例に説明していきます。2次元や3次元だけでなく、4次元配列やそれ以上の次元の配列にも適用できる方法です。

for文で1つずつ取得したnumpy配列を1つのnumpy配列に追加していく処理は、機械学習やディープラーニングでデータセットのデータを1つずつ読み込む際によく使うことになります。

numpy配列(ndarray)でリスト(list)と同じようにappend

まずは、リスト(list)で1つずつ取得した2次元配列を3次元配列に格納していきたくサンプルコードを説明し、同じようにnumpy配列で行った場合にうまくいかない例を紹介します。

リスト(list)にappendで2次元配列の要素を追加する方法

リスト(list)で、for文を使って一つずつ2次元配列を1つのリスト(list)に要素を追加していく実装例は次のようになります。まずは空のリスト”lists=[]”を定義して、listsに対してappendを使って要素を追加していきます。

lists = []
for i in range(5):
    a = [[i, i+1, i+2],
         [i+3, i +4, i+5]]
    lists.append(a)

print(lists)

このコードを実行した結果のprint文の出力は次のようになります。

[[[0, 1, 2], 
  [3, 4, 5]], 
 [[1, 2, 3], 
  [4, 5, 6]],
 [[2, 3, 4], 
  [5, 6, 7]],
 [[3, 4, 5],
  [6, 7, 8]],
 [[4, 5, 6],
  [7, 8, 9]]]

2次元配列を3次元配列に追加するだけなく、3次元配列でも4次元配列でも、多次元配列で要素を追加するのはこの方法で実装できます。

numpy配列(ndarray)でリスト(list)と同じようにappendした駄目な例

numpy配列で同じようにappendを使って要素を追加する場合の例を示します。


numpy_array = np.empty((0, 2, 3))
for i in range(5):
    a_np = np.array([[i, i+1, i+2],
                     [i+3, i+4, i+5]])
    numpy_array = np.append(numpy_array, a_np)

print(numpy_array)

numpy配列のappendはnp.appendを使います。リスト(list)との違いは、”numpy_array = np.append(numpy_array, a_np)”として変数”numpy_array”への代入文が必要なことです。

また、numpy配列では、空の配列の定義はnp.emptyを使い、0次元目以外の次元数は予め数値を指定します。ここでは、次のように(2,3)の2次元配列を要素として追加するので、”np.empty((0, 2, 3))”と空の配列を定義しています。

numpy_array = np.empty((0, 2, 3))

上のサンプルコードを実行した結果は次のようになります。

[0. 1. 2. 3. 4. 5. 1. 2. 3. 4. 5. 6. 2. 3. 4. 5. 6. 7. 3. 4. 5. 6. 7. 8.
 4. 5. 6. 7. 8. 9.]

3次元配列を得たかったのに1次元配列となってしまいました。

これを避ける方法として、np.appendの引数として”axis”を指定することが解決法として示されていることが多いです。

numpy配列(ndarray)でリスト(list)と同じようにappendした駄目な例(axisをしてもダメな例)

では、np.appenに引数”axis”を指定した場合の例を示します。

今回は3次元配列に2次元配列の要素”a_np”を追加していきたいので、空の3次元配列の軸0に2次元配列を追加していくことを意図して”axis=0″を指定した次のサンプルコードが自然です。

numpy_array = np.empty((0, 2, 3))
for i in range(5):
    a_np = np.array([[i, i+1, i+2],
                     [i+3, i+4, i+5]])
    a_np = np.reshape(a_np, (1, 2, 3)) # reshapeで追加先と同じ次元数にする
    numpy_array = np.append(numpy_array, a_np, axis=0)

しかし、このコードを実行すると次のようなエラーが出力され、プログラムが実行できません。

ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 3 dimension(s) and the array at index 1 has 2 dimension(s)

このように、numpy配列では、リスト(list)と同じように要素をappendで追加しても、うまくいきません。

以降は、numpy配列での要素の追加方法について説明します。

numpyのappendで3次元配列に2次元の要素を追加する

まずは、np.appendによる3次元配列に2次元配列の要素の追加方法を2つ紹介します。

appendを使った2つの方法

1つ目は、要素を追加する前に、追加する要素の次元数を変換する方法です。

    numpy_array = np.empty((0, 2, 3))
    for i in range(5):
        a_np = np.array([[i, i+1, i+2],
                         [i+3, i+4, i+5]])
        a_np = np.reshape(a_np, (1, 2, 3)) # reshapeで追加先と同じ次元数にする
        numpy_array = np.append(numpy_array, a_np, axis=0)
        
    print(numpy_array)

np.appendは、追加対象のnumpy配列”numpy_array”と追加したい要素”a_np”が同じ次元数である必要があり、要素”a_np”を”reshape”を使って便宜上3次元にすればOKです。でも、めんどくさいですよね。

上のコードの出力結果”numpy_array”の中身は次のようになります。意図した通りです。

[[[0. 1. 2.]
  [3. 4. 5.]]

 [[1. 2. 3.]
  [4. 5. 6.]]

 [[2. 3. 4.]
  [5. 6. 7.]]

 [[3. 4. 5.]
  [6. 7. 8.]]

 [[4. 5. 6.]
  [7. 8. 9.]]]

次に、appendを使った2つ目のやり方は次のようになります。上の駄目な例では、np.appendにaxisを指定しないせいで、1次元配列となってしまいました。次の例では、一旦1次元配列になってしまった”numpy_array”をreshapeメソッドを使って3次元化しています。


numpy_array = np.empty((0, 2, 3))
for i in range(5):
    a_np = np.array([[i, i+1, i+2],
                     [i+3, i+4, i+5]])
    numpy_array = np.append(numpy_array, a_np)

 # reshapeで次元を整理する
numpy_array = np.reshape(numpy_array, (-1, 2, 3))
print(numpy_array)

この方法で得られる”numpy_array”をprint文で出力した結果は、上の例で紹介したものと同一となります。

append以外の2つの方法

ここでは、np.append以外のメソッド(関数)を使った方法を紹介します。

一番楽な豊方法はnp.vstackです。次のように使います。

numpy_array = np.empty((0, 2, 3))
for i in range(5):
    a_np = np.array([[i, i+1, i+2],
                     [i+3, i+4, i+5]])
    numpy_array = np.vstack((numpy_array, [a_np]))

np.vstackは、同じ次元数の要素からなるタプル(tuple)を引数として、v(vertical)方向にnumpy配列を結合します。

np.vstack((numpy_array, [a_np]))のように、3次元の”numpy_array”と2次元の”a_np”を3次元化した”[a_np]”の2要素のタプル(tuple)を結合します。

格納したnumpy配列(上の例では”numpy_array”)と、追加したい要素(上の例では”a_np”)に対して要素に括弧”[]”をつけて次元数を増やしてタプル(tuple)として指定するだけです。上の例で紹介した、記述量の多いreshapeメソッドは必要なく、括弧”[]”を記述するだけなので簡単です。

次の例は、考え方が簡単な例です。単純に、pythonリスト(list)で3次元配列に2次元配列要素を追加した後、numpy配列(ndarray)化しています。

lists = []
for i in range(5):
    a_np = np.array([[i, i+1, i+2],
                     [i+3, i+4, i+5]])
    lists.append(a_np)
numpy_array = np.array(lists)

np.vstackを使った上の例よりも、慣れ親しんだ方法で要素の追加ができます。

しかし、追加する要素はリスト(list)型です。追加要素がnumpy配列であると決まっている場合、例えばファイル読み込みするデータがすでにnumpy配列となっている等の場合、この方法を使うことはできません。

おわりに:結局どの方法が良いのか

一番楽な方法はnp.vstack()を使う方法です。ただ、stack関係のメソッドに慣れていない場合は覚えにくいかもしれません。

次のおすすめの方法はreshapeとnp.append(axis=0)を使う方法です。リスト(list)に慣れていると、やや直観的にわかりやすいです。追加したい要素のnumpy配列に対して、次元を1つreshape等で追加し、np.appendをaxis=0で指定して要素を追加します。

リスト(list)とnumpy配列(ndarray)では、append等の要素追加の仕様が少し異なります。本記事では、numpy配列でのやり方を4つ紹介しました。

コメント

タイトルとURLをコピーしました