よちよちpython

独習 python/Qpython/Pydroid3/termux/Linux

【NumPy】numpy配列をn分割するnp.array_split(配列 , 個数)

numpyで配列をn分割するnp.array_split(配列 , 個数)

配列をn個に分割したいとき、np.array_split()を使うと便利です。

【実行環境】

  • Android
  • Termux
  • Python3.9
  • Jupyter Notebook





1次元配列の場合

まずは簡単な例から。1~10まで並んだ配列を2分割してみます。

余りの出ない分割の場合

素数10個の配列を、2や5で分割する場合は共に余りが出ないので、同じ要素数のグループに均等に分割できますよね。

2等分します。

# 元の配列
a = np.arange(1,11)
print(a)

# 2分割
np.array_split(a, 2)
[ 1  2  3  4  5  6  7  8  9 10]





[array([1, 2, 3, 4, 5]), array([ 6,  7,  8,  9, 10])]

素数が5個ずつ、2等分されました。



余りの出る分割の場合

10の3等分だと、個数は
10 ÷ 3 = 3 余り 1
ですので、余りをどこかのグループに入れて、個数を(3, 3, 4)みたいにグループ分けしなくちゃいけませんが、これも自動でやってくれます。

print(a)

# 3分割
np.array_split(a, 3)
[ 1  2  3  4  5  6  7  8  9 10]





[array([1, 2, 3, 4]), array([5, 6, 7]), array([ 8,  9, 10])]

先頭のグループに余りが追加されて要素数が4つに、残り2グループは要素数3つ、全体が3分割されました。

では、要素数が11個の配列を3等分する場合はどうなる?

11 ÷ 3 = 3 余り 2

なので、要素数が(5, 3, 3)にするか、余り2を2グループに1つずつ入れて(4, 4, 3)になれば3等分できる。

では、やっていただきます。numpyさん、お願いします。

a11 = np.arange(1,12)
print(a11)

# 要素数11を3等分
np.array_split(a11, 3)
[ 1  2  3  4  5  6  7  8  9 10 11]





[array([1, 2, 3, 4]), array([5, 6, 7, 8]), array([ 9, 10, 11])]

(4,4,3)の要素数で3分割されました。



素数を超した分割を指定した場合

分割数を、元の配列数を超えて指定するとどうなるか。2個を3等分していただきます。エラーが出るだろうけど

# 要素数を超えた分割指定
np.array_split([1,2], 3)
[array([1]), array([2]), array([], dtype=int64)]

お、エラーは出さず、律儀に空の配列を含んだ3分割がされました。



各分割をそれぞれ変数に代入できるか(できる)

指定分割数だけ変数を用意すると、各変数に代入できるんじゃないか。やってみましょう。

# 変数に代入できるか? 3等分する
x, y, z = np.array_split([5,6,7], 3)

# 変数を出力
print(x, y, z)
[5] [6] [7]

出来ますね。



2次元配列のn分割

元の配列が2次元配列になるとどうだろう?

5行4列の配列を2等分する。

# 見やすいように表示する
from pprint import pprint

# 5行4列の2次元配列生成
ad2 = np.arange(1,21).reshape(5,4)
print(ad2)

# 2等分
np.array_split(ad2, 2)

[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]
 [13 14 15 16]
 [17 18 19 20]]





[array([[ 1,  2,  3,  4],
        [ 5,  6,  7,  8],
        [ 9, 10, 11, 12]]),
 array([[13, 14, 15, 16],
        [17, 18, 19, 20]])]

2次元配列を2等分しました。行で分割されています。

n分割します。

print('元の配列\n', ad2)
print()

# n等分
for i in range(6):
    print(f'【{i+1}等分】')
    pprint(np.array_split(ad2, i+1))
    print('-'*30)
    
元の配列
 [[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]
 [13 14 15 16]
 [17 18 19 20]]

【1等分】
[array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12],
       [13, 14, 15, 16],
       [17, 18, 19, 20]])]
------------------------------
【2等分】
[array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]]),
 array([[13, 14, 15, 16],
       [17, 18, 19, 20]])]
------------------------------
【3等分】
[array([[1, 2, 3, 4],
       [5, 6, 7, 8]]),
 array([[ 9, 10, 11, 12],
       [13, 14, 15, 16]]),
 array([[17, 18, 19, 20]])]
------------------------------
【4等分】
[array([[1, 2, 3, 4],
       [5, 6, 7, 8]]),
 array([[ 9, 10, 11, 12]]),
 array([[13, 14, 15, 16]]),
 array([[17, 18, 19, 20]])]
------------------------------
【5等分】
[array([[1, 2, 3, 4]]),
 array([[5, 6, 7, 8]]),
 array([[ 9, 10, 11, 12]]),
 array([[13, 14, 15, 16]]),
 array([[17, 18, 19, 20]])]
------------------------------
【6等分】
[array([[1, 2, 3, 4]]),
 array([[5, 6, 7, 8]]),
 array([[ 9, 10, 11, 12]]),
 array([[13, 14, 15, 16]]),
 array([[17, 18, 19, 20]]),
 array([], shape=(0, 4), dtype=int64)]
------------------------------



n分割後の形状確認

Numpy配列の形状を確認するときは配列.shapeでできます。
分割後の各配列が同一形状とは限らないので、各配列ごとに形状を取得する必要があります。

分割全体をそのまま形状確認するとエラーになる例。

# 1次元配列生成
a11 = np.arange(1,12)
print(a11)

# 要素数11を3等分
np.array_split(a11, 3)

# 配列の形状確認
np.array_split(a11, 3).shape
[ 1  2  3  4  5  6  7  8  9 10 11]



---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

/data/data/com.termux/files/usr/tmp/ipykernel_8750/3673819837.py in <module>
      7 
      8 # 配列の形状確認
----> 9 np.array_split(a11, 3).shape


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

「リストオブジェクトはshapeの属性がない」と怒られました。

分割したらリストに各配列を格納しているようです。上でやったように変数で各配列を取り出した際も、リストを変数で分けて取り出したわけね。

分割後の各配列の形状を確認します。ついでに型も確認します。

# 1次元配列生成
a11 = np.arange(1,12)
print('元の配列')
print(a11)
print(type(a11))
print('-'*20)

# 要素数11を3等分
print('3等分後')
pprint(np.array_split(a11, 3))
print('-'*20)

# 配列の形状確認
all_a = np.array_split(a11, 3)
print('分割後の各配列の形状と型')
for i  in all_a:
    print(i.shape)
    print(type(i)) # 型確認
    print('-'*20)
元の配列
[ 1  2  3  4  5  6  7  8  9 10 11]
<class 'numpy.ndarray'>
--------------------
3等分後
[array([1, 2, 3, 4]), array([5, 6, 7, 8]), array([ 9, 10, 11])]
--------------------
分割後の各配列の形状と型
(4,)
<class 'numpy.ndarray'>
--------------------
(4,)
<class 'numpy.ndarray'>
--------------------
(3,)
<class 'numpy.ndarray'>
--------------------



3次元配列で上記と同じようにn分割させようとしたらエラーが出ました。画像の配列が3次元ですけど、構造とかがぶっちゃけ捉えにくい。よくわからないので一旦放置します。

以上です。