Skip to content

NumPy Concatenate: np.concatenate, vstack, hstack로 배열 결합하기

Updated on

배열 결합은 수치 컴퓨팅에서 가장 일반적인 연산 중 하나입니다. 처리를 위해 데이터를 분할한 후 다시 조립해야 합니다. 여러 소스에서 특성을 하나의 행렬로 로드합니다. 앙상블을 위해 여러 모델의 예측을 스택합니다. Python 리스트를 사용하여 루프나 +로 배열을 결합하면 성능이 저하되고 불필요한 복사가 생성됩니다.

NumPy는 C 속도로 작동하며 어떤 축을 따라 연결할지 정밀하게 제어할 수 있는 배열 결합 전용 함수를 제공합니다. 이 가이드에서는 np.concatenate(), np.vstack(), np.hstack(), np.stack()과 그 사용 사례를 다룹니다.

📚

np.concatenate() -- 핵심 함수

np.concatenate()는 기존 축을 따라 배열 시퀀스를 결합합니다.

1D 배열

import numpy as np
 
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c = np.array([7, 8, 9])
 
result = np.concatenate([a, b, c])
print(result)  # [1 2 3 4 5 6 7 8 9]
print(result.shape)  # (9,)

행 방향 2D 배열 (axis=0)

import numpy as np
 
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
 
# 수직으로 스택 (행 추가)
result = np.concatenate([a, b], axis=0)
print(result)
# [[1 2]
#  [3 4]
#  [5 6]
#  [7 8]]
print(result.shape)  # (4, 2)

열 방향 2D 배열 (axis=1)

import numpy as np
 
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
 
# 수평으로 스택 (열 추가)
result = np.concatenate([a, b], axis=1)
print(result)
# [[1 2 5 6]
#  [3 4 7 8]]
print(result.shape)  # (2, 4)

Shape 요구사항

모든 배열은 연결 축을 제외하고 동일한 형태를 가져야 합니다.

import numpy as np
 
a = np.ones((3, 4))    # 3행, 4열
b = np.zeros((2, 4))   # 2행, 4열
 
# OK: 행 수가 다르지만, 열 수가 같음, axis=0
result = np.concatenate([a, b], axis=0)
print(result.shape)  # (5, 4)
 
# 오류: 열 수가 다름
c = np.ones((3, 5))
# np.concatenate([a, c], axis=0)  # ValueError: dimensions don't match

np.vstack() -- 수직 스택

np.vstack()는 배열을 수직으로(축 0을 따라) 스택합니다. np.concatenate(arrays, axis=0)과 동일하지만 1D 배열을 단일 행으로 처리합니다.

import numpy as np
 
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
 
# vstack은 1D 배열을 행으로 처리
result = np.vstack([a, b])
print(result)
# [[1 2 3]
#  [4 5 6]]
print(result.shape)  # (2, 3)
 
# 2D 배열의 경우
c = np.array([[1, 2], [3, 4]])
d = np.array([[5, 6]])
result = np.vstack([c, d])
print(result)
# [[1 2]
#  [3 4]
#  [5 6]]

np.hstack() -- 수평 스택

np.hstack()는 배열을 수평으로 스택합니다(2D의 경우 축 1, 1D의 경우 축 0).

import numpy as np
 
# 1D 배열: np.concatenate처럼 연결
a = np.array([1, 2, 3])
b = np.array([4, 5])
result = np.hstack([a, b])
print(result)  # [1 2 3 4 5]
 
# 2D 배열: 열 추가
c = np.array([[1], [2], [3]])
d = np.array([[4], [5], [6]])
result = np.hstack([c, d])
print(result)
# [[1 4]
#  [2 5]
#  [3 6]]

np.stack() -- 새로운 축 생성

concatenate와 달리 stack새로운 축을 따라 배열을 결합하여 차원 수를 1 증가시킵니다.

import numpy as np
 
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
 
# 새로운 축 0을 따라 스택 (기본값)
result = np.stack([a, b])
print(result)
# [[1 2 3]
#  [4 5 6]]
print(result.shape)  # (2, 3)
 
# 새로운 축 1을 따라 스택
result = np.stack([a, b], axis=1)
print(result)
# [[1 4]
#  [2 5]
#  [3 6]]
print(result.shape)  # (3, 2)

np.stack()에서는 모든 입력 배열이 동일한 형태를 가져야 합니다.

함수 비교

