4.10.14 유연한 쪼개기: array_split()과 dsplit()
이번 장에서는 배열 분할 파트의 마지막 두 가지 유용한 강력한 함수를 소개합니다. 하나는 에러 없는 유연함의 끝판왕인 array_split()이고, 다른 하나는 3차원에 특화된 전용 분할기 dsplit()입니다.
① np.array_split() : 에러 나지 않는 착한 분할
[비유로 이해하기: 유연한 사탕 나누기]
앞서 배운 기본 함수 np.split은 9개의 데이터를 4개로 쪼개라고 하면 얄짤없이 에러(ValueError)를 뿜어냅니다. 공평하게 똑같이 나눌 수 없기 때문이죠. 하지만 초능력을 가진 np.array_split()은 에러 없이 최대한 비슷하게 눈치껏 잘라서 나눠줍니다.
예를 들어 사탕 9개를 4명에게 나누라고 하면 에러를 내지 않고, 대신 앞사람부터 하나씩 덤을 얹어주어 3개, 2개, 2개, 2개로 공평하게(?) 배분합니다.
실전 데이터 분석에서는 데이터의 개수가 언제나 우리가 원하는 만큼 딱 떨어지지 않으므로, 에러 방지를 위해 실무에서 가장 유용하고 안전한 분할법으로 손꼽힙니다.
import numpy as np
# 원소가 9개인 배열
x = np.arange(9.0)
# 9개를 4명에게 통상적인 split 함수로 나눈다면: 에러 발생!
# np.split(x, 4) -> ValueError
# array_split 함수를 쓰면 알아서 눈치껏 분할!
s = np.array_split(x, 4)
print("결과:", s)
[실행 결과]
결과: [array([0., 1., 2.]), array([3., 4.]), array([5., 6.]), array([7., 8.])]
에러가 나지 않을 뿐만 아니라, 첫 번째 조각만 3개고 나머지는 2개씩 알뜰하게 나뉘어 리스트에 담긴 것을 확인할 수 있습니다!
이러한 유연함은 다차원(2차원 이상) 배열에서도 똑같이 작용하며, axis=0이나 axis=1을 지정해주면 자투리 행 열을 지혜롭게 쪼개어 반환해 줍니다.
# 7행 5열의 2차원 공간
a = np.arange(35).reshape(7, 5)
# 행(axis=0) 기준으로 강제로 4등분 하기 (7행을 4명이 나누기)
# 똑같이 나눌 수 없으므로, 앞사람부터 2행, 2행, 2행, 맨마지막은 1행으로 가져갑니다.
result = np.array_split(a, 4, axis=0)
print("첫 번째 사람이 가져간 배열 모양:", result[0].shape) # (2, 5) 형태로 2줄을 가져감
print("마지막 사람이 가져간 배열 모양:", result[-1].shape) # (1, 5) 형태로 1줄만 가져감
② np.dsplit() : 3차원 깊이(Depth) 방면으로 쪼개기
[비유로 이해하기: 3차원 식빵 덩어리 단면으로 갈라 썰기]
2차원 평면에는 축이 두 개(가로, 세로)뿐이라서 hsplit(가로 자르기)과 vsplit(세로 자르기) 두 친구뿐이었다면, 3차원부터는 새로운 축인 깊이(Z축, Depth, axis=2)가 하나 더 생겨납니다.
이 깊이 축을 자르기 위해 태어난 3차원 전용 톱이 바로 np.dsplit() 입니다. 앞뒤로 두껍게 쌓인 3차원 큐브나 큰 식빵 한 덩이를 단면 방향에서 세로로 자른다고 생각하시면 완벽하게 일치합니다.
np.dsplit(x)는 이전에 배운 원조 함수 np.split(x, axis=2)와 사실 하는 역할이 100% 동일합니다!
# (2개 덩어리, 2행, 6열 깊이)의 입체적인 3차원 배열
x = np.arange(24).reshape(2, 2, 6)
# 앞뒤 깊이(Depth, axis=2) 방향 한가운데를 내리쳐 2등분 합니다.
# (6열 깊이가 각각 3열, 3열로 쪼개짐)
d_result = np.dsplit(x, 2)
print("원본 3차원 배열 x의 모양:", x.shape) # (2, 2, 6)
print("dsplit 후 첫 번째 앞쪽 조각 모양:", d_result[0].shape) # (2, 2, 3)로 분리됨!
[실무 꿀팁]
dsplit역시 일반 함수이기 때문에 깊이가 딱 나누어떨어지지 않으면 에러가 납니다. 그래서 실무에서 깊이 방향으로 자투리가 생기는 불균등 분할을 에러 없이 강행하고 싶다면,np.array_split(x, 등분개수, axis=2)처럼 만능 쪼개기 도구인array_split으로 축 번호를 직접 제어해 주는 방식이 훨씬 똑똑하고 안전합니다.