Engineering numpy python

Numpy入門:np.ndarrayを結合する方法を解説 - concatenate, stackなど-

numpyで機械学習や数値計算のコードを書いていると、2つの配列を結合したくなる時があります。方法は様々なのですが、基本的にはnp.concatenatenp.stackを使えば、やりたいことを実現できることが多いです。今日はこの2つの結合方法をメインに、視覚的に理解しやすいよう図も交えながら、仕様を解説したいと思います。

np.concatenateとnp.stackの違いは?

np.concatenatenp.stackのどちらも、np.ndarrayを結合する関数になりますが、np.concatenateは基本的にそのまま結合するイメージで、np.stackは次元を追加して結合する関数になります。実際に図示してみると以下のようになります。np.concatenateは軸を増やさずに結合しているのに対して、np.stackは軸を拡張して結合しているのがわかると思います。
np.concatenateではaxis=1がないとしてエラーになる場合でも、np.stackでは列方向に結合していることがわかると思います。

np.concatenate

では実際のコード上ではどうなるのか見てみましょう。

np.concatenateで結合を行うと、次元をそのままにnp.ndarrayの結合を行うことができます。

# shape (3, )
>>> a = np.array([1,2,3])

# shape (6, )
>>> np.concatenate([a, a])
array([1, 2, 3, 1, 2, 3])

# shape (9, )
>>> np.concatenate([a, a, a])
array([1, 2, 3, 1, 2, 3, 1, 2, 3])

axisを使って次元を指定することで、結合の軸を指定することができます。

# shape (2, 3)
>>> a = np.array([[1,2,3], [4,5,6]])

# axis=0, shape (4, 3)
>>> np.concatenate([a, a])
array([[1, 2, 3],
       [4, 5, 6],
       [1, 2, 3],
       [4, 5, 6]])

# axis=1, shape (2, 6)
>>> np.concatenate([a, a], axis=1)
array([[1, 2, 3, 1, 2, 3],
       [4, 5, 6, 4, 5, 6]])

次元が合わない場合はエラーが出ます。DataFrameのようにマージする際に補完されることはないです。

# shape (2, 3)
>>> a = np.array([[1,2,3], [4,5,6]])

# shape (1, 3)
>>> b = np.array([[7,8,9]])

# shape (3, 3)
>>> np.concatenate([a, b])
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

# dimension mismatch -> error
>>> np.concatenate([a, b], axis=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<__array_function__ internals>", line 200, in concatenate
ValueError: all the input array dimensions except for the concatenation axis must match exactly, but along dimension 0, the array at index 0 has size 2 and the array at index 1 has size 1

np.stack

np.stackで結合すると、次元を1つ増やしてnp.ndarrayを結合します。何も軸を指定しない場合は、先頭に軸を追加し配列を結合しますが、axis=1などを指定すると、以下の例の場合後ろに軸を追加して、列方向に配列を結合します。ここらへんの振る舞いがnp.concatenateと大きく異なる部分かと思います。ただし、元のデータが0次元なのに対して、1次元を飛ばして2次元を指定するとさすがにエラーになります。

# (3, )
>>> a = np.array([1,2,3])

# (2, 3)
>>> np.stack([a, a])
array([[1, 2, 3],
       [1, 2, 3]])

# (3, 2)
>>> np.stack([a, a], axis=1)
array([[1, 1],
       [2, 2],
       [3, 3]])

>>> np.stack([a, a], axis=2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<__array_function__ internals>", line 200, in stack
  File "/usr/local/lib/python3.8/dist-packages/numpy/core/shape_base.py", line 467, in stack
    axis = normalize_axis_index(axis, result_ndim)
numpy.AxisError: axis 2 is out of bounds for array of dimension 2

np.vstack, np.hstackもある

np.stackは少し癖があるように思いますが、np.vstacknp.hstackのような派生版もあります。こっちはものすごく直感的で、np.hstackは横方向に結合し、np.vstackは縦方向に結合することができます。コードを書く際はこちらの方がやりたいことが明示的なので、可読性は高いかもしれません。

# shape (3, )
>>> a = np.array([1,2,3])

# shape (6, )
>>> np.hstack([a, a])
array([1, 2, 3, 1, 2, 3])

# shape (2, 3)
>>> np.vstack([a, a])
array([[1, 2, 3],
       [1, 2, 3]])

まとめ

今回はnumpyのnp.ndarrayの結合方法としてnp,concatenatenp.stackをご紹介しました。仕様がやや異なっていますので、しっかり理解したうえで使っていければと思います!

-Engineering, numpy, python
-, ,