NumPy 인덱싱 & 슬라이싱: 텐서를 자유자재로 자르는 법
1. 왜 인덱싱/슬라이싱이 이렇게 중요할까?
딥러닝을 하다 보면 텐서를 이렇게 자주 다루게 됩니다.
- 배치에서 앞 몇 개 샘플만 뽑기
- 이미지에서 특정 채널(R/G/B) 만 골라 쓰기
- 시퀀스 데이터에서 일부 타임스텝만 자르기
- 라벨에서 특정 클래스만 골라내기
이 모든 작업이 결국 “인덱싱(indexing) & 슬라이싱(slicing)” 입니다.
그리고 PyTorch의 Tensor 인덱싱/슬라이싱 문법은 NumPy와 거의 동일하기 때문에,
NumPy에서 확실히 익혀두면 딥러닝 코드 작성이 훨씬 편해집니다.
2. 기본 인덱싱: 1차원부터 감잡기
2.1 1차원 배열 인덱싱
import numpy as np
x = np.array([10, 20, 30, 40, 50])
print(x[0]) # 10
print(x[1]) # 20
print(x[4]) # 50
- 인덱스는 0부터 시작
x[i]는 i번째 원소
2.2 음수 인덱싱
뒤에서부터 세고 싶을 때는 음수 인덱스를 사용합니다.
print(x[-1]) # 50 (맨 끝)
print(x[-2]) # 40
PyTorch에서도 똑같이 동작합니다.
3. 슬라이싱 기본: start:stop:step
슬라이싱은 x[start:stop:step] 형태로 사용합니다.
x = np.array([10, 20, 30, 40, 50])
print(x[1:4]) # [20 30 40], 1 이상 4 미만
print(x[:3]) # [10 20 30], 처음부터 3 미만
print(x[2:]) # [30 40 50], 2부터 끝까지
print(x[:]) # 전체 복사 느낌
step을 넣으면 간격을 둘 수 있습니다.
print(x[0:5:2]) # [10 30 50], 0~4까지 2칸씩
print(x[::2]) # [10 30 50], 위와 동일
딥러닝에서 예를 들면, 타임스텝을 2개씩 건너뛰거나, 특정 간격으로 샘플을 선택할 때 유용합니다.
4. 2차원 이상 배열 인덱싱: 행과 열 다루기
2차원 배열부터가 사실상 “행렬/배치”이기 때문에 딥러닝 느낌이 나기 시작합니다.
import numpy as np
X = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]) # shape: (3, 3)
4.1 행/열 단일 인덱싱
print(X[0]) # 첫 번째 행: [1 2 3]
print(X[1]) # 두 번째 행: [4 5 6]
print(X[0, 0]) # 1행 1열: 1
print(X[1, 2]) # 2행 3열: 6
X[i]→ i번째 행 (1D 배열)X[i, j]→ i번째 행, j번째 열의 값 (스칼라)
4.2 행 슬라이싱
print(X[0:2]) # 0~1행
# [[1 2 3]
# [4 5 6]]
print(X[1:]) # 1행부터 끝까지
# [[4 5 6]
# [7 8 9]]
이건 보통 배치에서 앞/뒤 일부 샘플만 자를 때 PyTorch에서 그대로 쓰는 패턴입니다.
4.3 열 슬라이싱
print(X[:, 0]) # 모든 행, 0번째 열 → [1 4 7]
print(X[:, 1]) # 모든 행, 1번째 열 → [2 5 8]
:는 “해당 차원 전체”를 의미X[:, 0]는 “행은 전부, 열은 0번째”라는 뜻
딥러닝에서:
(batch_size, feature_dim)배열에서 특정 feature만 뽑고 싶을 때:X[:, k]
5. 3차원 이상: 배치 × 채널 × 높이 × 너비
이미지 데이터를 예로 들어 보겠습니다.
# (batch, height, width) 라고 가정
images = np.random.randn(32, 28, 28) # 32개, 28x28 이미지
5.1 특정 샘플 하나만 뽑기
img0 = images[0] # 첫 번째 이미지, shape: (28, 28)
img_last = images[-1] # 마지막 이미지
5.2 배치 일부만 사용하기
first_8 = images[:8] # 앞에서 8개만, shape: (8, 28, 28)
5.3 이미지의 일부 영역만 자르기 (crop)
# 가운데 20x20 영역만
crop = images[:, 4:24, 4:24] # shape: (32, 20, 20)
PyTorch에서도:
# images_torch: (32, 1, 28, 28) 같은 텐서라고 가정
center_crop = images_torch[:, :, 4:24, 4:24]
처럼 인덱싱/슬라이싱 개념이 거의 그대로 입니다.
6. 슬라이싱은 보통 “뷰(view)”이다
중요한 포인트 하나:
슬라이싱 결과는 보통 원본 배열의 “뷰(view)” 입니다. 즉, 새로 데이터를 복사한 게 아니라 원본을 바라보는 창이라는 뜻입니다.
x = np.array([10, 20, 30, 40, 50])
y = x[1:4] # view
print(y) # [20 30 40]
y[0] = 999
print(y) # [999 30 40]
print(x) # [ 10 999 30 40 50] ← 원본도 바뀜!
이 특징은:
- 메모리를 아끼고 빠르다는 장점이 있지만
- 실수로 원본을 바꿀 수도 있다는 단점이 있습니다.
완전히 별도의 배열로 만들고 싶다면 copy()를 사용합니다.
x = np.array([10, 20, 30, 40, 50])
y = x[1:4].copy()
y[0] = 999
print(x) # [10 20 30 40 50], 원본 유지
PyTorch에서도 비슷한 개념이 있으니, “뷰 vs 복사” 감각을 잡아두면 디버깅이 훨씬 쉬워집니다.
7. 불리언 인덱싱: 조건으로 원소 뽑기
불리언 인덱싱은 “조건을 만족하는 원소만 선택”할 때 사용합니다.
import numpy as np
x = np.array([1, -2, 3, 0, -5, 6])
mask = x > 0
print(mask) # [ True False True False False True]
pos = x[mask]
print(pos) # [1 3 6]
x > 0→True/False로 이루어진 배열x[mask]→True인 위치만 뽑기
조합 예시:
X = np.array([[1, 2, 3],
[4, 5, 6],
[-1, -2, -3]])
pos = X[X > 0]
print(pos) # [1 2 3 4 5 6]
딥러닝에서 자주 활용되는 패턴:
- 특정 조건을 만족하는 샘플만 추출 (예: 라벨이 특정 값인 것만)
- 손실(loss) 계산 시, 마스크를 씌워서 일부 값만 평균 내기 등
PyTorch에서도:
import torch
x = torch.tensor([1, -2, 3, 0, -5, 6])
mask = x > 0
pos = x[mask]
처럼 거의 동일하게 사용됩니다.
8. 정수 배열 / 리스트 인덱싱 (Fancy Indexing)
정수 인덱스들의 배열/리스트로 원하는 위치를 한 번에 뽑을 수도 있습니다.
x = np.array([10, 20, 30, 40, 50])
idx = [0, 2, 4]
print(x[idx]) # [10 30 50]
2차원에서도 가능합니다.
X = np.array([[1, 2],
[3, 4],
[5, 6]]) # shape: (3, 2)
rows = [0, 2]
print(X[rows])
# [[1 2]
# [5 6]]
딥러닝에서 예를 들면:
- 랜덤하게 섞인 인덱스 배열로 배치 샘플 뽑기
- 특정 위치의 라벨/예측만 모아서 통계 내기
PyTorch도 같은 스타일로 사용할 수 있습니다.
9. 자주 쓰는 인덱싱 패턴 정리
딥러닝 관점에서 자주 등장하는 패턴을 모아보면:
import numpy as np
# (batch, feature)
X = np.random.randn(32, 10)
# 1) 앞 8개 샘플만
X_head = X[:8] # (8, 10)
# 2) 특정 feature (예: 3번 컬럼)만
f3 = X[:, 3] # (32,)
# 3) 짝수 인덱스 샘플만
X_even = X[::2] # (16, 10)
# 4) 라벨이 1인 샘플만 선택
labels = np.random.randint(0, 3, size=(32,))
mask = labels == 1
X_cls1 = X[mask] # 라벨 1에 해당하는 샘플만
# 5) 랜덤 셔플 후 앞 24개를 train, 뒤 8개를 val
indices = np.random.permutation(len(X))
train_idx = indices[:24]
val_idx = indices[24:]
X_train = X[train_idx]
X_val = X[val_idx]
위 패턴들은 PyTorch 텐서에서도 거의 그대로 사용됩니다. 결국 NumPy 인덱싱에 익숙해지는 것 = 텐서 데이터를 자유롭게 “쪼개고, 섞고, 골라내는 능력”을 기르는 것입니다.
10. 마무리
이번 글에서 본 것들을 정리하면:
- 인덱싱:
x[i],x[i, j], 음수 인덱스 - 슬라이싱:
start:stop:step,:, 다차원 인덱싱 (X[:, 0],X[:8],X[:, 4:8]) - 슬라이싱은 보통 뷰(view) 이므로 원본이 바뀔 수 있음 → 필요하면
copy() - 불리언 인덱싱: 조건으로 필터링 (
x[x > 0],X[labels == 1]) - 정수 배열 인덱싱: 원하는 인덱스 모음으로 한 번에 선택 (
x[[0,2,4]])
이 정도를 손에 익히면, PyTorch 텐서를 가지고 “배치 자르기 / 채널 선택 / 마스크 적용 / 샘플 섞기” 같은 작업을 훨씬 수월하게 할 수 있습니다.

댓글이 없습니다.