NumPyのconcatenate(), vstack(), hstack(), dstack(), stack()の違い


このエントリーをはてなブックマークに追加

NumPyのconcatenate(), vstack(), hstack(), dstack(), stack()の違い について毎回混乱するのでまとめました。

concatenate()

複数のアレイを、既存の軸に沿って結合する関数です。

基本的に、後述するvstack(), hstack(), dstack()の上位互換がconcatenate()だと思っておけば良さそう。

2つの同shapeなアレイを結合する例を示します。axisの指定によりどの軸に沿って結合するかを指定します。

a = np.random.random((5, 6, 7, 8))
b = np.random.random((5, 6, 7, 8))

c = np.concatenate([a, b], axis=0)  # shape: (10, 6, 7, 8)
c = np.concatenate([a, b], axis=1)  # shape: (5, 12, 7, 8)
c = np.concatenate([a, b], axis=2)  # shape: (5, 6, 14, 8)
c = np.concatenate([a, b], axis=3)  # shape: (5, 6, 7, 16)

# 軸を省略したときはaxis=0を指定したのと同じ
c = np.concatenate([a, b])  # shape: (10, 6, 7, 8)

axisで指定した軸に関しては長さがずれていても結合できます。

a = np.random.random((5, 6, 7, 8))
b = np.random.random((5, 6, 70, 8))

c = np.concatenate([a, b], axis=2)  # shape: (5, 6, 77, 8)

vstack(), hstack(), dstack()

基本的に以下のように思っておけばよいです。

  • vstack(): concatenate(axis=0)と同じ
  • hstack(): concatenate(axis=1)と同じ
  • dstack(): concatenate(axis=2)と同じ

hstack()の例だけ以下に示します。

a = np.random.random((5, 6, 7, 8))
b = np.random.random((5, 6, 7, 8))

c = np.hstack([a, b])  # (5, 12, 7, 8)

しかし、以下に示すように、細部が微妙に異なります。個人的には、これらを覚えるのはかなり困難なので、 事前に結合対象となるアレイのdimを合わせたあとにconcatenate()(または場合に応じてvstack(), hstack(), dstack())を使うほうが 読みやすいコードになるのではないかと思います。

vstack()

vstack()に渡された1-Dアレイ(e.g. (N,))は、結合前に2-Dアレイ(e.g. (1, N,))に拡張されます。よって1-Dアレイと2-Dアレイの結合が可能です。

a = np.random.random((7, ))  # (1, 7)に拡張される
b = np.random.random((100, 7))

c = np.vstack([a, b])  # shape: (101, 7)

hstack()

hstack()に1-Dアレイと1-Dアレイが渡された場合は、例外的に、連結された1-Dアレイが返ります。

a = np.random.random((5,))
b = np.random.random((5,))

c = np.hstack([a, b])  # shape: (10,)

1-Dアレイと2-Dアレイが渡された場合はエラーになります。

dstack()

dstack()に渡された1-Dアレイ(e.g. (N,))は、結合前に3-Dアレイ(e.g. (1,N,1))に拡張されます。

dstack()に渡された2-Dアレイ(e.g. (M,N))は、結合前に3-Dアレイ(e.g. (M,N,1))に拡張されます。

よって1-Dアレイ、2-Dアレイ、3-Dアレイの結合が可能となることがあります。

a = np.random.random((5,))  # (1, 5, 1)に拡張される
b = np.random.random((1,5))  # (1, 5, 1)に拡張される
c = np.random.random((1,5,100)) 

d = np.dstack([a, b, c])  # shape: (1, 5, 1+1+100)

stack()

stack()はこれまで紹介したコードと異なり、新規に軸を生成します。

a = np.random.random((5, 6, 7))
b = np.random.random((5, 6, 7))

c = np.stack([a, b], axis=0)  # shape: (2, 5, 6, 7)
c = np.stack([a, b], axis=1)  # shape: (5, 2, 6, 7)
c = np.stack([a, b], axis=2)  # shape: (5, 6, 2, 7)

# axis=0を指定したのと同じ
c = np.stack([a, b])  # shape: (2, 5, 6, 7)

参考URL