본문 바로가기

컴퓨터공학/python

[Numpy] Indexing and Slicing

이번 글에서는 ndarray의 Indexing 에 대해서 알아보도록 하겠습니다.

 


reference

https://numpy.org/doc/stable/reference/arrays.indexing.html

 

Indexing — NumPy v1.21 Manual

When there is at least one slice (:), ellipsis (...) or newaxis in the index (or the array has more dimensions than there are advanced indexes), then the behaviour can be more complicated. It is like concatenating the indexing result for each advanced inde

numpy.org


 

Index


1. What is indexing?

1.1  Slicing

1.2 Advanced indexing

1.3 3rd Order Tensor Slicing

 


1.1 What is Indexing?

Array indexing 이란 the square brackets ([])을 이용하여 선택한 요소값을 찾아내는 방법을 의미합니다.

python은 obj를 선택값으로 하는 array x를 인덱싱을 할 수 있도록 " x[obj] " syntax를 이용하여 field acess을 제공합니다.

간단한 예를 들어 설명하면 이해가 편리할것 같습니다.

import numpy as np

a = np.arange(10) 
>>>print(f"ndarray: \n{a}\n"}

ndarray:
[0 1 2 3 4 5 6 7 8 9]

>>>print("a[0] : ", a[0])
a[0] : 0

>>>print("a[2] : ", a[2])
a[2] : 2

위의 예제는 square brackets 속 인덱스를 이용해 결괏값으로 반환해주고 있습니다. 

 

여기서 잠깐 부가적으로 알아두면 좋은팁 np.arange(10)의 end값이 9가 나오는 이유에 대해 짚고 넘어가도록 하겠습니다.

 

일반적으로 a<=  x <= b 의 원소의 개수는 b-a+1 으로 b-0+1 = 10 이 되기 위해서 b는 9가 되어야 합니다.

즉, 원소의 개수(n)를 맞춰주기 위해 9(n-1)가 나오는것 입니다. 

 

1.2 Slicing

Slicing은 indexing을 활용하여 특정 Portion의 view를 기본적으로 반환합니다.

array a 를 이용하여 slicing에 대해 간단히 설명하자면,

 a[start: end]는 a[start] 부터 a[end-1]까지를 slcing한 결괏값을 반환 해 줍니다.

"꼭 end-1에 주의해야 합니다"

간단한 예시를 들어 설명하도록 하겠습니다.

a= np.arange(10)

>>>print("a[0:3]) :", a[0:3])
a[0:3] : [0,1,2]

>>>print("a[5:-1] :", a[5:-1]) 
a[5:-1] : [5,6,7,8]

>>>print("a[2:] : ", a[2:])
a[2:] : [2 3 4 5 6 7 8 9]

>>>print("a[-2:] : ". a[-2:])
a[-2:] : [8 9]

>>>print("a[:2] :", a[:2])
a[:2] : [0 1]

>>>print("a[:-2] :", a[:-2])
a[:-2] : [0 1 2 3 4 5 6 7]

[n:m] : 인덱스 n부터 m-1 까지의 원소

 

[:-n] : end부터 start방향으로 n개 제외한 모든 원소

[start:] :  start부터 끝까지의 모든 원소

[:end] : index[end-1] 까지의 모든 원소

 

 

그렇다면 일정 간격을 두고 indexing을 하려면 어떻게 해야 할까요?

바로  [start : end : step] 을 이용하면 됩니다.

여기서 step은 간격을 의미합니다.

부가적으로 Ellipsis(생략) and newaxis(새로운축 추가(차원 추가)) objects 또한 어디든 사용 가능합니다.

(링크를 걸어두었으니 참고하십시오)

아래는 이에 관한 간단한 예시들입니다.

Basic
a = np.arange(10)

1.
>>>print("a[2:7:2] :", a[2:7:2])
a[2:7:2] : [2 4 6]

2.
>>>print("a[::3] :", a[::3]) 
a[::3] : [0 3 6 9]

Options
3.
>>>print("a[7:2:-1] : ", a[7:2:-1])
a[7:2:-1] :  [7 6 5 4 3]

4.
>>>print("a[::-1] :", a[::-1])
a[::-1] : [9 8 7 6 5 4 3 2 1 0]

5.
>>>print("a[::-3] :", a[::-3])
a[::-3] : [9 6 3 0]

 

[::-1] : 원소의 순서 reverse

[::-3] : 전체 reverse후 3의 간격으로 

 

 

마지막으로 square brackets 속에 튜플을 넣어주면 그것은 인덱스 list로 해석됩니다.

그리고 boolean값을 이용할 수도 있습니다. 즉, 조건을 삽입할 수도 있다는 말이죠.

이 또한 간단한 예시를 들어 보도록 하겠습니다.

import numpy as np
a= np.arange(10) 
indices = np.array([0,3,6,-1])

>>>print(a[indices])
[0 3 6 9]

>>>print(a[a%3==0])
[0 3 6 9]

 

 

 

 

1.2 Advanced Indexing 

 

이번에는 Matrix 에서 Slicing을 한번 해볼까요?

차원만 늘어났을뿐 Slicing하는 개념은 동일합니다.

a[x,y] 에서 x와 y는 각각 행과 열에 대해 기존 규칙에 따라 slicing을 수행합니다.

예시를 들어보도록 하겠습니다.

improt numpy as np

a =np.arange(12).reshape(4,3)
>>>print(f"ndarray: \n{a}\n")
ndarray: 
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]

>>>print("a[1:,0] : ", a[1:,0])
a[1:,0] :  [3 6 9]

>>>print("a[:3,1] : ", a[:3,1])
a[:3,1] :  [1 4 7]

>>>print("a[1:3,2] : ", a[1:3,2])
a[1:3,2] :  [5 8]

matrix에서도 역연산이 가능하며 이를 이용하여 1. 좌우대칭 2. 상하대칭 3.회전을 할 수 있습니다.

아래 예시를 들어 설명하도록 하겠습니다. (3.회전은 시계방향 180도 회전입니다.)

import numpy as np
image=np.arange(9).reshape((3,3))

1.horizontal filip
horizontal_flip = image[:,::-1]
print(horizontal_flip)
[[2 1 0]
 [5 4 3]
 [8 7 6]]

2.vertical flip
vertical_flip = image[::-1,:]
print(vertical_flip)
[[6 7 8]
 [3 4 5]
 [0 1 2]]


3.rotation
rotation = image[::-1,::-1]
print(rotation)
[[8 7 6]
 [5 4 3]
 [2 1 0]]

 

1.3 3rd Order Tensor Slicing