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つ紹介しました。
コメント