이번 포스팅에서는 넘파이 배열을 다루면서 중요한 개념인 인덱싱과 슬라이싱에 대해 알아보도록 하겠습니다.
import numpy as np
1. 1차원 배열
✅ 인덱싱
넘파이 배열의 인덱싱은 파이썬 리스트의 인덱싱 방식과 대체로 동일합니다.
반복문을 사용해서 넘파이 배열 내 각 원소에 접근 또한 가능합니다.
arr = np.arange(10)
print(arr)
# [0 1 2 3 4 5 6 7 8 9]
print(arr[0]) # 0
print(arr[2]) # 2
print(arr[-1]) # 9
하지만 차이점 또한 존재합니다.
복수의 값을 인덱싱하기 위해서 넘파이 배열에는 배열을 인자로 전달할 수 있습니다.
인자로 전달하는 배열은 넘파이 배열 내 타겟값들의 인덱스로 구성됩니다.
arr = np.arange(10)
print(arr)
# [0 1 2 3 4 5 6 7 8 9]
print(arr[[0, 2, 5, -1]])
# [0 2 5 9]
✅ 슬라이싱
파이썬 리스트처럼 넘파이 배열도 슬라이싱이 가능합니다.
슬라이싱으로 가져오는 값의 범위는 [start, end) 입니다.
arr = np.arange(10)
print(arr)
# [0 1 2 3 4 5 6 7 8 9]
print(arr[0:3]) # [0 1 2]
print(arr[4:]) # [4 5 6 7 8 9]
print(arr[:3]) # [0 1 2]
print(arr[-2:]) # [8 9]
print(arr[:-3]) # [0 1 2 3 4 5 6]
print(arr[:]) # [0 1 2 3 4 5 6 7 8 9]
print(arr[::2]) # [0 2 4 6 8]
print(arr[::-2]) # [9 7 5 3 1]
슬라이싱을 통해 넘파이 배열의 원소값을 수정할 수 있습니다.
arr = np.arange(1, 11)
print(arr)
# [ 1 2 3 4 5 6 7 8 9 10]
arr[:5] = 0
print(arr)
# [ 0 0 0 0 0 6 7 8 9 10]
2. 2차원 배열
💡 arr[x, y]
- x: 행 인덱싱
- y: 열 인덱싱
2차원 넘파이 배열은 콤마(,)를 사용해 행 또는 열에 대한 인덱싱을 수행할 수 있습니다.
행과 열에 대한 인덱싱은 연속적으로 이루어지지 않고 독립적으로 이루어집니다.
아래 예제코드를 살펴보겠습니다.
인덱싱 인자가 하나인 경우에는 행에 대한 인덱싱을 수행합니다.
arr = np.arange(12).reshape((3, 4))
print(arr.shape)
# (3, 4)
print(arr)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
print(arr[0]) # [0 1 2 3]
print(arr[1]) # [4 5 6 7]
print(arr[2]) # [8 9 10 11]
인덱싱 인자를 2개 전달하는 경우에는 각각 행과 열에 대한 인덱싱을 수행합니다.
arr = np.arange(9).reshape((3, 3))
print(arr)
# [[0 1 2]
# [3 4 5]
# [6 7 8]]
print(arr[0, 0], arr[0, 1], arr[0, 2]) # 0 1 2
print(arr[1, 0], arr[1, 1], arr[1, 2]) # 3 4 5
print(arr[2, 0], arr[2, 1], arr[2, 2]) # 6 7 8
인덱싱 인자를 전달할 때 슬라이싱도 사용이 가능합니다.
행과 열에 대해 각각 인덱싱 또는 슬라이싱을 수행한 결과에서 교집합인 부분을 가져옵니다.
arr = np.arange(12).reshape((3, 4))
print(arr)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
print(arr[0, 1:]) # [1 2 3]
arr2 = np.arange(12).reshape((4, 3))
print(arr2)
# [[ 0 1 2]
# [ 3 4 5]
# [ 6 7 8]
# [ 9 10 11]]
print(arr2[1:, 0]) # [3 6 9]
print(arr2[:3, 1]) # [1 4 7]
print(arr2[1:3, 2]) # [5 8]
예시코드를 한 번 더 살펴보겠습니다.
arr = np.arange(16).reshape((4, 4))
print(arr)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]
# [12 13 14 15]]
print(arr[1:3, 1:3])
# [[ 5 6]
# [ 9 10]]
print(arr[:2, :3])
# [[0 1 2]
# [4 5 6]]
print(arr[1:, 2:])
# [[ 6 7]
# [10 11]
# [14 15]]
print(arr[2:, :-2])
# [[ 8 9]
# [12 13]]
인덱싱과 슬라이싱을 응용하면 이미지를 뒤집거나 회전시킬 수 있습니다.
image = np.arange(9).reshape((3, 3))
print(image)
# [[0 1 2]
# [3 4 5]
# [6 7 8]]
# 좌우로 이미지 뒤집기
horizontal_flip = image[:, ::-1]
print(horizontal_flip)
# [[2 1 0]
# [5 4 3]
# [8 7 6]]
# 상하로 이미지 뒤집기
vertical_flip = image[::-1, :]
print(vertical_flip)
# [[6 7 8]
# [3 4 5]
# [0 1 2]]
# 이미지 180도 회전
rotation_180 = image[::-1, ::-1]
print(rotation_180)
# [[8 7 6]
# [5 4 3]
# [2 1 0]]
3. 3차원 배열
💡 arr[x, y, z]
- x: 채널 인덱싱
- y: 행 인덱싱
- z: 열 인덱싱
3차원 넘파이 배열의 인덱싱은 '채널 → 행 → 열' 순으로 이루어집니다.
인덱싱 인자를 2개 전달하는 경우에는 채널과 행에 대해서만 인덱싱을 수행합니다.
arr = np.arange(27).reshape((3, 3, 3))
print(arr)
# [[[ 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]]]
print(arr[0, 0])
# [0 1 2]
print(arr[2, 1])
# [21 22 23]
print(arr[0, 1, 2])
# 5
첫 번째 예제코드입니다.
'채널 → 행 → 열'의 순서로 인덱싱이 수행되는 것을 참고하세요.
arr = np.arange(27).reshape((3, 3, 3))
print(arr)
# [[[ 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]]]
print(arr[0, :2, :2])
# [[0 1]
# [3 4]]
print(arr[1, :2, :])
# [[ 9 10 11]
# [12 13 14]]
print(arr[2, 1:, 1:])
# [[22 23]
# [25 26]]
print(arr[:, :2, :]) # shape=(3, 2, 3)
# [[[ 0 1 2]
# [ 3 4 5]]
# [[ 9 10 11]
# [12 13 14]]
# [[18 19 20]
# [21 22 23]]]
print(arr[:, :, 0]) # shape=(3, 3)
# [[ 0 3 6]
# [ 9 12 15]
# [18 21 24]]
print(arr[1:, 1:, 1:]) # shape=(2, 2, 2)
# [[[13 14]
# [16 17]]
# [[22 23]
# [25 26]]]
두 번째 예제코드 입니다.
... 기호를 사용하면 나머지 차원을 의미합니다.
imageSet = np.random.normal(size=(32, 100, 200))
# 아래 세 줄의 코드는 같은 의미입니다.
image0 = imageSet[0]
image0 = imageSet[0, :, :]
image0 = imageSet[0, ...]
print(image0.shape) # (100, 200)
# 아래 두 줄의 코드는 같은 의미입니다.
col0 = imageSet[:, :, 0]
col0 = imageSet[..., 0]
print(col0.shape) # (32, 100)
# 아래 두 줄의 코드는 같은 의미입니다.
image0_col0 = imageSet[0, :, 0]
image0_col0 = imageSet[0, ..., 0]
print(image0_col0.shape) # (100, )
마지막으로 컬러 이미지를 다루는 예제를 살펴보겠습니다.
컬러이미지는 RGB 채널로 이루어지기 때문에 넘파이 3차원 배열로 표현이 가능합니다.
이때 슬라이싱을 사용해서 이미지의 일부분을 가져올 수 있습니다.
image = np.random.normal(size=(3, 500, 300))
# image_r = image[0], image_g = image[1], image_b = image[2]
image_r, image_g, image_b = image
print(image_r.shape, image_g.shape, image_b.shape)
# (500, 300) (500, 300) (500, 300)
# 이미지 좌측상단 일부분 가져오기
top_left = image[:, :100, :100]
# 이미지 우측상단 일부분 가져오기
top_right = image[:, :100, -100:]
# 이미지 좌측하단 일부분 가져오기
bottom_left = image[:, -100:, :100]
# 이미지 우측하단 일부분 가져오기
bottom_right = image[:, -100:, -100:]
print(top_left.shape, top_right.shape)
# (3, 100, 100) (3, 100, 100)
print(bottom_left.shape, bottom_right.shape)
# (3, 100, 100) (3, 100, 100)
마치며
이상으로 넘파이 배열의 인덱싱과 슬라이싱에 대한 정리를 마치도록 하겠습니다.
인덱싱과 슬라이싱의 결과로 반환되는 배열의 차원에 유의해야겠습니다.
다음 포스팅에서는 정수/불리언 배열을 활용해서 넘파이 배열을 인덱싱, 슬라이싱 하는 방법에 대해 알아보도록 하겠습니다.
넘파이 배열의 인덱싱과 슬라이싱 이해하기(2)
지난 포스팅에 이어 이번에는 정수/불리언 배열을 활용한 인덱싱과 슬라이싱에 대해 알아보도록 하겠습니다. import numpy as np 1. 정수 인덱싱 배열 💡 인덱싱을 위해 사용하는 정수 인덱싱 배열의
dataphile.tistory.com
'머신러닝・딥러닝 > numpy' 카테고리의 다른 글
넘파이 배열의 인덱싱과 슬라이싱 이해하기(2) (0) | 2023.07.17 |
---|