4.6.14 분할 함수 array_split()
① np.array_split() 개요
[비유로 이해하기: 유연한 사탕 나누기]
np.split은 공평하게 똑같이 나누어 떨어지지 않으면 에러를 뿜지만, np.array_split은 에러 없이 최대한 비슷하게 눈치껏 나눠줍니다. (예: 사탕 7개를 3명에게 나누면 3개, 2개, 2개로 앞쪽부터 남은 자투리를 배분합니다.) 실전 데이터는 갯수가 딱 떨어지지 않는 경우가 흔하므로 훨씬 안전한 분할법입니다.
함수 np.array_split(ary) 인자인 ary를 여러 개의 부분 배열로 분리한다. 반환 값은 분리한 배열의 목록(list)이다. 이미 알아본 np.split()와의 차이는 두 번째 인자가 정수인 경우, 등분이 안 되더라도 오류가 발생하지 않고 분할이 가능하다.
numpy.array_split(ary, indices_or_sections, axis=0):
indices_or_sections가 축을 동일하게 나누지 않는 정수가 될 경우, 오류가 발생하지 않고 마지막 남은 배열을 부분 배열로 반환한다. l개의 섹션으로 분할되어야 하는 길이가 len인 배열의 경우, len % l 크기의 하위 배열 len // l + 1개와 나머지 크기 len // l을 반환함.
ary: 분할 대상 배열indices_or_sections: 분할할 수나 첨자 구간axis=0: 기본은 0이며, 분할하는 축
다음 9개 원소로 구성된 벡터 x가 있다.
import numpy as np
x = np.arange(9.0)
x
출력:
array([0., 1., 2., 3., 4., 5., 6., 7., 8.])
배열 x는 원소가 9개이므로 2등분은 안 된다. 그러나 다음 코드로 배열 x를 2개로 나눌 수 있다.
np.array_split(x, 2)
출력:
[array([0., 1., 2., 3., 4.]), array([5., 6., 7., 8.])]
3등분은 가능하다. 다음 코드는 배열 x를 3개로 분할한다.
np.array_split(x, 3)
출력:
[array([0., 1., 2.]), array([3., 4., 5.]), array([6., 7., 8.])]
4등분은 안 되나 다음 코드로 배열 x를 4개로 나눌 수 있다.
np.array_split(x, 4)
출력:
[array([0., 1., 2.]), array([3., 4.]), array([5., 6.]), array([7., 8.])]
또한, 5등분은 안 되나 다음 코드는 배열 x를 5개로 나눌 수 있다.
np.array_split(x, 5)
출력:
[array([0., 1.]),
array([2., 3.]),
array([4., 5.]),
array([6., 7.]),
array([8.])]
다음 코드의 첨자 목록 [2, 4, 8]로 배열 x를 4개로 분할할 수 있다.
np.array_split(x, [2, 4, 8])
출력:
[array([0., 1.]), array([2., 3.]), array([4., 5., 6., 7.]), array([8.])]
② 2차원 np.array_split() 분할
다음 모양 (7, 5)의 2차원 배열 a가 있다.
import numpy as np
a = np.arange(35).reshape(7, 5)
a
출력:
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29],
[30, 31, 32, 33, 34]])
배열 x를 수직으로 2개로 나누면 다음과 같다.
np.array_split(a, 2, axis=0)
출력:
[array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]]),
array([[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29],
[30, 31, 32, 33, 34]])]
배열 x를 수평으로 2개로 나누면 다음과 같다.
np.array_split(a, 2, axis=1)
출력:
[array([[ 0, 1, 2],
[ 5, 6, 7],
[10, 11, 12],
[15, 16, 17],
[20, 21, 22],
[25, 26, 27],
[30, 31, 32]]),
array([[ 3, 4],
[ 8, 9],
[13, 14],
[18, 19],
[23, 24],
[28, 29],
[33, 34]])]
배열 x를 수직으로 4개로 나누면 다음과 같다.
np.array_split(a, 4, axis=0)
출력:
[array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9]]),
array([[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]]),
array([[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29]]),
array([[30, 31, 32, 33, 34]])]
배열 x를 수평으로 4개로 나누면 다음과 같다.
np.array_split(a, 4, axis=1)
출력:
[array([[ 0, 1],
[ 5, 6],
[10, 11],
[15, 16],
[20, 21],
[25, 26],
[30, 31]]),
array([[ 2],
[ 7],
[12],
[17],
[22],
[27],
[32]]),
array([[ 3],
[ 8],
[13],
[18],
[23],
[28],
[33]]),
array([[ 4],
[ 9],
[14],
[19],
[24],
[29],
[34]])]
다음으로 수직으로 첨자 [2, 4]로 슬라이싱한 3개의 배열의 목록을 반환한다.
np.array_split(a, [2, 4], axis=0)
출력:
[array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9]]),
array([[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]]),
array([[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29],
[30, 31, 32, 33, 34]])]
다음으로 수평으로 첨자 [2, 4]로 슬라이싱한 3개의 배열의 목록을 반환한다.
np.array_split(a, [2, 4], axis=1)
출력:
[array([[ 0, 1],
[ 5, 6],
[10, 11],
[15, 16],
[20, 21],
[25, 26],
[30, 31]]),
array([[ 2, 3],
[ 7, 8],
[12, 13],
[17, 18],
[22, 23],
[27, 28],
[32, 33]]),
array([[ 4],
[ 9],
[14],
[19],
[24],
[29],
[34]])]
③ 3차원 이상의 axis=2로 배열 분할
np.array_split(a, axis=2):
3차원에서 axis는 0, 1, 2를 사용할 수 있다. 일반적으로 3차원에서 axis=2는 깊이(depth) 축이라고 한다. numpy에서 표시된 2차원 배열이 여러 개 쌓은 3차원 배열(다음의 왼쪽 그림)에서 보면 깊이 축인 axis=2는 다음의 검은색 가로 방향의 축이다. 3차원으로 상상하면 오른쪽 그림으로 이해하면 쉽다.
음 왼쪽 그림은 모양 (2, 2, 4)인 3차원 배열을 나타내며, 오른쪽 그림은 모양 (3, 3, 4)인 3차원 배열을 표시한다. 일반적으로 오른쪽 모양의 3차원 배열을 아래 방향으로 펼쳐서 2차원 배열 형태를 여러 개 그리면 왼쪽 그림처럼 그려진다. 4차원 이상으로 가도 같은 절차에 따라 상상하면 이해하기 쉽다.