함수새 축 생성?1D 입력 처리
np.concatenate기존 (기본값 0)아니오그대로 연결
np.vstack0 (수직)아니오1D를 행으로 처리
np.hstack1 (수평)아니오1D 배열 연결
np.stack새 축예 (+1 차원)새 차원 생성
np.column_stack1아니오1D를 열로 처리
np.row_stack0아니오vstack과 동일

실용적인 예제

머신러닝을 위한 특성 결합

import numpy as np
 
# 다양한 소스의 특성 배열
ages = np.array([25, 30, 35, 40])
incomes = np.array([50000, 60000, 75000, 90000])
scores = np.array([720, 680, 750, 800])
 
# 열로 스택하여 특성 행렬 생성
X = np.column_stack([ages, incomes, scores])
print(X)
# [[   25 50000   720]
#  [   30 60000   680]
#  [   35 75000   750]
#  [   40 90000   800]]
print(X.shape)  # (4, 3)

배치 처리 결과

import numpy as np
 
# 데이터를 배치로 처리하고 결과 결합
results = []
for batch_start in range(0, 100, 25):
    batch = np.random.randn(25, 10)  # 25개 샘플, 10개 특성
    processed = batch * 2 + 1  # 일부 처리
    results.append(processed)
 
# 모든 배치를 수직으로 결합
all_results = np.vstack(results)
print(all_results.shape)  # (100, 10)

이미지 처리 -- 채널 결합

import numpy as np
 
height, width = 100, 100
 
# 개별 색상 채널
red = np.random.randint(0, 256, (height, width))
green = np.random.randint(0, 256, (height, width))
blue = np.random.randint(0, 256, (height, width))
 
# RGB 이미지로 결합
rgb_image = np.stack([red, green, blue], axis=2)
print(rgb_image.shape)  # (100, 100, 3)

결합된 데이터 시각화

다양한 소스의 배열을 연결한 후, PyGWalker (opens in a new tab)를 사용하면 Jupyter에서 결합된 데이터셋을 인터랙티브하게 탐색할 수 있습니다:

import pandas as pd
import pygwalker as pyg
 
# 연결된 배열을 DataFrame으로 변환
df = pd.DataFrame(X, columns=['age', 'income', 'score'])
walker = pyg.walk(df)

FAQ

np.concatenate와 np.stack의 차이점은 무엇인가요?

np.concatenate는 차원 수를 변경하지 않고 기존 축을 따라 배열을 결합합니다. np.stack은 새로운 축을 따라 배열을 결합하여 차원을 하나 추가합니다. 예를 들어, 두 개의 (3,) 배열을 concatenate로 스택하면 (6,)이 되고, stack으로 하면 (2, 3)이 됩니다.

np.concatenate에서 axis는 무엇을 의미하나요?

axis 매개변수는 어떤 차원을 따라 결합할지 지정합니다. axis=0은 행을 따라 연결(더 많은 행 추가), axis=1은 열을 따라 연결(더 많은 열 추가)합니다. 2D 배열의 경우 axis=0은 수직 스택이고 axis=1은 수평 스택입니다.

vstack, hstack, concatenate는 언제 사용해야 하나요?

행을 추가하려면(수직 스택) vstack, 열을 추가하려면(수평 스택) hstack, 임의의 축을 지정해야 할 때는 concatenate를 사용하세요. vstackhstackconcatenate보다 1D 배열을 더 직관적으로 처리하는 편의 함수입니다.

배열을 연결할 때 ValueError가 발생하는 이유는 무엇인가요?

모든 배열은 연결 축을 제외하고 동일한 형태를 가져야 합니다. axis=0을 따라 연결하는 경우, 모든 배열은 동일한 열 수를 가져야 합니다. 연결 전에 array.shape로 형태를 확인하세요.

서로 다른 차원의 배열을 연결하려면 어떻게 하나요?

먼저 배열을 호환 가능한 차원으로 변환하세요. np.expand_dims(array, axis)로 차원을 추가하거나 array.reshape(new_shape)를 사용하세요. 예를 들어, 1D 배열을 2D 배열과 vstack하려면 1D 배열을 변환합니다: array.reshape(1, -1).

결론

NumPy는 배열 결합을 위한 완전한 도구 세트를 제공합니다: 어떤 축을 따라서든 범용 결합을 위한 np.concatenate(), 직관적인 수직/수평 스택을 위한 np.vstack()/np.hstack(), 새로운 차원을 생성해야 할 때의 np.stack(). concatenate는 기존 축을 따라 결합하고 stack은 새로운 축을 생성한다는 것을 기억하세요. 차원을 신중하게 맞추고, 일반적인 행/열 연산에서 가장 읽기 쉬운 코드를 위해 vstack/hstack을 사용하세요.

📚