NumPy의 꽃 Indexing과 Slicing이다. 다차원 배열에서 사용자가 원하는 요소만 정확히 골라내기 위해선 Indexing과 Slicing에 대한 이해가 필요하다. NumPy 배열를 다룰 때는 기본적으로 Python 시퀀스처럼 다루면 되므로 크게 어렵지 않다. 이번 글에서는 기본 인덱싱을 알아보자.
기본 인덱싱(Basic indexing)
단일 요소 인덱싱(Single element indexing)
단일 요소를 인덱싱할 때는 Python 인덱싱과 정확히 똑같이 동작한다.
import numpy as np
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
# 1
print(x[4], x[-2])
# 2
print(x.shape)
x.shape = (3, 3)
print(x.shape)
print(x)
print(x[1, 1])
# 3
print(x[1][1])
# 4
print(x[1])
# 1
5 8
# 2
(9,)
(3, 3)
[[1 2 3]
[4 5 6]
[7 8 9]]
5
# 3
5
# 4
[4 5 6]
# 1
4번 인덱스와 음수인 -2번 인덱스를 선택해 5, 8을 출력했다
# 2
(9, )이었던 1차원 배열을 (3, 3)인 2차원 배열로 확장시켰다.
x[1, 1]을 출력하면 5가 출력됐다.
# 3
x[1, 1]대신 x[1][1]로 출력해도 결과는 같다.
# 4
x[1]을 출력하면 길이가 3인 배열이 출력된다. 리턴된 배열은 복사(deep copy)된 것이 아니라 원본 배열의 메모리 주소를 가리키는 view라는 임시 배열을 생성해 출력한 것이다. 즉, 위의 x[1, 1](# 2)와 x[1][1](# 3)을 비교했을 때 x[1][1]는 먼저 x[1]의 임시배열(view)을 하나 만든 뒤 최종적으로 임시 배열을 생성하므로 x[1, 1]보다 비효율적이다.
슬라이싱과 스트라이딩(Slicing and Striding)
스트라이딩은 걸음이라는 뜻으로 step과 유사하게 생각하면 된다. NumPy의 기본 슬라이싱 역시 Python의 슬라이싱 개념을 N차원으로 확장한 것이다. Python과 똑같이 index는 0부터 시작하고 음수인 경우는 배열의 끝에서부터 센다
❗ NumPy 슬라이싱은 Python의 다른 시퀀스 타입들처럼 대상을 복사(copy)하는 대신 view를 생성한다. view는 참조하는 대상의 메모리 주소를 가리키고 있는 임시배열이라고 생각하면 된다. 따라서 어떤 큰 메모리를 차지하는 배열에서 일부를 추출해서 사용하고자 할 때, 큰 배열이 한번만 추출된 뒤 필요없어진다면 .copy()로 복사해서 사용하는 것이 좋다. 그렇지 않으면 일부 추출된 작은 배열이 삭제될 때까지 참조된 큰 배열이 작은 배열에게 참조되기 위해서 메모리에 계속 남아있을 것이기 때문이다.
import numpy as np
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
# 1
print(x[0:8:2])
# 2
print(x[-3:9])
y = np.array([[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [
[10, 11, 12], [13, 14, 15], [16, 17, 18]]])
# 3
print(y[1, 0:2, 1])
[1 3 5 7]
[8 9]
[11 14]
# 1
Python 슬라이싱과 같이 2step으로 1부터 7까지 출력됐다
# 2
음수 인덱스의 경우에는 배열의 끝부터 세어 8부터 출력됐다
# 3
위와 같은 3차원 배열에서 첫번째 인덱스에서 [[10, 11, 12], [13, 14, 15], [16, 17, 18]]를 선택하고 두번째 인덱스에서 [10, 11, 12], [13, 14, 15]를 선택하고 마지막 인덱스에서 [11 14]를 선택했다.
차원 인덱싱 도구(Dimensional indexing tools)
다차원 배열에서 한 차원을 인덱싱(= 한 차원을 선택) 하는데 유용한 도구들이 있다.
- Ellipsis(...)
파이썬에서 pass나 생략 등으로 사용되는 Ellipsis객체를 사용해서 배열의 한 차원 전체를 선택할 수 있다.
import numpy as np
x = np.array([[[1, 2, 3], [4, 5, 6]]])
# 1
print(...)
print(Ellipsis)
print(type(Ellipsis))
# 2
print(x.shape)
print(x[..., 1].shape)
print(x[..., 1])
# 3
print(x[0, ..., ...])
# 1
Ellipsis
Ellipsis
<class 'ellipsis'>
# 2
(1, 2, 3)
(1, 2)
[[2 5]]
# 3
IndexError: an index can only have a single ellipsis ('...')
# 1
파이썬에서 ... 와 Ellipsis는 전부 ellipsis객체를 의미한다
# 2
(1, 2, 3)인 3차원 배열에서 ...으로 [[1, 2, 3], [4, 5, 6]]를 선택하고 1로 [[2, 5]]를 선택했다
# 3
인덱싱할 때 ellipsis객체는 한번만 사용할 수 있다
- np.newaxis
인덱싱을 할 때 차원을 하나 더 확장한다
import numpy as np
x = np.arange(5)
# 1
print(x)
print(x.shape)
print(x[:, np.newaxis])
print(x[:, np.newaxis].shape)
# 2
print(x[:, None])
# 1
[0 1 2 3 4]
(5,)
[[0]
[1]
[2]
[3]
[4]]
(5, 1)
# 2
[[0]
[1]
[2]
[3]
[4]]
# 1
1차원 배열을 2차원 배열로 확장했다
# 2
np.newaxis 대신 None을 써도 동일한 결과를 얻을 수 있다.
'프로그래밍 > 데이터사이언스' 카테고리의 다른 글
[ADsP] 데이터 분석 기획 Section 01. 데이터 분석 기획의 이해(1) 분석기획 방향성 도출 (0) | 2023.09.21 |
---|---|
[ADsP] 데이터의 이해 Section 03. 가치 창조를 위한 데이터 사이언스와 전략 인사이트 (0) | 2023.09.19 |
[ADsP] 데이터의 이해 Section 02. 데이터의 가치와 미래 (0) | 2023.09.18 |
[ADsP] 데이터의 이해 Section 01. 데이터의 이해 (1) | 2023.09.15 |
[Python] 데이터사이언스를 위한 NumPy - (1) 배열 생성 (0) | 2023.05.17 |