다음 모양 (2, 2, 6)의 3차원 배열 x가 있다. 즉, 2행 6열의 배열 2개가 있는 3차원 배열이다.
import numpy as np
x = np.arange(24).reshape(2, 2, 6)
x
출력:
array([[[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11]],
[[12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23]]])
다음 코드는 깊이 축 axis=2로 배열을 4개로 나눈다.
np.array_split(x, 4, axis=2)
출력:
[array([[[ 0, 1],
[ 6, 7]],
[[12, 13],
[18, 19]]]),
array([[[ 2, 3],
[ 8, 9]],
[[14, 15],
[20, 21]]]),
array([[[ 4],
[10]],
[[16],
[22]]]),
array([[[ 5],
[11]],
[[17],
[23]]])]
배열 x의 모양이 (2, 2, 6)이므로 깊이 축의 길이는 마지막 값인 6이다. 그러므로 4등분은 되지 않는다. 다음 코드와 같이 array_split()에서 첨자 목록 [2, 4, 5]를 사용하고 axis=2로 지정하면 위 결과와 같다.
np.split(x, [2, 4, 5], axis=2)
출력:
[array([[[ 0, 1],
[ 6, 7]],
[[12, 13],
[18, 19]]]),
array([[[ 2, 3],
[ 8, 9]],
[[14, 15],
[20, 21]]]),
array([[[ 4],
[10]],
[[16],
[22]]]),
array([[[ 5],
[11]],
[[17],
[23]]])]
위에서 분할된 마지막 배열은 다음 슬라이싱 코드로도 확인할 수 있다.
x[:, :, 5:6]
출력:
array([[[ 5],
[11]],
[[17],
[23]]])
④ np.dsplit()
함수 np.dsplit(a)는 배열 a를 무조건 axis=2로만 분리하는 함수이다. 그러므로 3차원 이상의 배열에만 사용이 가능하다. 함수 np.hsplit(a)는 배열 a를 무조건 axis=1로만 분리하며 함수 np.vsplit(a)는 배열 a를 무조건 axis=0으로만 분리한다.
다음 모양 (2, 2, 6)의 3차원 배열 x가 있다.
import numpy as np
x = np.arange(24).reshape(2, 2, 6)
x
출력:
array([[[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11]],
[[12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23]]])
다음 코드로 깊이 축으로 2개를 분할한다.
np.dsplit(x, 2)
출력:
[array([[[ 0, 1, 2],
[ 6, 7, 8]],
[[12, 13, 14],
[18, 19, 20]]]),
array([[[ 3, 4, 5],
[ 9, 10, 11]],
[[15, 16, 17],
[21, 22, 23]]])]
위 예의 2분할은 등분이 되므로 위 코드는 다음 코드 np.split(x, 2, axis=2)로도 가능하다.
np.split(x, 2, axis=2)
출력:
[array([[[ 0, 1, 2],
[ 6, 7, 8]],
[[12, 13, 14],
[18, 19, 20]]]),
array([[[ 3, 4, 5],
[ 9, 10, 11]],
[[15, 16, 17],
[21, 22, 23]]])]
다음 코드로 깊이 축으로 3개로 분할한다.
np.dsplit(x, 3)
출력:
[array([[[ 0, 1],
[ 6, 7]],
[[12, 13],
[18, 19]]]),
array([[[ 2, 3],
[ 8, 9]],
[[14, 15],
[20, 21]]]),
array([[[ 4, 5],
[10, 11]],
[[16, 17],
[22, 23]]])]
배열 x의 모양이 (2, 2, 6)이므로 깊이 축의 길이는 마지막 값인 6이다. 그러므로 4등분은 되지 않으므로 오류가 발생한다.
np.dsplit(x, 4)
오류:
ValueError: array split does not result in an equal division
다음 코드와 같이 np.array_split()에서 첨자 목록 [2, 4, 5]를 사용하면 가능하다.
np.dsplit(x, [2, 4, 5])
출력:
[array([[[ 0, 1],
[ 6, 7]],
[[12, 13],
[18, 19]]]),
array([[[ 2, 3],
[ 8, 9]],
[[14, 15],
[20, 21]]]),
array([[[ 4],
[10]],
[[16],
[22]]]),
array([[[ 5],
[11]],
[[17],
[23]]])]
위에서 분할된 세 번째 배열은 다음 슬라이싱 코드로도 확인할 수 있다.
x[:, :, 4:5]
출력:
array([[[ 4],
[10]],
[[16],
[22]]])