【NumPy】ndarrayを分割するsplit、array_split、hsplit、vsplit、dsplit[Python]

  • URLをコピーしました!

NumPy

前回、Pandasのgroupbyでキーによるグルーピングをして統計値を算出する方法を紹介しました。

今回はNumPyでndarrayを分割するsplit、array_split、hsplit、vsplit、dsplitを紹介します。

それでは始めていきましょう。

np.split

まずはndarrayを等分に、もしくは分割するインデックスを指定して分割するnp.splitです。

「np.split(ndarray, 数値)」とすることでndarrayを指定した値に等分割することができます。

import numpy as np

data = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

print(np.split(data, 2))

実行結果
[array([0, 1, 2, 3, 4]), array([5, 6, 7, 8, 9])]

この際、引数として与えるndarrayはリストではダメでエラーとなります。

import numpy as np

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

print(np.split(data, 2))

実行結果
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/numpy/lib/shape_base.py:859, in split(ary, indices_or_sections, axis)
    858 try:
--> 859     len(indices_or_sections)
    860 except TypeError:

(中略)

AttributeError: 'list' object has no attribute 'shape'

また指定する数値はndarrayを余りなく等分割できる値でないとエラーとなります。

import numpy as np

data = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

print(np.split(data, 3))

実行結果
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[15], line 5
      1 import numpy as np
      3 data = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
----> 5 print(np.split(data, 3))

File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/numpy/lib/shape_base.py:864, in split(ary, indices_or_sections, axis)
    862     N = ary.shape[axis]
    863     if N % sections:
--> 864         raise ValueError(
    865             'array split does not result in an equal division') from None
    866 return array_split(ary, indices_or_sections, axis)

ValueError: array split does not result in an equal division

数値をリストで与えるとそのインデックス位置で分割されます。

import numpy as np

data = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8])

print(np.split(data, [2, 6]))

実行結果
[array([0, 1]), array([2, 3, 4, 5]), array([6, 7, 8])]

二次元ndarrayの場合、オプション引数として「axis=軸方向」を与えると任意の軸方向で分割することができます(デフォルトは0)。

import numpy as np

data = np.array([[0, 1, 2, 3, 4, 5, 6, 7], [8, 7, 6, 5, 4, 3, 2, 1]])

print(np.split(data, 2, axis=0))

実行結果
[array([[0, 1, 2, 3, 4, 5, 6, 7]]), array([[8, 7, 6, 5, 4, 3, 2, 1]])]
import numpy as np

data = np.array([[0, 1, 2, 3, 4, 5, 6, 7], [8, 7, 6, 5, 4, 3, 2, 1]])

print(np.split(data, 2, axis=1))

実行結果
[array([[0, 1, 2, 3],
       [8, 7, 6, 5]]), array([[4, 5, 6, 7],
       [4, 3, 2, 1]])]

np.array_split

np.splitでは指定した数値で等分割できない場合はエラーとなりました。

それでもなるべく分割して欲しいという場合、「np.array_split」を使うと、エラーとならずみ分割できます。

使い方は「np.array_split(ndarray, 数値)」です。

import numpy as np

data = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

print(np.array_split(data, 3))

実行結果
[array([0, 1, 2, 3]), array([4, 5, 6]), array([7, 8, 9])]

余りが出る場合、前方のndarrayから一つずつ追加されていきます。

そのため上の例では最初のndarrayが後の二つのndarrayよりも要素が一つ多くなっています。

import numpy as np

data = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

print(np.array_split(data, 7))

実行結果
[array([0, 1]), array([2, 3]), array([4, 5]), array([6]), 
array([7]), array([8]), array([9])]

こちらの例では7分割しようとすると3余るため、前方のndarrayから3つのndarrayで要素数が一つ多くなっています。

np.hsplit、np.vsplit、np.dsplit

np.hsplitは横方向、np.vsplitは縦方向、np.dsplitは深さ方向にndarrayを等分割します。

まずnp.hsplitですが、使い方はこれまでと同じで「np.hsplit(ndarray, 数値)」です。

import numpy as np

data = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

print(np.hsplit(data, 2))

実行結果
[array([0, 1, 2, 3, 4]), array([5, 6, 7, 8, 9])]
import numpy as np

data = np.array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]])

print(np.hsplit(data, 2))

実行結果
[array([[0, 1, 2, 3, 4],
       [9, 8, 7, 6, 5]]), array([[5, 6, 7, 8, 9],
       [4, 3, 2, 1, 0]])]

あくまでも等分割するのでやはり余りが出る場合はエラーとなります。

import numpy as np

data = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8])

print(np.hsplit(data, 2))

実行結果
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[31], line 5
      1 import numpy as np
      3 data = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8])
----> 5 print(np.hsplit(data, 2))

File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/numpy/lib/shape_base.py:940, in hsplit(ary, indices_or_sections)
    938     return split(ary, indices_or_sections, 1)
    939 else:
--> 940     return split(ary, indices_or_sections, 0)

File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/numpy/lib/shape_base.py:864, in split(ary, indices_or_sections, axis)
    862     N = ary.shape[axis]
    863     if N % sections:
--> 864         raise ValueError(
    865             'array split does not result in an equal division') from None
    866 return array_split(ary, indices_or_sections, axis)

ValueError: array split does not result in an equal division

次にnp.vsplitですが、こちらも使い方はこれまでと同じで「np.vsplit(ndarray, 数値)」です。

import numpy as np

data = np.array([[0, 1, 2, 3, 4,], [5, 6, 7, 8, 9], [9, 8, 7, 6, 5], [4, 3, 2, 1, 0]])

print(np.vsplit(data, 2)[0])
print(np.vsplit(data, 2)[1])

実行結果
[[0 1 2 3 4]
 [5 6 7 8 9]]
[[9 8 7 6 5]
 [4 3 2 1 0]]

np.vsplitは2次元目を分割するので最低2次元のndarrayである必要があります。

そのため1次元のndarrayの場合はエラーとなります。

import numpy as np

data = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

print(np.vsplit(data, 2))

実行結果
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[36], line 5
      1 import numpy as np
      3 data = np.array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])
----> 5 print(np.vsplit(data, 2))

File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/numpy/lib/shape_base.py:989, in vsplit(ary, indices_or_sections)
    987 if _nx.ndim(ary) < 2:
    988     raise ValueError('vsplit only works on arrays of 2 or more dimensions')
--> 989 return split(ary, indices_or_sections, 0)

File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/numpy/lib/shape_base.py:864, in split(ary, indices_or_sections, axis)
    862     N = ary.shape[axis]
    863     if N % sections:
--> 864         raise ValueError(
    865             'array split does not result in an equal division') from None
    866 return array_split(ary, indices_or_sections, axis)

ValueError: array split does not result in an equal division

最後にnp.dsplitですが、こちらも使い方はこれまでと同じで「np.dsplit(ndarray, 数値)」です。

import numpy as np

data = np.array([[[1, 2, 3, 4], [5, 6, 7, 8]],
                 [[9, 10, 11, 12], [13, 14, 15, 16]],
                 [[17, 18, 19, 20], [21, 22, 23, 24]]])

print(np.dsplit(data, 2))

実行結果
[array([[[ 1,  2],
        [ 5,  6]],

       [[ 9, 10],
        [13, 14]],

       [[17, 18],
        [21, 22]]]), array([[[ 3,  4],
        [ 7,  8]],

       [[11, 12],
        [15, 16]],

       [[19, 20],
        [23, 24]]])]

np.vsplitは三次元目を分割するので、2次元以下のndarrayの場合はエラーとなります。

import numpy as np

data = np.array([[0, 1, 2, 3, 4,], [5, 6, 7, 8, 9], [9, 8, 7, 6, 5], [4, 3, 2, 1, 0]])

print(np.dsplit(data, 2))

実行結果
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[43], line 5
      1 import numpy as np
      3 data = np.array([[0, 1, 2, 3, 4,], [5, 6, 7, 8, 9], [9, 8, 7, 6, 5], [4, 3, 2, 1, 0]])
----> 5 print(np.dsplit(data, 2))

File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/numpy/lib/shape_base.py:1033, in dsplit(ary, indices_or_sections)
    994 """
    995 Split array into multiple sub-arrays along the 3rd axis (depth).
    996 
   (...)
   1030 array([], shape=(2, 2, 0), dtype=float64)]
   1031 """
   1032 if _nx.ndim(ary) < 3:
-> 1033     raise ValueError('dsplit only works on arrays of 3 or more dimensions')
   1034 return split(ary, indices_or_sections, 2)

ValueError: dsplit only works on arrays of 3 or more dimensions

次回はNumPyで配列の形状を変えるブロードキャスト(np.broadcast_to、np.broadcast_arrays)を紹介します。

ではでは今回はこんな感じで。

よかったらシェアしてね!
  • URLをコピーしました!

コメント

コメントする